morse.c (2453B)
1#include <X11/X.h> 2#include <X11/Xlib.h> 3#include <X11/keysym.h> 4 5#include <time.h> 6#include <unistd.h> 7#include <time.h> 8#include <err.h> 9#include <string.h> 10#include <stdbool.h> 11#include <stdlib.h> 12#include <stdio.h> 13 14#include "lut.c" 15 16#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) 17 18static char translate(const char *seq); 19 20static const int long_ms = 300; 21static const int letter_ms = 1000; 22 23static char seqbuf[64]; 24static int seqlen; 25 26char 27translate(const char *seq) 28{ 29 int i; 30 31 for (i = 0; i < ARRLEN(morse_lut); i++) { 32 if (!strcmp(seq, morse_lut[i] + 1)) 33 return morse_lut[i][0]; 34 } 35 36 return '?'; 37} 38 39int 40main(int argc, const char **argv) 41{ 42 struct timespec press, release; 43 unsigned long diff_ms; 44 bool is_pressed; 45 int timeout_cnt; 46 Display *display; 47 XEvent event; 48 Window root; 49 int sleep_cnt; 50 int x11fd; 51 int ret; 52 53 setvbuf(stdout, NULL, _IONBF, 0); 54 55 display = XOpenDisplay(NULL); 56 if (!display) errx(1, "No display found"); 57 58 root = DefaultRootWindow(display); 59 XGrabKey(display, XKeysymToKeycode(display, 'n'), 0, root, 60 False, GrabModeAsync, GrabModeAsync); 61 62 memset(&press, 0, sizeof(struct timespec)); 63 memset(&release, 0, sizeof(struct timespec)); 64 65 seqlen = 0; 66 seqbuf[seqlen] = '\0'; 67 68 x11fd = XConnectionNumber(display); 69 70 timeout_cnt = 10; 71 is_pressed = false; 72 while (true) { 73 /* inaccurate and hacky but select() 74 * with XGrabKey is not working */ 75 sleep_cnt = 0; 76 while (!XPending(display) && sleep_cnt < letter_ms) { 77 usleep(1000); 78 sleep_cnt++; 79 } 80 81 if (!XPending(display)) { 82 if (!is_pressed) { 83 timeout_cnt++; 84 if (timeout_cnt == 1) { 85 putchar(translate(seqbuf)); 86 seqlen = 0; 87 seqbuf[seqlen] = '\0'; 88 } 89 if (timeout_cnt == 2) 90 putchar(' '); 91 } 92 continue; 93 } else { 94 timeout_cnt = 0; 95 } 96 97 XNextEvent(display, &event); 98 if (event.type == KeyPress && !is_pressed) { 99 is_pressed = true; 100 if (clock_gettime(CLOCK_REALTIME, &press)) 101 err(1, "clock_gettime"); 102 } else if (event.type == KeyRelease && is_pressed) { 103 is_pressed = false; 104 if (clock_gettime(CLOCK_REALTIME, &release)) 105 err(1, "clock_gettime"); 106 if (press.tv_sec == 0) continue; 107 diff_ms = (release.tv_sec - press.tv_sec) * 1000 108 + (release.tv_nsec - press.tv_nsec) / 1000000; 109 if (seqlen >= sizeof(seqbuf) - 1) 110 continue; 111 if (diff_ms > long_ms) { 112 seqbuf[seqlen++] = '-'; 113 } else { 114 seqbuf[seqlen++] = '.'; 115 } 116 seqbuf[seqlen] = '\0'; 117 } 118 } 119 120 XCloseDisplay(display); 121}