morse

Morse interpreter using X key events
git clone https://git.sinitax.com/sinitax/morse
Log | Files | Refs | LICENSE | sfeed.txt

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}