#include #include #include #include #include #include #include #include #include #include // Interval in seconds between reminders (default 20 minutes), // can be overridden with -i (supports optional s/m suffix). static unsigned long long interval_seconds = 20ULL * 60ULL; // Shared timestamp of when the "standing" event last occurred. static unsigned long long last_time_standing = 0; // Map a subset of key codes (digits and Enter) to characters. static char keycode_to_char(unsigned short code) { switch (code) { case KEY_0: return '0'; case KEY_1: return '1'; case KEY_2: return '2'; case KEY_3: return '3'; case KEY_4: return '4'; case KEY_5: return '5'; case KEY_6: return '6'; case KEY_7: return '7'; case KEY_8: return '8'; case KEY_9: return '9'; default: return '\0'; } } // Thread that once per second prints how long it has been since // last_time_standing was updated. static void *time_watcher_thread(void *arg) { (void)arg; for (;;) { sleep(1); unsigned long long now = (unsigned long long)time(NULL); if (last_time_standing != 0) { unsigned long long delta = now - last_time_standing; printf("Seconds since last_time_standing: %llu (interval=%llus)\n", delta, interval_seconds); fflush(stdout); // If we've exceeded the configured interval, lock the screen if (delta >= interval_seconds) { // Use xinput to disable all keyboard-like devices until user stands again. // This pipeline lists input devices, filters keyboards (excluding XTEST), // extracts their IDs, and disables each one. system("xinput --list --short | " "grep -i 'keyboard' | grep -v 'XTEST' | " "sed -E 's/.*id=([0-9]+).*/\\1/' | " "xargs -r -n1 xinput disable"); system("i3lock -n -i /usr/local/share/lockscreens/standing_gopher.png"); } } } return NULL; } int main(int argc, char **argv) { // Replace with the specific event node for your keyboard // Use 'lsusb' and 'cat /proc/bus/input/devices' to find the right one const char *dev = "/dev/input/by-id/usb-IC_Reader_IC_Reader_08FF20171101-event-kbd"; struct input_event ev; int fd; // Optional: -i [s|m] to override interval_seconds int opt; while ((opt = getopt(argc, argv, "i:")) != -1) { switch (opt) { case 'i': { char *end = NULL; unsigned long long v = strtoull(optarg, &end, 10); if (!optarg[0] || end == optarg || v == 0) { fprintf(stderr, "Invalid interval '%s' for -i (must start with positive integer)\n", optarg); return EXIT_FAILURE; } char unit = 'm'; // default unit: minutes if (*end != '\0') { // Allow a single unit character 's' or 'm' if (end[1] != '\0') { fprintf(stderr, "Invalid interval suffix in '%s' (use optional 's' or 'm')\n", optarg); return EXIT_FAILURE; } unit = (char)tolower((unsigned char)*end); if (unit != 's' && unit != 'm') { fprintf(stderr, "Unknown interval unit '%c' in '%s' (use 's' or 'm')\n", *end, optarg); return EXIT_FAILURE; } } if (unit == 's') { interval_seconds = v; } else { // 'm' interval_seconds = v * 60ULL; } break; } default: fprintf(stderr, "Usage: %s [-i interval{s|m}]\n", argv[0]); return EXIT_FAILURE; } } fd = open(dev, O_RDONLY); if (fd == -1) { perror("Cannot open device"); return EXIT_FAILURE; } // Grab the device: This blocks all other apps from seeing these keystrokes if (ioctl(fd, EVIOCGRAB, 1) == -1) { perror("Could not grab device"); close(fd); return EXIT_FAILURE; } printf("Input blocked from %s. Press Ctrl+C in this terminal to stop.\n", dev); // Buffer to accumulate the characters the reader "types" char buf_str[128]; size_t buf_len = 0; // Initialize last_time_standing and start the watcher thread last_time_standing = (unsigned long long)time(NULL); pthread_t watcher; if (pthread_create(&watcher, NULL, time_watcher_thread, NULL) != 0) { perror("Failed to create watcher thread"); ioctl(fd, EVIOCGRAB, 0); close(fd); return EXIT_FAILURE; } pthread_detach(watcher); // Continuous loop to capture events while (1) { ssize_t n = read(fd, &ev, sizeof(ev)); if (n == (ssize_t)-1) { perror("Read error"); break; } else if (n != sizeof(ev)) { continue; } // Process only key events (type 1) if (ev.type == EV_KEY) { if (ev.value == 1) { // key press if (ev.code == KEY_ENTER || ev.code == KEY_KPENTER) { // End of the "typed" sequence: print the accumulated string if (buf_len > 0) { buf_str[buf_len] = '\0'; long long val = strtoll(buf_str, NULL, 10); // Get the SHA-256 hash of the value unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char*)buf_str, buf_len, hash); printf("SHA-256: "); unsigned long long hash_val = 0; for (int i = 0; i < 8; i++) { hash_val = (hash_val << 8) | hash[i]; } printf(" (as number: %llu)", hash_val); printf("\n"); printf("Typed: %s (as number: %lld)\n", buf_str, val); buf_len = 0; if (hash_val == 4798061567229363866L) { last_time_standing = (unsigned long long)time(NULL); printf("Desk reminder timer reset at %llu seconds since epoch.\n", last_time_standing); system("pkill i3lock"); system("xinput --list --short | " "grep -i 'keyboard' | grep -v 'XTEST' | " "sed -E 's/.*id=([0-9]+).*/\\1/' | " "xargs -r -n1 xinput enable"); } } } else { char c = keycode_to_char(ev.code); if (c != '\0' && buf_len + 1 < sizeof(buf_str)) buf_str[buf_len++] = c; } } } } // Release the grab before exiting ioctl(fd, EVIOCGRAB, 0); close(fd); return 0; }