/* * Copyright (C) 2004,2005,2006 Nils Faerber * Parts for Stowaway (c) 2005 by Paul Eggleton * See README for other authors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USELIRC #include #endif #include "keyboards.h" #include "dev_uinput.h" #ifndef PATH_MAX #define PATH_MAX 1024 #endif #define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) char debug = 0; int uindev = 0; static int reinit = 0; #define DEFAULT_TTS "/dev/ttyS0" char TTY_PORT[PATH_MAX] = DEFAULT_TTS; void handle_sigterm(int signal) { dev_uinput_close(uindev); exit(EXIT_SUCCESS); } int open_serial(char *port, speed_t baud) { int fd, res; struct termios ssetup; fd=open(port, O_RDWR /*| O_NONBLOCK*/); if (fd <= 0) { perror("open serial"); fprintf(stderr,"opening %s failed\n", port); return (-1); } res = tcgetattr(fd, &ssetup); if (res < 0) { perror("tcgetattr"); return (-1); } ssetup.c_iflag = 0L; ssetup.c_oflag = 0L; ssetup.c_cflag &= ~(CSTOPB|PARENB|CRTSCTS); ssetup.c_cflag |= (CS8|CLOCAL); ssetup.c_lflag = 0L; ssetup.c_cc[VTIME] = 0; ssetup.c_cc[VMIN] = 1; cfsetispeed(&ssetup, baud); cfsetospeed(&ssetup, baud); res=tcsetattr(fd, TCSANOW, &ssetup); if (res < 0) { perror("tcsetattr"); return (-1); } return (fd); } #ifdef USELIRC int lirc(char *progname) { struct lirc_config *config; if (debug) fprintf(stderr, "progname %s\n",progname); if (lirc_init(progname,1) == -1) { printf("failed to init lirc\n"); exit(EXIT_FAILURE); } if (debug) fprintf(stderr, "in lirc\n"); if (lirc_readconfig(NULL,&config,NULL) == 0) { int i, ret; char *code, *c; while (lirc_nextcode(&code) == 0) { if (code == NULL) continue; while ((ret = lirc_code2char(config, code, &c)) == 0 && c != NULL) { sscanf(c,"%x",&i); if (debug) fprintf(stderr, "%s %u\n",c,i); dev_uinput_key(uindev, i, KEY_PRESSED); dev_uinput_key(uindev, i, KEY_RELEASED); if (debug) fprintf(stderr, "Code : %s\n",c); } free(code); if (ret == -1) break; } lirc_freeconfig(config); } return lirc_deinit(); } #endif int compaq_foldable(void) { int fd; unsigned char buf[16]; char fn=0; fd = open_serial(TTY_PORT, B4800); if (fd <= 0) return (-1); while (fd > 0) { read (fd, buf, 2); // fprintf(stderr, "0x%02x 0x%02x 0x%02x | ", buf[0], buf[1], ~buf[0]); if (buf[0] == (unsigned char)~buf[1]) { if (debug) fprintf(stderr, "press: %d ", buf[0]); if (buf[0] == 0x02) { fn=1; continue; } if (fn) buf[0] = foldable_function[buf[0]]; else buf[0] = foldable_normal[buf[0]]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } else if (((unsigned char)buf[0] & (unsigned char)~0x80) == (unsigned char)~buf[1]) { if (debug) fprintf(stderr, "rel. : %d ", buf[0] & ~0x80); if ((buf[0] & ~0x80) == 0x02) { fn = 0; continue; } if (fn) buf[0] = foldable_function[(unsigned char)buf[0] & (unsigned char)~0x80]; else buf[0] = foldable_normal[(unsigned char)buf[0] & (unsigned char)~0x80]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } } return 0; } int lastChar = 0; char shiftState = 0; char altState = 0; char ctrlState = 0; //struct timeval tvlast; //unsigned char lastkey; int belkin_infrared(void) { int fd; //unsigned char buf[16]; unsigned char buf; unsigned char key; unsigned int key_down; unsigned int key_state; unsigned char keycode; int isChar = 0; //struct timeval tv; // gettimeofday(&tv, NULL); fd = open_serial(TTY_PORT, B9600); if (fd <= 0) return (-1); while (fd > 0) { // read (fd, buf, 2); // key = buf[1] & 0x7f; // key_down = !(buf[1] & 0x80); read (fd, &buf, 1); key = buf & 0x7f; key_down = !(buf & 0x80); // keycode = belkin_irda_normal[key]; keycode = key; switch (keycode) { case 81: keycode = 16; break; //q - case 87: keycode = 17; break; //w - case 69: keycode = 18; break; //e - case 82: keycode = 19; break; //r - case 84: keycode = 20; break; //t - case 89: keycode = 21; break; //y - case 85: keycode = 22; break; //u - case 73: keycode = 23; break; //i - case 79: keycode = 24; break; //o - case 80: keycode = 25; break; //p - case 91: keycode = 26; break; //[ - case 93: keycode = 27; break; //] - case 13: keycode = 28; break; // ret - case 94: keycode = 30; break; //a - case 83: keycode = 31; break; //s - case 68: keycode = 32; break; //d - case 70: keycode = 33; break; //f - case 71: keycode = 34; break; //g - case 72: keycode = 35; break; //h case 74: keycode = 36; break; //j - case 75: keycode = 37; break; //k - case 76: keycode = 38; break; //l - case 59: keycode = 39; break; //; case 44: keycode = 40; break; //' - case 90: keycode = 44; break; //z - case 88: keycode = 45; break; //x - case 67: keycode = 46; break; //c - case 86: keycode = 47; break; //v case 66: keycode = 48; break; //b case 78: keycode = 49; break; //n case 77: keycode = 50; break; //m case 60: keycode = 51; break; //,< case 46: keycode = 52; break; //.> case 47: keycode = 53; break; // /? - case 27: keycode = 1; break; // til case 49: keycode = 2; break; // 1 case 50: keycode = 3; break; // 2 case 51: keycode = 4; break; // 3 case 52: keycode = 5; break; // 4 case 53: keycode = 6; break; // 5 case 54: keycode = 7; break; // 6 case 55: keycode = 8; break; // 7 case 56: keycode = 9; break; // 8 case 57: keycode = 10; break; // 9 case 48: keycode = 11; break; // 0 case 45: keycode = 12; break; // - case 61: keycode = 13; break; //-= case 8: keycode = 14; break; // bkspace case 9: keycode = 15; break; // tab case 20: keycode = 58; break; // caps lock case 16: // shift l - case 18: keycode = 42; break; // shift r case 17: keycode = 29; break; // ctrl case 29: keycode = 56; break; // alt case 32: keycode = 57; break; // space - case 33: keycode = 57; break; // space - case 92: keycode = 43; break; // backslash bar - case 19: keycode = 111; break; // del case 37: keycode = 103; break; // right case 38: keycode = 105; break; // up case 39: keycode = 108; break; // left case 40: keycode = 106; break; // down //default: keycode =0; break; //case 79: keycode = 24; break; } if ( /*(keycode >= 2 && keycode <=13) || */(keycode >= 16 && keycode <= 25) || (keycode >= 30 && keycode <= 38) || (keycode >= 44 && keycode <= 50)) { isChar = 1; if (debug && isChar) fprintf (stderr, "is char\n"); } //if (debug) // fprintf(stderr, "ctrl:%d alt:%d shift:%d\n", ctrlState, altState, shiftState); // if (! isChar) { if ( key_down ) key_state = KEY_PRESSED; else key_state = KEY_RELEASED; if (lastChar == 64) key_state = KEY_RELEASED; if (debug) fprintf(stderr,"event %d %d\n", key_state, keycode); dev_uinput_key(uindev, (unsigned short)keycode, key_state); lastChar = keycode; /* } else { if (! key_down && keycode == lastChar) { if (shiftState) { if (debug) fprintf(stderr,"release %d\n", 14); dev_uinput_key(uindev, (unsigned short)14, KEY_RELEASED); } else if (ctrlState || altState) { if (debug) fprintf(stderr,"release %d\n", 19); dev_uinput_key(uindev, (unsigned short)19, KEY_RELEASED); } if (debug && keycode) fprintf(stderr,"press %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED); if (debug && keycode) fprintf(stderr,"release %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED); if (debug && keycode) fprintf(stderr,"release %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED); } lastChar = keycode; }*/ } return 0; } int freedom_keyboard(void) { int fd; unsigned char buf[16]; unsigned char key; unsigned int key_down; unsigned char keycode; fd = open_serial(TTY_PORT, B9600); if (fd <= 0) return (-1); while (fd > 0) { read (fd, buf, 1); key = buf[0]; //keyboard sends n when pressing a key // and n+63 when releasing the key key_down = ( key < 63 ); if (!key_down) key = (key-63)&0x3F; // convert key code for key up keycode = freedom_kbd[key]; if (debug) fprintf(stdout, "0x%02x 0x%02x\n", buf[0], keycode); if ( key_down ) { if (debug) fprintf(stdout,"press %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED); } else { if (debug) fprintf(stdout,"release %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED); } } return 0; } int select_read(int fd, int timeout_sec, int timeout_us) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = timeout_sec; tv.tv_usec = timeout_us; return select(fd+1, &fds, NULL, NULL, &tv); } int stowaway_init(int fd) { int status; unsigned char buf[16]; ioctl(fd, TIOCMGET, &status); status |= TIOCM_DTR; /* Set DTR */ status &= ~TIOCM_RTS; /* Clear RTS */ ioctl(fd, TIOCMSET, &status); /* Unfortunately, DCD seems to be high all of the time on H3900, so the following can't be used */ /* ioctl(fd, TIOCMIWAIT, TIOCM_CAR */ /* So we just wait instead */ usleep(1000000); ioctl(fd, TIOCMGET, &status); status |= TIOCM_RTS; /* Set RTS */ ioctl(fd, TIOCMSET, &status); /* Stowaway will send back 0xFA 0xFD indicating successful init */ if (select_read(fd, 2, 0)) { read(fd, buf, 2); if ((buf[0] == 0xFA) && (buf[0] == 0xFD)) if (debug) fprintf(stderr, "keyboard initialised\n"); } return 0; } int open_apm(void) { int fd; fd = open( "/dev/apm_bios", O_RDONLY | O_NONBLOCK ); if (fd <= 0) return -1; return fd; } int check_apm_resume(int fd) { apm_event_t ev; int resumed; resumed = 0; while (read(fd, &ev, sizeof(apm_event_t)) > 0) { if (ev == APM_NORMAL_RESUME) resumed = 1; } return resumed; } void stowaway_sig(int sig) { reinit = 1; } int stowaway(void) { int fd, apm_fd; unsigned char buf[16]; char fn=0; struct sigaction act; int rc; fd = open_serial(TTY_PORT, B9600); if (fd <= 0) return (-1); /* Make SIGHUP cause a reinit of the keyboard */ act.sa_handler = stowaway_sig; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGHUP, &act, NULL); /* Open APM so we can listen for resume events */ apm_fd = open_apm(); while (fd > 0) { stowaway_init(fd); while (fd > 0) { rc = select_read(fd, 0, 100000); if (rc == -1) { if (reinit) { reinit = 0; break; } else { perror("select"); return 1; } } else if (rc == 0) { /* Timeout expired with nothing read, do APM resume check */ if ((apm_fd > 0) && (check_apm_resume(apm_fd))) break; continue; } rc = read (fd, buf, 1); if (rc == -1) { if (reinit) { reinit = 0; break; } else { perror("read"); return 1; } } if ( ((unsigned char)buf[0] & (unsigned char)0x80) == 0 ) { if (debug) fprintf(stderr, "press: %d\n", buf[0]); if (buf[0] == 0x08) { fn = 1; continue; } if (fn) buf[0] = stowaway_function[buf[0]]; else buf[0] = stowaway_normal[buf[0]]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } else { if (debug) fprintf(stderr, "rel. : %d\n", buf[0] & ~0x80); if ((buf[0] & ~0x80) == 0x08) { fn = 0; continue; } if (fn) buf[0] = stowaway_function[(unsigned char)buf[0] & (unsigned char)~0x80]; else buf[0] = stowaway_normal[(unsigned char)buf[0] & (unsigned char)~0x80]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } } } return 0; } int stowawayxt(void) { #define STOWAWAYXT_GR_FN 33 #define STOWAWAYXT_BL_FN 34 int fd, apm_fd; unsigned char buf[16]; char bluefn=0,greenfn=0; struct sigaction act; int rc; fd = open_serial(TTY_PORT, B9600); if (fd <= 0) return (-1); /* Make SIGHUP cause a reinit of the keyboard */ act.sa_handler = stowaway_sig; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGHUP, &act, NULL); /* Open APM so we can listen for resume events */ apm_fd = open_apm(); while (fd > 0) { stowaway_init(fd); while (fd > 0) { rc = select_read(fd, 0, 100000); if (rc == -1) { if (reinit) { reinit = 0; break; } else { perror("select"); return 1; } } else if (rc == 0) { /* Timeout expired with nothing read, do APM resume check */ if ((apm_fd > 0) && (check_apm_resume(apm_fd))) break; continue; } rc = read (fd, buf, 1); if (rc == -1) { if (reinit) { reinit = 0; break; } else { perror("read"); return 1; } } if ( ((unsigned char)buf[0] & (unsigned char)0x80) == 0 ) { /* KEY PRESSED */ if (debug) fprintf(stderr, "press: %d\n", buf[0]); if (buf[0] == STOWAWAYXT_BL_FN) { bluefn = 1; continue; } if (buf[0] == STOWAWAYXT_GR_FN) { greenfn = 1; dev_uinput_key(uindev,42,KEY_PRESSED); continue; } if (bluefn) buf[0] = stowawayxt_function[buf[0]]; else if (greenfn) { buf[0] = stowawayxt_function[buf[0]]; /* fixup where green function is not shift blue function */ switch (buf[0]) { case KEY_UP: buf[0] = KEY_PAGEUP; break; case KEY_LEFT: buf[0] = KEY_HOME; break; case KEY_DOWN: buf[0] = KEY_PAGEDOWN; break; case KEY_RIGHT: buf[0] = KEY_END; break; case KEY_INTL2: buf[0] = KEY_INTL3; break; } /* /switch */ } else buf[0]=stowawayxt_normal[buf[0]]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] != KEY_RESERVED) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } else { /* KEY RELEASED */ if (debug) fprintf(stderr, "rel. : %d\n", buf[0] & ~0x80); if ((buf[0] & ~0x80) == STOWAWAYXT_BL_FN) { bluefn = 0; continue; } if ((buf[0] & ~0x80) == STOWAWAYXT_GR_FN) { greenfn = 0; dev_uinput_key(uindev,42,KEY_RELEASED); continue; } if (bluefn) buf[0] = stowawayxt_function[(unsigned char) buf[0] & (unsigned char)~0x80]; else if (greenfn) { buf[0] = stowawayxt_function[(unsigned char) buf[0] & (unsigned char)~0x80]; /* fixup where green function is not shift blue function */ switch(buf[0]) { case KEY_UP: buf[0] = KEY_PAGEUP; break; case KEY_LEFT: buf[0] = KEY_HOME; break; case KEY_DOWN: buf[0] = KEY_PAGEDOWN; break; case KEY_RIGHT: buf[0] = KEY_END; break; case KEY_INTL2: buf[0] = KEY_INTL3; break; } /* /switch */ } else buf[0] = stowawayxt_normal[(unsigned char)buf[0] & (unsigned char)~0x80]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] != KEY_RESERVED) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } } } return 0; } int snapntype(void) { int fd; unsigned char buf[16]; char symb=0; fd = open_serial(TTY_PORT, B2400); while (fd > 0) { read (fd, buf, 1); if (debug) fprintf(stderr, "got %d\n", buf[0]); if (buf[0] & 0x80) { /* release */ read(fd,buf+1,1); buf[0] = buf[0] & 0x7f; if (buf[0] == 27) { symb = 0; continue; } if (symb) buf[0] = snapntype_symbol[buf[0]]; else buf[0] = snapntype_normal[buf[0]]; if (debug) fprintf(stderr, " release %d\n", buf[0]); if (buf[0] != 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } else { /* press */ if (buf[0] == 27) { symb=1; continue; } if (symb) buf[0] = snapntype_symbol[buf[0]]; else buf[0] = snapntype_normal[buf[0]]; if (debug) fprintf(stderr, " press %d\n", buf[0]); if (buf[0] != 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } } return 0; } int snapntypebt(void) { int fd; unsigned char buf[16]; unsigned char key, last_key=0; unsigned char pressed; unsigned char fn = 0; fd = open_serial(TTY_PORT, B9600); while (fd > 0) { read (fd, buf, 1); read (fd, buf+1, 1); if (debug) fprintf(stderr, "got %02x%02x\n", buf[0],buf[1]); if (buf[1] & 0x80) { /* release */ key = buf[1] & 0x7F; if (key == 30) { fn = 0; if (last_key) { dev_uinput_key(uindev, (unsigned short)snapntypebt_fn[last_key], KEY_RELEASED); } continue; } pressed = KEY_RELEASED; if (debug) fprintf(stderr, " release:"); } else { key = buf[1]; if (key == 30) { fn = 1; last_key = 0; continue; } pressed = KEY_PRESSED; if (debug) fprintf(stderr, " press: "); } if (debug) fprintf(stderr, " %d (%d)\n",key,snapntypebt_normal[key]); if (!fn) key = snapntypebt_normal[key]; else { last_key = key; key = snapntypebt_fn[key]; } if (key != 0 && !debug) dev_uinput_key(uindev, (unsigned short)key, pressed); } return 0; } int hpslim(void) { int fd; unsigned char cin; unsigned char cnew; char symb=0; char shft=0; char symshft=0; char numlck=0; fd = open_serial(TTY_PORT, B4800); if (fd < 0) return -1; for (;;) { if (read (fd, &cin, 1) < 0) { perror(TTY_PORT); return -1; } if (debug) fprintf(stderr, "got %d 0x%x\n", cin,cin); if (cin & 0x80) { /* release */ cin &= 0x7f; switch (cin) { case MKBD_HPS_FNKEY: /* Fn key release */ symb = 0; continue; case KEY_LEFTSHIFT: case KEY_RIGHTSHIFT: shft = 0; break; } if (symb) cnew = hpslim_symbol[cin]; else { /* if numlock, convert QWERTYUIOP to 1-9,0 */ if (numlck && cin >= KEY_Q && cin <= KEY_P) cnew = cin + KEY_1 - KEY_Q; else cnew = hpslim_normal[cin]; } if (debug) fprintf(stderr, " release cnew=%d 0x%x\n", cnew,cnew); if (cnew != 0) { dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED); if (symshft) dev_uinput_key(uindev, (unsigned short)KEY_RIGHTSHIFT, KEY_RELEASED); symshft = 0; // toggle numlck on release if (cnew == KEY_NUMLOCK) numlck = !numlck; } } else { /* press */ switch (cin) { case MKBD_HPS_FNKEY: /* Fn key press */ symb = 1; continue; case KEY_LEFTSHIFT: case KEY_RIGHTSHIFT: shft = 1; break; } if (symb) { /* if shift needed to get correct char */ symshft = hpslim_symshft[cin] && !shft; cnew = hpslim_symbol[cin]; } else { /* if numlock, convert QWERTYUIOP to 1-9,0 */ if (numlck && cin >= KEY_Q && cin <= KEY_P) cnew = cin + KEY_1 - KEY_Q; else cnew = hpslim_normal[cin]; } if (debug) fprintf(stderr, " press cnew=%d 0x%x\n", cnew,cnew); if (cnew != 0) { if (symshft) dev_uinput_key(uindev, (unsigned short)KEY_RIGHTSHIFT, KEY_PRESSED); dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED); } } } return 0; } int smartbt(void) { int fd; unsigned char buf[16]; fd = open_serial(TTY_PORT, B2400); while (fd > 0) { read (fd, buf, 1); if (buf[0] > 126) { if (debug) fprintf(stderr, "error: unexpected char %d\n", buf[0]); continue; } if (buf[0] > 63) { /* release */ buf[0] = buf[0] - 63; if (debug) fprintf(stderr, "rel.: %d\n", buf[0]); buf[0] = smartbt_normal[buf[0]]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } else { /* press */ if (debug) fprintf(stderr, "press: %d\n", buf[0]); buf[0] = smartbt_normal[buf[0]]; if (debug) fprintf(stderr,"= 0x%02x\n", buf[0]); if (buf[0] > 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } } return 0; } int flexis(void) { int fd; unsigned char buf[16]; char symb=0; fd = open_serial(TTY_PORT, B9600); while (fd > 0) { read (fd, buf, 1); if (debug) fprintf(stderr, "got %d\n", buf[0]); if (buf[0] & 0x80) { /* key press */ buf[0] = buf[0] & 0x7f; if (symb) buf[0] = flexis_fx100_function[buf[0]]; else buf[0] = flexis_fx100_normal[buf[0]]; /* FIXME: function key */ /* FIXME: this code is a little broken, it should check scancode not keycode for set 1/2 */ if (buf[0] == KEY_LEFTSHIFT || buf[0] == KEY_RIGHTSHIFT || buf[0] == KEY_LEFTCTRL || buf[0] == KEY_RIGHTCTRL || buf[0] == KEY_LEFTALT || buf[0] == KEY_RIGHTALT ) { dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } else { read(fd,buf+1,1); if (debug) fprintf(stderr, "got %d\n", buf[1]); dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } } else { /* release of key from Set 2 */ if (symb) buf[0] = flexis_fx100_function[buf[0]]; else buf[0] = flexis_fx100_normal[buf[0]]; if (buf[0] != 0) dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); } } return 0; } int benqgamepad(void) { int fd; unsigned char buf[16]; int i; unsigned char keycode; fd = open_serial(TTY_PORT, B4800); while (fd > 0) { keycode = 0; read (fd, buf, 2); if (buf[0] & 0x80) { /* release */ if (debug) fprintf(stderr, "release: %d %d\n", buf[0], buf[1]); buf[0] = buf[0] & 0x7f; for (i=0; i<10; i++) { if (benq_gamepad_map[i][0] == buf[0]) { keycode = benq_gamepad_map[i][1]; break; } } if (keycode != 0) dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED); } else { if (debug) fprintf(stderr, "press: %d %d\n", buf[0], buf[1]); for (i=0; i<10; i++) { if (benq_gamepad_map[i][0] == buf[0]) { keycode = benq_gamepad_map[i][1]; break; } } if (keycode != 0) dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED); } } return 0; } int pocketvik(void) { int fd; unsigned char buf[16]; unsigned char mods=0; int res; struct termios ssetup; int i; fd = open_serial(TTY_PORT, B57600); /* PocketVIK needs CRTSCTS */ res = tcgetattr(fd, &ssetup); if (res < 0) { perror("tcgetattr"); return (-1); } ssetup.c_cflag |= CRTSCTS; res = tcsetattr(fd, TCSANOW, &ssetup); if (res < 0) { perror("tcgetattr"); return (-1); } while (fd > 0) { read (fd, buf, 1); if (debug) fprintf(stderr, "got %d\n", buf[0]); if (buf[0] & 0x80) { /* press with modifiers */ mods = buf[0] & 0x7f; read (fd, buf, 1); } else mods = 0; if (mods & POCKETVIK_Fn) buf[0] = pocketvik_function[buf[0]]; else buf[0] = pocketvik_normal[buf[0]]; if (buf[0] != 0) { if (debug) fprintf(stderr, "press/release %d\n", buf[0]); /* Modifiers down */ for ( i = 0 ; i < ARRAY_SIZE(pocketvik_modifiers) ; i++ ) { if (pocketvik_modifiers[i].mask & mods) dev_uinput_key(uindev, pocketvik_modifiers[i].key, KEY_PRESSED); } /* Key down */ dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); /* Key up */ dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED); /* Modifiers up */ for (i = 0; i < ARRAY_SIZE(pocketvik_modifiers); i++ ) { if (pocketvik_modifiers[i].mask & mods) dev_uinput_key(uindev, pocketvik_modifiers[i].key, KEY_RELEASED); } } } return 0; } int micro_foldaway(void) { int fd; unsigned char buf[16]; unsigned char lastkey = 0; // char symb=0; int checkkey = 0; fd = open_serial(TTY_PORT, B9600); while (fd > 0) { read (fd, buf, 1); if (debug) fprintf(stderr, "got: %d\n", buf[0]); if (buf[0] & 0x80) { /* possible release */ checkkey = (159 - buf[0]); if (checkkey > 0 && checkkey <= 4) { buf[0] = micro_foldaway_normal[159 - buf[0]]; dev_uinput_key(uindev, buf[0], KEY_RELEASED); } else if (buf[0] == 133 && lastkey > 0) { dev_uinput_key(uindev, lastkey, KEY_RELEASED); lastkey = 0; } /* Eat repeated code */ read (fd, buf, 1); } else { checkkey = buf[0]; /* if (symb) buf[0] = micro_foldaway_function[buf[0]]; else*/ buf[0] = micro_foldaway_normal[buf[0]]; if (buf[0] != 0) { if (checkkey > 4) lastkey = buf[0]; /* Not a modifier, record key */ dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } } } return 0; } int micro_datapad(void) { int fd; unsigned char buf[16]; unsigned char lastkey = 0; int checkkey = 0; fd = open_serial(TTY_PORT, B9600); while (fd > 0) { read (fd, buf, 1); if (debug) fprintf(stderr, "got: %d\n", buf[0]); if (buf[0] & 0x80) { /* possible release */ checkkey = (159 - buf[0]); if (checkkey > 0 && checkkey <= 4) { buf[0] = micro_foldaway_normal[159 - buf[0]]; dev_uinput_key(uindev, buf[0], KEY_RELEASED); } else if (buf[0] == 133 && lastkey > 0) { dev_uinput_key(uindev, lastkey, KEY_RELEASED); lastkey = 0; } /* Eat repeated code */ read (fd, buf, 1); } else { checkkey = buf[0]; /* if (symb) buf[0]=micro_datapad_function[buf[0]]; else*/ buf[0] = micro_datapad_normal[buf[0]]; if (buf[0] != 0) { if (checkkey > 4) lastkey = buf[0]; /* Not a modifier, record key */ dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED); } } } return 0; } int hp_bt_foldable(void){ int fd; unsigned char buf[1]; unsigned char cnew; char symb=0; fd = open_serial(TTY_PORT, B9600); if (fd < 0) return -1; for (;;) { if (read (fd, buf, 1) < 0) { perror(TTY_PORT); return -1; } if (debug) fprintf(stderr, "got %d (0x%x)\n", buf[0], buf[0]); if (buf[0] & 0x80) { /* release */ buf[0] &= 0x7f; if (buf[0] == 2) { symb = 0; continue; } if (symb) cnew = btfoldable_function[buf[0]]; else cnew = btfoldable_normal[buf[0]]; if (debug) fprintf(stderr, " release cnew=%d (0x%x)\n", cnew, cnew); if (cnew != 0) dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED); } else { /* press */ if (buf[0] == 2) { symb = 1; continue; } if (symb) cnew = btfoldable_function[buf[0]]; else cnew = btfoldable_normal[buf[0]]; if (debug) fprintf(stderr, " press cnew=%d (0x%x)\n", cnew, cnew); if (cnew != 0) dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED); } } return 0; } int compaq_microkbd(void) { int fd; unsigned char buf[2]; unsigned char cnew; char symb=0; fd = open_serial(TTY_PORT, B4800); if (fd < 0) return -1; for (;;) { if (read (fd, buf, 2) < 0) { perror(TTY_PORT); return -1; } if (debug) fprintf(stderr, "got %d %d (0x%x 0x%x)\n", buf[0], buf[1], buf[0], buf[1]); if (buf[0] & 0x80) { /* release */ buf[0] &= 0x7f; if (buf[0] == 2) { symb = 0; continue; } if (symb) cnew = compaq_function[buf[0]]; else cnew = compaq_normal[buf[0]]; if (debug) fprintf(stderr, " release cnew=%d (0x%x)\n", cnew, cnew); if (cnew != 0) dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED); } else { /* press */ if (buf[0] == 2) { symb = 1; continue; } if (symb) cnew = compaq_function[buf[0]]; else cnew = compaq_normal[buf[0]]; if (debug) fprintf(stderr, " press cnew=%d (0x%x)\n", cnew, cnew); if (cnew != 0) dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED); } } return 0; } int targus_infrared(void) { int fd; unsigned char buf; unsigned char key; unsigned int key_down; unsigned char keycode; fd = open_serial(TTY_PORT, B9600); if (fd <= 0) return (-1); while (fd > 0) { read (fd, &buf, 1); key = buf & 0x7f; key_down = !(buf & 0x80); // keycode = belkin_irda_normal[key]; keycode = key; if (debug) fprintf(stderr, "0x%02x 0x%02x\n", buf, key); if ( key_down ) { if (debug) fprintf(stderr,"press %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED); } else { if (debug) fprintf(stderr,"release %d\n", keycode); dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED); } } return 0; } void print_usage(char *arg0) { fprintf (stderr, "kbdd %s\n", VERSION); fprintf (stderr, "Usage:\n"); fprintf (stderr, "%s [-d] [-h] [-c ] -p -t \n", arg0); fprintf (stderr, "-d\tenable debugging output\n"); fprintf (stderr, "-h\tprint this help\n"); fprintf (stderr, "-c \n"); fprintf (stderr, "\tRead port and type from config file\n"); fprintf (stderr, "-p \n"); fprintf (stderr, "\tspecify serial port device, default %s\n", DEFAULT_TTS); fprintf (stderr, "-t \n"); fprintf (stderr, "\tspecify the serial keyboard type, supported are:\n"); fprintf (stderr, "\tfoldable - Compaq/HP foldable keyboard\n"); fprintf (stderr, "\tstowaway - Targus Stowaway keyboard\n"); fprintf (stderr, "\tstowawayxt - Stowaway XT\n"); fprintf (stderr, "\tsnapntype - Snap'n'Type\n"); fprintf (stderr, "\tsnapntypebt - Snap'n'Type Bluetooth\n"); fprintf (stderr, "\thpslim - HP Slim keyboard\n"); fprintf (stderr, "\tsmartbt - Smart Bluetooth keyboard\n"); fprintf (stderr, "\tlirc - LIRC consumer IR\n"); fprintf (stderr, "\tbelkinir - Belkin IR (not IrDA)\n"); fprintf (stderr, "\tflexis - Flexis FX-100 keyboard\n"); fprintf (stderr, "\tg250 - Benq G250 gamepad\n"); fprintf (stderr, "\tpocketvik - GrandTec PocketVIK\n"); fprintf (stderr, "\tmicrofold - Micro Innovations Foldaway keyboard\n"); fprintf (stderr, "\tmicropad - Micro Innovations Datapad\n"); fprintf (stderr, "\tmicrokbd - Compaq MicroKeyboard\n"); fprintf (stderr, "\ttargusir - Targus Universal Wireless keyboard\n"); fprintf (stderr, "\tbtfoldable - HP iPAQ Bluetooth Foldable Keyboard\n\n"); fprintf (stderr, "\tfreedom - Freedom keyboard\n"); fprintf (stderr, "Example:\n\t%s -t foldable\n", arg0); } #define KBD_TYPE_NONE 0 #define KBD_TYPE_FOLDABLE 1 #define KBD_TYPE_SNAPNTYPE 2 #define KBD_TYPE_STOWAWAY 3 #define KBD_TYPE_STOWAWAYXT 4 #define KBD_TYPE_HPSLIM 5 #define KBD_TYPE_SMARTBT 6 #define KBD_TYPE_LIRC 7 #define KBD_TYPE_BELKINIR 8 #define KBD_TYPE_FLEXIS 9 #define KBD_TYPE_BENQ_GAMEPAD 10 #define KBD_TYPE_POCKETVIK 11 #define KBD_TYPE_MICRO_FOLDAWAY 12 #define KBD_TYPE_MICRO_DATAPAD 13 #define KBD_TYPE_COMPAQ_MICROKBD 14 #define KBD_TYPE_TARGUSIR 15 #define KBD_TYPE_SNAPNTYPEBT 16 #define KBD_TYPE_BTFOLDABLE 17 #define KBD_TYPE_FREEDOM 18 int find_kbd_type(const char *ktype) { if (strncmp("foldable", ktype, 8) == 0) return KBD_TYPE_FOLDABLE; else if (strncmp("snapntypebt", ktype, 11) == 0) return KBD_TYPE_SNAPNTYPEBT; else if (strncmp("snapntype", ktype, 9) == 0) return KBD_TYPE_SNAPNTYPE; else if (strncmp("stowawayxt", ktype, 10) == 0) return KBD_TYPE_STOWAWAYXT; else if (strncmp("stowaway", ktype, 8) == 0) return KBD_TYPE_STOWAWAY; else if (strncmp("hpslim", ktype, 6) == 0) return KBD_TYPE_HPSLIM; else if (strncmp("smartbt", ktype, 7) == 0) return KBD_TYPE_SMARTBT; else if (strncmp("flexis", ktype, 6) == 0) return KBD_TYPE_FLEXIS; else if (strncmp("lirc", ktype, 4) == 0) return KBD_TYPE_LIRC; else if (strncmp("belkinir", ktype, 8) == 0) return KBD_TYPE_BELKINIR; else if (strncmp("g250", ktype, 4) == 0) return KBD_TYPE_BENQ_GAMEPAD; else if (strncmp("pocketvik", ktype, 9) == 0) return KBD_TYPE_POCKETVIK; else if (strncmp("microfold", ktype, 9) == 0) return KBD_TYPE_MICRO_FOLDAWAY; else if (strncmp("micropad", ktype, 8) == 0) return KBD_TYPE_MICRO_DATAPAD; else if (strncmp("microkbd", ktype, 8) == 0) return KBD_TYPE_COMPAQ_MICROKBD; else if (strncmp("targusir", ktype, 8) == 0) return KBD_TYPE_TARGUSIR; else if (strncmp("btfoldable", ktype, 10) == 0) return KBD_TYPE_BTFOLDABLE; else if (strncmp("freedom", ktype, 7) == 0) return KBD_TYPE_FREEDOM; fprintf(stderr, "unrecognised keyboard type %s\n", ktype); return KBD_TYPE_NONE; } void parse_config(const char *path, int *kbdtype, char port[]) { char *needle; FILE *fd; char buf[PATH_MAX]; fd = fopen(path, "r"); if (!fd) { fprintf(stderr, "could not open config file %s\n", path); return; } while (!feof(fd)) { fgets(buf, PATH_MAX, fd); if (*buf == '#' || *buf == '\0') { /* It's a comment or a blank line */ continue; } if ((needle = strstr(buf, "port:")) != 0) { needle += 5; /* Trim whitespaces */ while (isspace(*needle)) { needle++; } while (isspace(needle[strlen(needle)-1])) { needle[strlen(needle)-1] = '\0'; } strncpy(port, needle, PATH_MAX); } else if ((needle = strstr(buf, "type:")) != 0) { needle += 5; /* Trim whitespaces */ while (isspace(*needle)) { needle++; } while (isspace(needle[strlen(needle)-1])) { needle[strlen(needle)-1] = '\0'; } *kbdtype = find_kbd_type(needle); } } } int main(int argc, char **argv) { int optc; int kbdtype=KBD_TYPE_NONE; while ((optc = getopt(argc, argv, "c:t:p:dh")) != -1) { switch ((char)optc) { case 'h': print_usage(argv[0]); exit(1); break; case 'd': debug = 1; break; case 't': kbdtype = find_kbd_type(optarg); break; case 'p': strncpy(TTY_PORT, optarg, PATH_MAX); break; case 'c': parse_config(optarg, &kbdtype, TTY_PORT); break; } } if (kbdtype == 0) { print_usage(argv[0]); exit(1); } uindev = dev_uinput_init(); if (uindev <= 0) { fprintf(stderr, "init uinput failed\n"); exit (1); } signal(SIGTERM, handle_sigterm); if (kbdtype == KBD_TYPE_FOLDABLE) compaq_foldable(); else if (kbdtype == KBD_TYPE_BTFOLDABLE) hp_bt_foldable(); else if (kbdtype == KBD_TYPE_SNAPNTYPE) snapntype(); else if (kbdtype == KBD_TYPE_SNAPNTYPEBT) snapntypebt(); else if (kbdtype == KBD_TYPE_STOWAWAY) stowaway(); else if (kbdtype == KBD_TYPE_STOWAWAYXT) stowawayxt(); else if (kbdtype == KBD_TYPE_HPSLIM) hpslim(); else if (kbdtype == KBD_TYPE_SMARTBT) smartbt(); else if (kbdtype == KBD_TYPE_FLEXIS) flexis(); else if (kbdtype == KBD_TYPE_BENQ_GAMEPAD) benqgamepad(); else if (kbdtype == KBD_TYPE_POCKETVIK) pocketvik(); else if (kbdtype == KBD_TYPE_MICRO_FOLDAWAY) micro_foldaway(); else if (kbdtype == KBD_TYPE_MICRO_DATAPAD) micro_datapad(); else if (kbdtype == KBD_TYPE_COMPAQ_MICROKBD) compaq_microkbd(); else if (kbdtype == KBD_TYPE_LIRC) #ifdef USELIRC lirc(basename(argv[0]); #else { fprintf(stderr, "keyboard type 'lirc' is not supported in this version\n"); exit(1); } #endif else if (kbdtype == KBD_TYPE_BELKINIR) belkin_infrared(); else if (kbdtype == KBD_TYPE_TARGUSIR) targus_infrared(); else if (kbdtype == KBD_TYPE_FREEDOM) freedom_keyboard(); return 0; }