morse

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

commit 00f06c0f2ecfad3c26b8a3e3ea1114908a6dc8d0
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon,  3 Oct 2022 01:49:49 +0200

Initial prototype

Diffstat:
A.gitignore | 1+
AMakefile | 10++++++++++
Alut.c | 40++++++++++++++++++++++++++++++++++++++++
Amorse.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 172 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +morse diff --git a/Makefile b/Makefile @@ -0,0 +1,10 @@ +LDLIBS = -lX11 + +all: morse + +clean: + rm -f morse + +morse: morse.c + +.PHONY: all clean diff --git a/lut.c b/lut.c @@ -0,0 +1,40 @@ +static const char *morse_lut[] = { + "A" ".-", + "B" "-...", + "C" "-.-.", + "D" "-..", + "E" ".", + "F" "..-.", + "G" "--.", + "H" "....", + "I" "..", + "J" ".---", + "K" "-.-", + "L" ".-..", + "M" "--", + "N" "-.", + "O" "---", + "P" ".--.", + "Q" "--.-", + "R" ".-.", + "S" "...", + "T" "-", + "U" "..-", + "V" "...-", + "W" ".--", + "X" "-..-", + "Y" "-.--", + "Z" "--..", + "1" ".----", + "2" "..---", + "3" "...--", + "4" "....-", + "5" ".....", + "6" "-....", + "7" "--...", + "8" "---..", + "9" "----.", + "0" "-----" +}; + + diff --git a/morse.c b/morse.c @@ -0,0 +1,121 @@ +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include <time.h> +#include <unistd.h> +#include <time.h> +#include <err.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#include "lut.c" + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) + +static char translate(const char *seq); + +static const int long_ms = 300; +static const int letter_ms = 1000; + +static char seqbuf[64]; +static int seqlen; + +char +translate(const char *seq) +{ + int i; + + for (i = 0; i < ARRLEN(morse_lut); i++) { + if (!strcmp(seq, morse_lut[i] + 1)) + return morse_lut[i][0]; + } + + return '?'; +} + +int +main(int argc, const char **argv) +{ + struct timespec press, release; + unsigned long diff_ms; + bool is_pressed; + int timeout_cnt; + Display *display; + XEvent event; + Window root; + int sleep_cnt; + int x11fd; + int ret; + + setvbuf(stdout, NULL, _IONBF, 0); + + display = XOpenDisplay(NULL); + if (!display) errx(1, "No display found"); + + root = DefaultRootWindow(display); + XGrabKey(display, XKeysymToKeycode(display, 'n'), 0, root, + False, GrabModeAsync, GrabModeAsync); + + memset(&press, 0, sizeof(struct timespec)); + memset(&release, 0, sizeof(struct timespec)); + + seqlen = 0; + seqbuf[seqlen] = '\0'; + + x11fd = XConnectionNumber(display); + + timeout_cnt = 10; + is_pressed = false; + while (true) { + /* inaccurate and hacky but select() + * with XGrabKey is not working */ + sleep_cnt = 0; + while (!XPending(display) && sleep_cnt < letter_ms) { + usleep(1000); + sleep_cnt++; + } + + if (!XPending(display)) { + if (!is_pressed) { + timeout_cnt++; + if (timeout_cnt == 1) { + putchar(translate(seqbuf)); + seqlen = 0; + seqbuf[seqlen] = '\0'; + } + if (timeout_cnt == 2) + putchar(' '); + } + continue; + } else { + timeout_cnt = 0; + } + + XNextEvent(display, &event); + if (event.type == KeyPress && !is_pressed) { + is_pressed = true; + if (clock_gettime(CLOCK_REALTIME, &press)) + err(1, "clock_gettime"); + } else if (event.type == KeyRelease && is_pressed) { + is_pressed = false; + if (clock_gettime(CLOCK_REALTIME, &release)) + err(1, "clock_gettime"); + if (press.tv_sec == 0) continue; + diff_ms = (release.tv_sec - press.tv_sec) * 1000 + + (release.tv_nsec - press.tv_nsec) / 1000000; + if (seqlen >= sizeof(seqbuf) - 1) + continue; + if (diff_ms > long_ms) { + seqbuf[seqlen++] = '-'; + } else { + seqbuf[seqlen++] = '.'; + } + seqbuf[seqlen] = '\0'; + } + } + + XCloseDisplay(display); +}