3 * Copyright (C) 2007, Harbour, All rights reserved.
6 #include <F_Linux_Keyboard.H>
13 #include <linux/keyboard.h>
14 #include <sys/ioctl.h>
19 static int tty_fd = -1;
20 const int F_STDIN_FILENO = 0;
21 static termios old_attr;
22 static sighandler_t old_sigio;
23 F_Linux_Keyboard *F_Linux_Keyboard::this_;
25 static int map_vt100_control_kode(unsigned char kode, unsigned int mods)
73 return '-'; // ctrl+7, ctrl+-
92 static int map_vt100_5_kode(unsigned char *key_seq, unsigned int mods)
94 if ((key_seq[1] == '[') && (key_seq[4] == '~')) {
126 static int map_vt100_4_kode(unsigned char *key_seq, unsigned int mods)
128 if ((key_seq[1] == key_seq[2]) && (key_seq[1] == '[')) {
129 switch (key_seq[3]) {
144 if ((key_seq[1] == '[') && (key_seq[3] == '~')) {
145 switch (key_seq[2]) {
165 static int map_vt100_3_kode(unsigned char *key_seq, unsigned int mods)
167 if (key_seq[1] == '[') {
168 switch (key_seq[2]) {
186 // kode => keyboard code
188 // TODO: maybe load terminfo database and map against it ?
191 static bool is_printable(unsigned char c)
193 if ((c > 31) && (c != 0x7f))
198 static int map_vt100_kode(unsigned char *key_seq, unsigned int mods, int len)
201 if (len > 5) { // now we do not know anything about such long seqs
202 debug("Bad vt100 kode len - %d", len);
208 if (is_printable(key_seq[0]))
210 if ((key = map_vt100_control_kode(key_seq[0], mods)))
213 case 2: // alt + key ?
214 if (is_printable(key_seq[1]))
216 if ((key = map_vt100_control_kode(key_seq[1], mods)))
220 if ((key = map_vt100_3_kode(key_seq, mods)))
224 if ((key = map_vt100_4_kode(key_seq, mods)))
228 if ((key = map_vt100_5_kode(key_seq, mods)))
234 debug("Unknown keycode seq len %d (mods - 0x%x):", len, mods);
235 for (int i = 0; i < len; i++)
236 debug("linux_kbd: seq[%d] = 0x%x \'%c\'", i, key_seq[i],
237 (key_seq[i] > 31) ? key_seq[i] : ' ');
241 #define F_MAX_KEY_SEQ 16
243 void F_Linux_Keyboard::kbd_handler(void)
245 unsigned char key_seq[F_MAX_KEY_SEQ];
246 int res = read(tty_fd, key_seq, F_MAX_KEY_SEQ);
248 log("kbd_handler", FATAL_LEVEL, "tty_fd read error - %d", res);
251 int key, shifts_state = 6;
252 unsigned char locks_state;
253 if (ioctl(tty_fd, TIOCLINUX, &shifts_state) < 0)
254 log("kbd_handler", FATAL_LEVEL, "ioctl: %s", strerror(errno));
255 if (ioctl(tty_fd, KDGKBLED, &locks_state) < 0)
256 log("kbd_handler", FATAL_LEVEL, "ioctl: %s", strerror(errno));
260 ev.type = F_KEY_PRESS;
262 // map shifts and locks states
263 // TODO: get the ALTGR lock state here too
264 ev.kbd.modifiers = (locks_state & LED_SCR) ? F_SCROLL_LOCK : 0;
265 ev.kbd.modifiers |= (locks_state & LED_NUM) ? F_NUM_LOCK : 0;
266 ev.kbd.modifiers |= (locks_state & LED_CAP) ? F_CAPS_LOCK : 0;
267 ev.kbd.modifiers |= (shifts_state & (1 << KG_SHIFT)) ? F_SHIFT : 0;
268 ev.kbd.modifiers |= (shifts_state & (1 << KG_CTRL)) ? F_CTRL : 0;
269 ev.kbd.modifiers |= (shifts_state & (1 << KG_ALT)) ? F_ALT : 0;
270 ev.kbd.modifiers |= (shifts_state & (1 << KG_ALTGR)) ? F_META : 0;
271 // check for normal input or selection
273 for (int i = 0; i < res; i++) {
274 if (!is_printable(key_seq[i]))
278 for (int i = 0; i < res; i++) {
279 ev.kbd.key = key_seq[i];
280 this_->add_event(ev);
283 } else if (!(key = map_vt100_kode(key_seq, ev.kbd.modifiers, res)))
286 this_->add_event(ev);
289 F_Linux_Keyboard::F_Linux_Keyboard()
293 tty_fd = open(ttyname(F_STDIN_FILENO), O_RDONLY);
295 tty_fd = F_STDIN_FILENO;
296 // test if kbd is in K_XLATE mode
298 if (ioctl(tty_fd, KDGKBMODE, &arg) < 0) {
299 log("linux_keyboard", FATAL_LEVEL, "ioctl: %s", strerror(errno));
302 if (arg != K_XLATE) {
303 log("linux_keyboard", FATAL_LEVEL,
304 "Sorry, only XLATE keyboard mode is supported");
308 if (fcntl(tty_fd, F_SETFL,
309 fcntl(tty_fd, F_GETFL) | (O_NONBLOCK | O_ASYNC)) < 0) {
310 log("linux_keyboard", FATAL_LEVEL, "Can't set mode for your tty, bye.");
315 old_sigio = signal(SIGIO, (sighandler_t) F_Linux_Keyboard::kbd_handler);
316 log("linux_kbd", CHAT_LEVEL, "Found and enabled.");
321 void F_Linux_Keyboard::mode_set()
324 tcgetattr(tty_fd, &old_attr);
325 termios new_attr = old_attr;
326 new_attr.c_lflag &= ~(ICANON | ECHO);
327 new_attr.c_cc[VMIN] = 1;
328 new_attr.c_cc[VTIME] = 0;
329 new_attr.c_iflag &= ~(INPCK | ISTRIP | IXON);
330 new_attr.c_oflag |= OPOST | ONLCR;
331 tcsetattr(tty_fd, TCSANOW, &new_attr);
336 void F_Linux_Keyboard::mode_restore()
339 tcsetattr(tty_fd, TCSANOW, &old_attr);
344 F_Linux_Keyboard::~F_Linux_Keyboard()
349 signal(SIGIO, old_sigio);