/* keyfaker - Linux keyboard-typer faker Copyright (C) 2010 Kabel 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 3 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, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define SHIFT 0x00000100 struct { int keycode; char ch; } keys[] = { { KEY_0, '0' }, { KEY_1, '1' }, { KEY_2, '2' }, { KEY_3, '3' }, { KEY_4, '4' }, { KEY_5, '5' }, { KEY_6, '6' }, { KEY_7, '7' }, { KEY_8, '8' }, { KEY_9, '9' }, { KEY_MINUS, '-' }, { KEY_EQUAL, '=' }, { KEY_A, 'a' }, { KEY_B, 'b' }, { KEY_C, 'c' }, { KEY_D, 'd' }, { KEY_E, 'e' }, { KEY_F, 'f' }, { KEY_G, 'g' }, { KEY_H, 'h' }, { KEY_I, 'i' }, { KEY_J, 'j' }, { KEY_K, 'k' }, { KEY_L, 'l' }, { KEY_M, 'm' }, { KEY_N, 'n' }, { KEY_O, 'o' }, { KEY_P, 'p' }, { KEY_Q, 'q' }, { KEY_R, 'r' }, { KEY_S, 's' }, { KEY_T, 't' }, { KEY_U, 'u' }, { KEY_V, 'v' }, { KEY_W, 'w' }, { KEY_X, 'x' }, { KEY_Y, 'y' }, { KEY_Z, 'z' }, { KEY_LEFTBRACE, '[' }, { KEY_RIGHTBRACE, ']' }, { KEY_SEMICOLON, ';' }, { KEY_APOSTROPHE, '\'' }, { KEY_BACKSLASH, '\\' }, { KEY_COMMA, ',' }, { KEY_DOT, '.' }, { KEY_SLASH, '/' }, { SHIFT | KEY_0, ')' }, { SHIFT | KEY_1, '!' }, { SHIFT | KEY_2, '@' }, { SHIFT | KEY_3, '#' }, { SHIFT | KEY_4, '$' }, { SHIFT | KEY_5, '%' }, { SHIFT | KEY_6, '^' }, { SHIFT | KEY_7, '&' }, { SHIFT | KEY_8, '*' }, { SHIFT | KEY_9, '(' }, { SHIFT | KEY_MINUS, '_' }, { SHIFT | KEY_EQUAL, '+' }, { SHIFT | KEY_A, 'A' }, { SHIFT | KEY_B, 'B' }, { SHIFT | KEY_C, 'C' }, { SHIFT | KEY_D, 'D' }, { SHIFT | KEY_E, 'E' }, { SHIFT | KEY_F, 'F' }, { SHIFT | KEY_G, 'G' }, { SHIFT | KEY_H, 'H' }, { SHIFT | KEY_I, 'I' }, { SHIFT | KEY_J, 'J' }, { SHIFT | KEY_K, 'K' }, { SHIFT | KEY_L, 'L' }, { SHIFT | KEY_M, 'M' }, { SHIFT | KEY_N, 'N' }, { SHIFT | KEY_O, 'O' }, { SHIFT | KEY_P, 'P' }, { SHIFT | KEY_Q, 'Q' }, { SHIFT | KEY_R, 'R' }, { SHIFT | KEY_S, 'S' }, { SHIFT | KEY_T, 'T' }, { SHIFT | KEY_U, 'U' }, { SHIFT | KEY_V, 'V' }, { SHIFT | KEY_W, 'W' }, { SHIFT | KEY_X, 'X' }, { SHIFT | KEY_Y, 'Y' }, { SHIFT | KEY_Z, 'Z' }, { SHIFT | KEY_LEFTBRACE, '{' }, { SHIFT | KEY_RIGHTBRACE, '}' }, { SHIFT | KEY_SEMICOLON, ':' }, { SHIFT | KEY_APOSTROPHE, '"' }, { SHIFT | KEY_BACKSLASH, '|' }, { SHIFT | KEY_COMMA, '<' }, { SHIFT | KEY_DOT, '>' }, { SHIFT | KEY_SLASH, '?' }, { KEY_SPACE, ' ' }, { KEY_TAB, '\t' }, { KEY_ENTER, '\n' }, { 0, 0 } }; int from, to; void sigcatch (int sig) { if (sig == SIGINT || sig == SIGTERM) { ioctl (from, EVIOCGRAB, NULL); ioctl (to, UI_DEV_DESTROY); close (from); close (to); exit (EXIT_SUCCESS); } } int main (int argc, char ** argv) { int i, enabled = 0, shift = 0; ssize_t rd; struct input_event ev[64]; char * data = NULL; off_t datalen = 0; off_t position = 0; struct uinput_user_dev ud; struct timespec now, lastF12, lastF11; int lF12 = 0, lF11 = 0; signal (SIGTERM, sigcatch); signal (SIGINT, sigcatch); if (argc < 3) { fprintf (stderr, "usage: %s \n\n", basename (argv[0])); exit (1); } usleep (100000); from = open (argv[1], O_RDONLY); if (from < 0) { fprintf (stderr, "cannot open %s: %s\n", argv[1], strerror (errno)); exit (1); } if (ioctl (from, EVIOCGRAB, (void *) 1) < 0) { close (from); fprintf (stderr, "cannot grab %s: %s\n", argv[1], strerror (errno)); exit (1); } to = open ("/dev/input/uinput", O_WRONLY | O_NONBLOCK); if (to < 0 && errno == ENOENT) { fprintf (stderr, "/dev/input/uinput does not exists, trying modprobe uinput\n", strerror (errno)); system ("modprobe uinput"); sleep (1); to = open ("/dev/input/uinput", O_WRONLY | O_NONBLOCK); } if (to < 0) { close (from); fprintf (stderr, "cannot open /dev/input/uinput: %s\n", strerror (errno)); exit (1); } ioctl (to, UI_SET_EVBIT, EV_SYN); ioctl (to, UI_SET_EVBIT, EV_KEY); for (i = 0; i < KEY_MAX; i++) ioctl (to, UI_SET_KEYBIT, i); memset ((void *) &ud, 0, sizeof (ud)); strcpy (ud.name, "kabel keys"); ud.id.version = 4; ud.id.bustype = BUS_PCI; write (to, (char *) &ud, sizeof (ud)); ioctl (to, UI_DEV_CREATE); printf ("started\n"); while (1) { rd = read (from, (char *) ev, sizeof (struct input_event) * 64); for (i = 0; i < rd / sizeof (struct input_event); i++) { if (ev[i].type == EV_KEY) { if (ev[i].code == KEY_F11) { if (ev[i].value == 1) { clock_gettime (CLOCK_MONOTONIC, &lastF11); lF11 = 1; } else if (lF11) { struct timespec diff; clock_gettime (CLOCK_MONOTONIC, &now); diff.tv_sec = now.tv_sec - lastF11.tv_sec; diff.tv_nsec = now.tv_nsec - lastF11.tv_nsec; if (diff.tv_nsec < 0) { diff.tv_sec --; diff.tv_nsec += 1000000000; } if (diff.tv_sec >= 5) raise (SIGTERM); } } else if (ev[i].code == KEY_F12) { int changestate = 0; if (ev[i].value == 1) { clock_gettime (CLOCK_MONOTONIC, &lastF12); lF12 = 1; } else if (lF12) { struct timespec diff; clock_gettime (CLOCK_MONOTONIC, &now); diff.tv_sec = now.tv_sec - lastF12.tv_sec; diff.tv_nsec = now.tv_nsec - lastF12.tv_nsec; if (diff.tv_nsec < 0) { diff.tv_sec --; diff.tv_nsec += 1000000000; } if (diff.tv_sec >= 3) { changestate = 1; lF12 = 0; } } if (changestate) { if (!enabled) { struct stat st; int fd; fd = open (argv[2], O_RDONLY); if (fd < 0) { fprintf (stderr, "can not open %s for reading\n", argv[2]); continue; } stat (argv[2], &st); data = malloc (st.st_size); read (fd, data, st.st_size); datalen = st.st_size; position = 0; close (fd); printf ("faking enabled with %u bytes of data\n", datalen); enabled = 1; } else { free (data); data = NULL; datalen = 0; position = 0; printf ("faking disabled\n"); enabled = 0; } } continue; } else if (enabled && position < datalen) { int j; for (j = 0; keys[j].keycode != 0; j++) if (ev[i].code == (keys[j].keycode & ~SHIFT)) break; if ((keys[j].keycode & ~SHIFT) != 0) { int k; for (k = 0; keys[k].keycode != 0; k++) if (data[position] == keys[k].ch) break; if (keys[j].ch != 0) { if (ev[i].value == 1) { struct input_event tev[4]; int l, shifted; tev[0].time = ev[i].time; tev[0].type = EV_KEY; tev[0].code = KEY_LEFTSHIFT; tev[0].value = 1; tev[1].time = ev[i].time; tev[1].time.tv_usec += 3000; if (tev[1].time.tv_usec > 1000000) { tev[1].time.tv_sec += 1; tev[1].time.tv_usec %= 1000000; } tev[1].type = EV_KEY; tev[1].code = keys[k].keycode & ~SHIFT; tev[1].value = 1; tev[2].time = ev[i].time; tev[2].time.tv_usec += 6000; if (tev[2].time.tv_usec > 1000000) { tev[2].time.tv_sec += 1; tev[2].time.tv_usec %= 1000000; } tev[2].type = EV_KEY; tev[2].code = keys[k].keycode & ~SHIFT; tev[2].value = 0; tev[3].time = ev[i].time; tev[3].time.tv_usec += 9000; if (tev[3].time.tv_usec > 1000000) { tev[3].time.tv_sec += 1; tev[3].time.tv_usec %= 1000000; } tev[3].type = EV_KEY; tev[3].code = KEY_LEFTSHIFT; tev[3].value = 0; shifted = keys[k].keycode & SHIFT; struct input_event sev; sev.type = EV_SYN; sev.code = 0; sev.value = 0; for (l = shifted ? 0 : 1; l < (shifted ? 4 : 3); l++) { write (to, (char *) &tev[l], sizeof (struct input_event)); sev.time = tev[l].time; sev.time.tv_usec += 3; if (sev.time.tv_usec >= 1000000) { sev.time.tv_sec += 1; sev.time.tv_usec %= 1000000; } write (to, (char *) &sev, sizeof (struct input_event)); } position++; } } else goto other; } else goto other; } else { other: if (!enabled || (enabled && ev[i].code != KEY_LEFTSHIFT && ev[i].code != KEY_RIGHTSHIFT && ev[i].code != KEY_CAPSLOCK)) write (to, (char *) &ev[i], sizeof (struct input_event)); if (enabled && ev[i].code == KEY_BACKSPACE && ev[i].value && position > 0) position --; } } else if (ev[i].type == EV_SYN) write (to, (char *) &ev[i], sizeof (struct input_event)); } } }