Prevent keystrokes from leaking through to the console when using evdev. This uses the same method Weston and X use. Sadly, to be fully effective when launching remotely, this needs root permissions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
diff --git a/README-raspberrypi.txt b/README-raspberrypi.txt
index 744fd89..0724a8c 100644
--- a/README-raspberrypi.txt
+++ b/README-raspberrypi.txt
@@ -148,5 +148,8 @@ this determining the CAPS LOCK behavior:
Notes
================================================================================
-* Input events from the keyboard leak through to the console
+* When launching apps remotely (via SSH), SDL can prevent local keystrokes from
+ leaking into the console only if it has root privileges. Launching apps locally
+ does not suffer from this issue.
+
diff --git a/src/input/evdev/SDL_evdev.c b/src/input/evdev/SDL_evdev.c
index 497cd40..92dc4fe 100644
--- a/src/input/evdev/SDL_evdev.c
+++ b/src/input/evdev/SDL_evdev.c
@@ -45,6 +45,18 @@ static _THIS = NULL;
#include <linux/keyboard.h>
#endif
+
+/* We need this to prevent keystrokes from appear in the console */
+#ifndef KDSKBMUTE
+#define KDSKBMUTE 0x4B51
+#endif
+#ifndef KDSKBMODE
+#define KDSKBMODE 0x4B45
+#endif
+#ifndef K_OFF
+#define K_OFF 0x04
+#endif
+
#include "SDL.h"
#include "SDL_assert.h"
#include "SDL_endian.h"
@@ -370,6 +382,72 @@ static int SDL_EVDEV_get_console_fd(void)
return -1;
}
+/* Prevent keystrokes from reaching the tty */
+static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
+{
+ char arg;
+
+ *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */
+ if (!IS_CONSOLE(tty)) {
+ return SDL_SetError("Tried to mute an invalid tty");
+ }
+ ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */
+ if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) {
+ return SDL_SetError("EVDEV: Failed muting keyboard");
+ }
+
+ return 0;
+}
+
+/* Restore the keyboard mode for given tty */
+static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
+{
+ if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
+ SDL_Log("EVDEV: Failed restoring keyboard mode");
+ }
+}
+
+/* Read /sys/class/tty/tty0/active and open the tty */
+static int SDL_EVDEV_get_active_tty()
+{
+ int fd, len;
+ char ttyname[NAME_MAX + 1];
+ char ttypath[PATH_MAX+1] = "/dev/";
+ char arg;
+
+ fd = open("/sys/class/tty/tty0/active", O_RDONLY);
+ if (fd < 0) {
+ return SDL_SetError("Could not determine which tty is active");
+ }
+
+ len = read(fd, ttyname, NAME_MAX);
+ close(fd);
+
+ if (len <= 0) {
+ return SDL_SetError("Could not read which tty is active");
+ }
+
+ if (ttyname[len-1] == '\n') {
+ ttyname[len-1] = '\0';
+ }
+ else {
+ ttyname[len] = '\0';
+ }
+
+ SDL_strlcat(ttypath, ttyname, PATH_MAX);
+ fd = open(ttypath, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ return SDL_SetError("Could not open tty: %s", ttypath);
+ }
+
+ if (!IS_CONSOLE(fd)) {
+ close(fd);
+ return SDL_SetError("Invalid tty obtained: %s", ttypath);
+ }
+
+ return fd;
+}
+
int
SDL_EVDEV_Init(void)
{
@@ -403,6 +481,19 @@ SDL_EVDEV_Init(void)
/* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
_this->console_fd = SDL_EVDEV_get_console_fd();
+
+ /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */
+ _this->tty = STDIN_FILENO;
+ if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
+ /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */
+ _this->tty = SDL_EVDEV_get_active_tty();
+ if (_this->tty >= 0) {
+ if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
+ close(_this->tty);
+ _this->tty = -1;
+ }
+ }
+ }
}
_this->ref_count += 1;
@@ -429,6 +520,12 @@ SDL_EVDEV_Quit(void)
if (_this->console_fd >= 0) {
close(_this->console_fd);
}
+
+ if (_this->tty >= 0) {
+ SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
+ close(_this->tty);
+ }
+
/* Remove existing devices */
while(_this->first != NULL) {
SDL_EVDEV_device_removed(_this->first->path);
diff --git a/src/input/evdev/SDL_evdev.h b/src/input/evdev/SDL_evdev.h
index 34f369d..b9311d4 100644
--- a/src/input/evdev/SDL_evdev.h
+++ b/src/input/evdev/SDL_evdev.h
@@ -43,6 +43,8 @@ typedef struct SDL_EVDEV_PrivateData
int numdevices;
int ref_count;
int console_fd;
+ int kb_mode;
+ int tty;
} SDL_EVDEV_PrivateData;
extern int SDL_EVDEV_Init(void);