Blob Blame Raw

#include "app.h"

#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>


int inputInit(Input *in, App *app) {
  LOGDBG("input: init");
  
  in->app = app;
  in->mappedKeyCode = 0;
  in->mappedPressed = 0;
  
  LOGDBG("input: init: connect to X11");
  in->dpy = XOpenDisplay(NULL);
  if (!in->dpy)
    return LOGERR("input: init: cannot connect to X11");
  
  LOGDBG("input: init: search free keycode for temporary mappings");
  int kk = 0, kc0 = 0, kc1 = 0;
  XDisplayKeycodes(in->dpy, &kc0, &kc1);
  KeySym *ks = XGetKeyboardMapping(in->dpy, kc0, kc1 - kc0 + 1, &kk);
  for(int kc = kc0; kc <= kc1; ++kc) {
    int found = 1;
    for(int i = 0; i < kk; ++i, ++ks)
      if (ks[kc*kk + i]) { found = 0; break; }
    if (found)
      { in->mappedKeyCode = kc; break; }
  }
  
  return 1;

  LOGDBG("input: init: found keycode %d", in->mappedKeyCode);
  if (!in->mappedKeyCode)
    LOGWRN("input: init: cannot found free keycode for temporary mappings, some keys may not work");
  
  return 1;
}


void inputDeinit(Input *in) {
  LOGDBG("input: deinit");
  XCloseDisplay(in->dpy);
}


void inputEvent(Input *in, unsigned int keySym, int press) {
  LOGDBG("input: event: keySym=%u press=%d", keySym, press);
  
  KeyCode keycode = XKeysymToKeycode(in->dpy, keySym);
  
  if (!keycode) {
    if (!in->mappedKeyCode) {
      LOGWRN("input: event: no keycode mapped to keySym[%u], and no free keycodes for temporary mapping", keySym);
      return;
    }
    
    keycode = in->mappedKeyCode;
    LOGDBG("input: event: temporary remap: keySym[%u] -> keycode[%hhu]", keySym, keycode);
    
    if (in->mappedPressed) {
      LOGWRN("input: event: temporary remap: mapped keys collision, release previously mapped key");
      XTestFakeKeyEvent(in->dpy, keycode, False, CurrentTime);
      XSync(in->dpy, False);
    }
    
    KeySym ks[2];
    XConvertCase(keySym, &ks[0], &ks[1]);
    LOGDBG("input: event: temporary remap: keySym[%u] -> keySyms[%lu, %lu]", keySym, ks[0], ks[1]);
    XChangeKeyboardMapping(in->dpy, keycode, ks[0] == ks[1] ? 1 : 2, ks, 1);
    XSync(in->dpy, False);
  }
  
  if (keycode == in->mappedKeyCode)
    in->mappedPressed = press;
  
  LOGDBG("input: event: keycode=%hhu press=%d", keycode, press);
  XTestFakeKeyEvent(in->dpy, keycode, press, CurrentTime);
  XSync(in->dpy, False);
}