203 lines
8.3 KiB
C
Raw Normal View History

/*
Written by retoor@molodetz.nl
This program captures keyboard input events, resolves device names, and logs these events into a specified database.
Includes:
- sormc.h: Custom library file for database management.
MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
2024-12-08 18:33:45 +00:00
#include "sormc.h"
#include <fcntl.h>
#include <linux/input.h>
2024-12-08 15:19:17 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
2024-12-08 18:33:45 +00:00
#include <unistd.h>
2024-12-08 15:19:17 +00:00
#define DATABASE_NAME "tikker.db"
#define DEVICE_TO_READ_DEFAULT "keyboard"
2024-12-08 15:19:17 +00:00
#define MAX_DEVICES 32
#define DEVICE_PATH "/dev/input/event"
2024-12-16 11:48:00 +00:00
const char *keycode_to_char[] = {
[2] = "1", [3] = "2", [4] = "3", [5] = "4", [6] = "5",
[7] = "6", [8] = "7", [9] = "8", [10] = "9", [11] = "0",
2024-12-16 13:54:01 +00:00
[12] = "-", [13] = "=", [14] = "[BACKSPACE]", [15] = "[TAB]",
2024-12-16 11:48:00 +00:00
[16] = "Q", [17] = "W", [18] = "E", [19] = "R", [20] = "T",
[21] = "Y", [22] = "U", [23] = "I", [24] = "O", [25] = "P",
2024-12-16 13:54:01 +00:00
[26] = "[", [27] = "]", [28] = "[ENTER]\n", [29] = "[LEFT_CTRL]",
2024-12-16 11:48:00 +00:00
[30] = "A", [31] = "S", [32] = "D", [33] = "F", [34] = "G",
[35] = "H", [36] = "J", [37] = "K", [38] = "L", [39] = ";",
2024-12-16 13:54:01 +00:00
[40] = "'", [41] = "`", [42] = "[LEFT_SHIFT]", [43] = "\\",
2024-12-16 11:48:00 +00:00
[44] = "Z", [45] = "X", [46] = "C", [47] = "V", [48] = "B",
[49] = "N", [50] = "M", [51] = ",", [52] = ".", [53] = "/",
2024-12-16 13:54:01 +00:00
[54] = "[RIGHT_SHIFT]", [55] = "[KEYPAD_*]", [56] = "[LEFT_ALT]",
[57] = " ", [58] = "[CAPSLOCK]",
[59] = "[F1]", [60] = "[F2]", [61] = "[F3]", [62] = "[F4]",
[63] = "[F5]", [64] = "[F6]", [65] = "[F7]", [66] = "[F8]",
[67] = "[F9]", [68] = "[F10]", [87] = "[F11]", [88] = "[F12]",
[69] = "[NUMLOCK]", [70] = "[SCROLLLOCK]", [71] = "[KEYPAD_7]",
[72] = "[KEYPAD_8]", [73] = "[KEYPAD_9]", [74] = "[KEYPAD_-]",
[75] = "[KEYPAD_4]", [76] = "[KEYPAD_5]", [77] = "[KEYPAD_6]",
[78] = "[KEYPAD_+]", [79] = "[KEYPAD_1]", [80] = "[KEYPAD_2]",
[81] = "[KEYPAD_3]", [82] = "[KEYPAD_0]", [83] = "[KEYPAD_.]",
2024-12-16 13:54:01 +00:00
[86] = "<", [100] = "[RIGHT_ALT]", [97] = "[RIGHT_CTRL]",
[119] = "[PAUSE]", [120] = "[SYSRQ]", [121] = "[BREAK]",
[102] = "[HOME]", [103] = "[UP]", [104] = "[PAGEUP]",
[105] = "[LEFT]", [106] = "[RIGHT]", [107] = "[END]",
[108] = "[DOWN]", [109] = "[PAGEDOWN]", [110] = "[INSERT]",
[111] = "[DELETE]",
[113] = "[MUTE]", [114] = "[VOLUME_DOWN]", [115] = "[VOLUME_UP]",
[163] = "[MEDIA_NEXT]", [165] = "[MEDIA_PREV]", [164] = "[MEDIA_PLAY_PAUSE]"
2024-12-16 11:48:00 +00:00
};
char *resolve_device_name(int fd) {
static char device_name[256];
device_name[0] = 0;
2024-12-08 15:19:17 +00:00
if (ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0) {
return 0;
}
return device_name;
2024-12-08 15:19:17 +00:00
}
2025-01-06 23:53:41 +00:00
char * sormgetc(char *result,int index){
char * end = NULL;
int current_index = 0;
while((end = strstr((char *)result, ";")) != NULL){
if(index == current_index){
result[end - (char *)result] = 0;
return result;
}
result = end + 1;
current_index++;
}
*end = 0;
return result;
}
int main(int argc, char *argv[]) {
char *device_to_read = rargs_get_option_string(argc, argv, "--device", DEVICE_TO_READ_DEFAULT);
2025-01-06 23:53:41 +00:00
//printf("%s\n", device_to_read);
int db = sormc(DATABASE_NAME);
2024-12-08 18:33:01 +00:00
ulonglong times_repeated = 0;
ulonglong times_pressed = 0;
ulonglong times_released = 0;
2024-12-16 11:48:00 +00:00
sormq(db, "CREATE TABLE IF NOT EXISTS kevent (id INTEGER PRIMARY KEY AUTOINCREMENT, code,event,name,timestamp,char)");
2025-01-06 23:53:41 +00:00
if(argc > 1 && !strcmp(argv[1],"presses_today")){
time_t now = time(NULL);
char time_string[32];
strftime(time_string, sizeof(time_string), "%Y-%m-%d", localtime(&now));
sorm_ptr result = sormq(db, "SELECT COUNT(id) as total FROM kevent WHERE timestamp >= %s AND event = 'PRESSED'",time_string);
printf("%s",sormgetc((char *)result,1));
//fflush(stdout);
free(result);
exit(0);
}
2024-12-08 15:19:17 +00:00
int keyboard_fds[MAX_DEVICES];
int num_keyboards = 0;
2024-12-08 18:33:45 +00:00
2024-12-08 15:19:17 +00:00
for (int i = 0; i < MAX_DEVICES; i++) {
char device_path[32];
snprintf(device_path, sizeof(device_path), "%s%d", DEVICE_PATH, i);
int fd = open(device_path, O_RDONLY);
if (fd < 0) {
continue;
}
char *device_name = resolve_device_name(fd);
if (!device_name) {
close(fd);
continue;
}
bool is_device_to_read = strstr(device_name, device_to_read) != NULL;
printf("[%s] %s. Mount: %s.\n", is_device_to_read ? "-" : "+", device_name, device_path);
if (is_device_to_read) {
2024-12-08 15:19:17 +00:00
keyboard_fds[num_keyboards++] = fd;
} else {
close(fd);
}
}
if (num_keyboards == 0) {
fprintf(stderr, "No keyboard found. Are you running as root?\n"
"If your device is listed above with a minus [-] in front, \n"
"run this application using --device='[DEVICE_NAME]'\n");
2024-12-08 15:19:17 +00:00
return 1;
}
printf("Monitoring %d keyboards.\n", num_keyboards);
struct input_event ev;
fd_set read_fds;
2024-12-08 18:33:45 +00:00
2024-12-08 15:19:17 +00:00
while (1) {
FD_ZERO(&read_fds);
int max_fd = -1;
for (int i = 0; i < num_keyboards; i++) {
FD_SET(keyboard_fds[i], &read_fds);
if (keyboard_fds[i] > max_fd) {
max_fd = keyboard_fds[i];
}
}
if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0) {
perror("select error");
break;
}
for (int i = 0; i < num_keyboards; i++) {
if (FD_ISSET(keyboard_fds[i], &read_fds)) {
ssize_t bytes = read(keyboard_fds[i], &ev, sizeof(struct input_event));
if (bytes == sizeof(struct input_event)) {
if (ev.type == EV_KEY) {
char *char_name = NULL;
2024-12-16 11:48:00 +00:00
if (ev.code < sizeof(keycode_to_char) / sizeof(keycode_to_char[0])) {
2024-12-16 13:54:01 +00:00
char_name = (char *)keycode_to_char[ev.code];
2024-12-16 11:48:00 +00:00
}
char keyboard_name[256];
ioctl(keyboard_fds[i], EVIOCGNAME(sizeof(keyboard_name)), keyboard_name);
printf("Keyboard: %s, ", keyboard_name);
2024-12-08 18:33:45 +00:00
char *event_name = NULL;
if (ev.value == 1) {
2024-12-08 15:19:17 +00:00
event_name = "PRESSED";
2024-12-08 18:33:01 +00:00
times_pressed++;
2024-12-08 18:33:45 +00:00
} else if (ev.value == 0) {
2024-12-08 15:19:17 +00:00
event_name = "RELEASED";
2024-12-08 18:33:01 +00:00
times_released++;
2024-12-08 18:33:45 +00:00
} else {
2024-12-08 15:19:17 +00:00
event_name = "REPEATED";
2024-12-08 18:33:01 +00:00
times_repeated++;
2024-12-08 15:19:17 +00:00
}
2024-12-16 11:48:00 +00:00
sormq(db, "INSERT INTO kevent (code, event, name,timestamp,char) VALUES (%d, %s, %s, DATETIME('now'),%s)", ev.code,
event_name, keyboard_name, char_name);
2024-12-08 18:33:45 +00:00
printf("Event: %s, ", ev.value == 1 ? "PRESSED" : ev.value == 0 ? "RELEASED" : "REPEATED");
2024-12-16 11:48:00 +00:00
printf("Key Code: %d, ", ev.code);
printf("Name: %s, ", char_name);
2024-12-08 18:33:45 +00:00
printf("Pr: %lld Rel: %lld Rep: %lld\n", times_pressed, times_released, times_repeated);
2024-12-08 15:19:17 +00:00
}
}
}
}
}
for (int i = 0; i < num_keyboards; i++) {
close(keyboard_fds[i]);
}
return 0;
}