Skip to content

Instantly share code, notes, and snippets.

@Maxdamantus
Last active October 20, 2019 08:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Maxdamantus/2f4677af369790b79f547a010bc7a522 to your computer and use it in GitHub Desktop.
Save Maxdamantus/2f4677af369790b79f547a010bc7a522 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <poll.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
const static int note_c3 = 48;
struct notes_map {
int last_press;
unsigned char notes[128];
};
static struct notes_map make_notes_map(void){
struct { int start_note; unsigned char key_codes[20]; } rows[] = {
{ note_c3 - 1, { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 } },
{ note_c3 - 0, { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51 } },
{ note_c3 + 1, { 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 36 } },
{ note_c3 + 2, { 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 99 } }
};
struct notes_map m = {0};
for (int y = 0; y < sizeof rows/sizeof *rows; y++){
for (int x = 0; x < sizeof rows[y].key_codes/sizeof *rows[y].key_codes; x++) {
unsigned char note = rows[y].start_note + x*3;
unsigned char key_code = rows[y].key_codes[x];
if (key_code >= sizeof m.notes) {
// it's almost a Mozart joke
fprintf(stderr, "Too many keys!\n");
exit(EXIT_FAILURE);
}
m.notes[key_code] = note;
}
}
return m;
}
static void handle_key(struct notes_map *m, unsigned int keycode, int state) {
if(state){
// ignore repeat
if(m->last_press == (int)keycode)
return;
m->last_press = keycode;
}else
m->last_press = -1;
if(keycode >= sizeof m->notes)
return;
int note = m->notes[keycode];
if(note == 0)
return;
printf("note%s 0 %i 127\n", state? "on" : "off", note);
fflush(stdout);
}
int main(void){
struct notes_map notes_map = make_notes_map();
Display *dpy;
Window rootwin, win;
XEvent e;
int scr;
GC gc;
int width = 800;
int height = 600;
if(!(dpy = XOpenDisplay(NULL))){
perror("XOpenDisplay");
return 1;
}
if(!XkbSetDetectableAutoRepeat(dpy, True, &(Bool){0})){
perror("XkbSetDetectableAutoRepeat");
return 1;
}
scr = DefaultScreen(dpy);
rootwin = RootWindow(dpy, scr);
win = XCreateSimpleWindow(dpy, rootwin, 0, 0, width, height, 1, BlackPixel(dpy, scr), BlackPixel(dpy, scr));
XStoreName(dpy, win, "Fluid Keys");
gc = XCreateGC(dpy, win, 0, NULL);
XSetForeground(dpy, gc, WhitePixel(dpy, scr));
XSetWMHints(dpy, win, &(XWMHints){ .input = True, .flags = InputHint });
XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask);
XMapWindow(dpy, win);
for(;;){
XNextEvent(dpy, &e);
switch(e.type){
case KeyPress:
case KeyRelease:
//printf("key%s: %u\n", e.type == KeyPress? "down" : "up", e.xkey.keycode);
handle_key(&notes_map, e.xkey.keycode, e.type == KeyPress);
break;
default:
fprintf(stderr, "type: %i\n", e.type);
}
}
XCloseDisplay(dpy);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment