/* 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));
}
}
}