2 #include <F_Linux_Keyboard.H>
9 #include <linux/keyboard.h>
10 #include <sys/ioctl.h>
15 static int tty_fd = -1;
16 const int F_STDIN_FILENO = 0;
17 static termios old_attr;
18 static sighandler_t old_sigio;
19 F_Linux_Keyboard *F_Linux_Keyboard::this_;
21 static int map_vt100_control_kode(unsigned char kode, unsigned int mods)
69 return '-'; // ctrl+7, ctrl+-
88 static int map_vt100_5_kode(unsigned char *key_seq, unsigned int mods)
90 if ((key_seq[1] == '[') && (key_seq[4] == '~')) {
122 static int map_vt100_4_kode(unsigned char *key_seq, unsigned int mods)
124 if ((key_seq[1] == key_seq[2]) && (key_seq[1] == '[')) {
125 switch (key_seq[3]) {
140 if ((key_seq[1] == '[') && (key_seq[3] == '~')) {
141 switch (key_seq[2]) {
161 static int map_vt100_3_kode(unsigned char *key_seq, unsigned int mods)
163 if (key_seq[1] == '[') {
164 switch (key_seq[2]) {
182 // kode => keyboard code
184 // TODO: maybe load terminfo database and map against it ?
187 static bool is_printable(unsigned char c)
189 if ((c > 31) && (c != 0x7f))
194 static int map_vt100_kode(unsigned char *key_seq, unsigned int mods, int len)
197 if (len > 5) { // now we do not know anything about such long seqs
198 debug("Bad vt100 kode len - %d", len);
204 if (is_printable(key_seq[0]))
206 if ((key = map_vt100_control_kode(key_seq[0], mods)))
209 case 2: // alt + key ?
210 if (is_printable(key_seq[1]))
212 if ((key = map_vt100_control_kode(key_seq[1], mods)))
216 if ((key = map_vt100_3_kode(key_seq, mods)))
220 if ((key = map_vt100_4_kode(key_seq, mods)))
224 if ((key = map_vt100_5_kode(key_seq, mods)))
230 debug("Unknown keycode seq len %d (mods - 0x%x):", len, mods);
231 for (int i = 0; i < len; i++)
232 debug("linux_kbd: seq[%d] = 0x%x \'%c\'", i, key_seq[i],
233 (key_seq[i] > 31) ? key_seq[i] : ' ');
237 #define F_MAX_KEY_SEQ 16
239 void F_Linux_Keyboard::kbd_handler(void)
241 unsigned char key_seq[F_MAX_KEY_SEQ];
242 int res = read(tty_fd, key_seq, F_MAX_KEY_SEQ);
244 log("kbd_handler", FATAL_LEVEL, "tty_fd read error - %d", res);
247 int key, shifts_state = 6;
248 unsigned char locks_state;
249 if (ioctl(tty_fd, TIOCLINUX, &shifts_state) < 0)
250 log("kbd_handler", FATAL_LEVEL, "ioctl: %s", strerror(errno));
251 if (ioctl(tty_fd, KDGKBLED, &locks_state) < 0)
252 log("kbd_handler", FATAL_LEVEL, "ioctl: %s", strerror(errno));
256 ev.type = F_KEY_PRESS;
258 // map shifts and locks states
259 // TODO: get the ALTGR lock state here too
260 ev.kbd.modifiers = (locks_state & LED_SCR) ? F_SCROLL_LOCK : 0;
261 ev.kbd.modifiers |= (locks_state & LED_NUM) ? F_NUM_LOCK : 0;
262 ev.kbd.modifiers |= (locks_state & LED_CAP) ? F_CAPS_LOCK : 0;
263 ev.kbd.modifiers |= (shifts_state & (1 << KG_SHIFT)) ? F_SHIFT : 0;
264 ev.kbd.modifiers |= (shifts_state & (1 << KG_CTRL)) ? F_CTRL : 0;
265 ev.kbd.modifiers |= (shifts_state & (1 << KG_ALT)) ? F_ALT : 0;
266 ev.kbd.modifiers |= (shifts_state & (1 << KG_ALTGR)) ? F_META : 0;
267 // check for normal input or selection
269 for (int i = 0; i < res; i++) {
270 if (!is_printable(key_seq[i]))
274 for (int i = 0; i < res; i++) {
275 ev.kbd.key = key_seq[i];
276 this_->add_event(ev);
279 } else if (!(key = map_vt100_kode(key_seq, ev.kbd.modifiers, res)))
282 this_->add_event(ev);
285 F_Linux_Keyboard::F_Linux_Keyboard()
289 tty_fd = open(ttyname(F_STDIN_FILENO), O_RDONLY);
291 tty_fd = F_STDIN_FILENO;
292 // test if kbd is in K_XLATE mode
294 if (ioctl(tty_fd, KDGKBMODE, &arg) < 0) {
295 log("linux_keyboard", FATAL_LEVEL, "ioctl: %s", strerror(errno));
298 if (arg != K_XLATE) {
299 log("linux_keyboard", FATAL_LEVEL,
300 "Sorry, only XLATE keyboard mode is supported");
304 if (fcntl(tty_fd, F_SETFL,
305 fcntl(tty_fd, F_GETFL) | (O_NONBLOCK | O_ASYNC)) < 0) {
306 log("linux_keyboard", FATAL_LEVEL, "Can't set mode for your tty, bye.");
311 old_sigio = signal(SIGIO, (sighandler_t) F_Linux_Keyboard::kbd_handler);
312 log("linux_kbd", CHAT_LEVEL, "Found and enabled.");
317 void F_Linux_Keyboard::mode_set()
320 tcgetattr(tty_fd, &old_attr);
321 termios new_attr = old_attr;
322 new_attr.c_lflag &= ~(ICANON | ECHO);
323 new_attr.c_cc[VMIN] = 1;
324 new_attr.c_cc[VTIME] = 0;
325 new_attr.c_iflag &= ~(INPCK | ISTRIP | IXON);
326 new_attr.c_oflag |= OPOST | ONLCR;
327 tcsetattr(tty_fd, TCSANOW, &new_attr);
332 void F_Linux_Keyboard::mode_restore()
335 tcsetattr(tty_fd, TCSANOW, &old_attr);
340 F_Linux_Keyboard::~F_Linux_Keyboard()
345 signal(SIGIO, old_sigio);