From cc8068f8ab1ed95905fc310899cf1438459e06dc Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Fri, 23 Oct 2020 21:14:25 -0400 Subject: [PATCH] emul: don't hardcode X11 keycodes in key handling routines I thought it wasn't possible with XCB to transform keycodes into symbols for the current keyboard mapping, but I hadn't looked hard enough. --- emul/hw/sms/sms.c | 77 +++++++++++++++++------------ emul/hw/ti/ti84.c | 120 +++++++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 86 deletions(-) diff --git a/emul/hw/sms/sms.c b/emul/hw/sms/sms.c index 7bce0f5..adc9d18 100644 --- a/emul/hw/sms/sms.c +++ b/emul/hw/sms/sms.c @@ -4,6 +4,8 @@ #include #include +#define XK_MISCELLANY +#include #include "../../emul.h" #include "vdp.h" @@ -153,6 +155,48 @@ void draw_pixels() xcb_flush(conn); } +// Returns true to exist event loop +static bool _handle_keypress(xcb_generic_event_t *e) +{ + xcb_key_press_event_t *ev = (xcb_key_press_event_t *)e; + bool ispressed = e->response_type == XCB_KEY_PRESS; + // change keycode into symbol + xcb_get_keyboard_mapping_reply_t* km = xcb_get_keyboard_mapping_reply( + conn, xcb_get_keyboard_mapping(conn, ev->detail, 1), NULL); + if (km->length) { + xcb_keysym_t* keysyms = (xcb_keysym_t*)(km + 1); + switch (keysyms[0]) { + case XK_Escape: free(km); return true; + case 'w': + pad_setbtn(&pad, PAD_BTN_UP, ispressed); + break; + case 'a': + pad_setbtn(&pad, PAD_BTN_LEFT, ispressed); + break; + case 's': + pad_setbtn(&pad, PAD_BTN_DOWN, ispressed); + break; + case 'd': + pad_setbtn(&pad, PAD_BTN_RIGHT, ispressed); + break; + case 'h': + pad_setbtn(&pad, PAD_BTN_A, ispressed); + break; + case 'j': + pad_setbtn(&pad, PAD_BTN_B, ispressed); + break; + case 'k': + pad_setbtn(&pad, PAD_BTN_C, ispressed); + break; + case 'l': + pad_setbtn(&pad, PAD_BTN_START, ispressed); + break; + } + } + free(km); + return false; +} + void event_loop() { while (1) { @@ -183,38 +227,9 @@ void event_loop() switch (e->response_type & ~0x80) { /* ESC to exit */ case XCB_KEY_RELEASE: - case XCB_KEY_PRESS: { - xcb_key_press_event_t *ev = (xcb_key_press_event_t *)e; - bool ispressed = e->response_type == XCB_KEY_PRESS; - switch (ev->detail) { - case 0x09: return; // ESC - case 0x19: // W - pad_setbtn(&pad, PAD_BTN_UP, ispressed); - break; - case 0x26: // A - pad_setbtn(&pad, PAD_BTN_LEFT, ispressed); - break; - case 0x27: // S - pad_setbtn(&pad, PAD_BTN_DOWN, ispressed); - break; - case 0x28: // D - pad_setbtn(&pad, PAD_BTN_RIGHT, ispressed); - break; - case 0x2b: // H - pad_setbtn(&pad, PAD_BTN_A, ispressed); - break; - case 0x2c: // J - pad_setbtn(&pad, PAD_BTN_B, ispressed); - break; - case 0x2d: // K - pad_setbtn(&pad, PAD_BTN_C, ispressed); - break; - case 0x2e: // L - pad_setbtn(&pad, PAD_BTN_START, ispressed); - break; - } + case XCB_KEY_PRESS: + if (_handle_keypress(e)) return; break; - } case XCB_EXPOSE: { draw_pixels(); break; diff --git a/emul/hw/ti/ti84.c b/emul/hw/ti/ti84.c index af88a28..cf4e791 100644 --- a/emul/hw/ti/ti84.c +++ b/emul/hw/ti/ti84.c @@ -11,6 +11,8 @@ #include #include +#define XK_MISCELLANY +#include #include "../../emul.h" #include "t6a04.h" @@ -83,64 +85,72 @@ static void iowr_interrupt(uint8_t val) } } -// TIL: XCB doesn't have a builtin way to translate a keycode to an ASCII char. -// Using Xlib looks complicated. This will probably not work in many cases (non -// query keyboards and all...), but for now, let's go with this. static uint8_t keycode_to_tikbd(xcb_keycode_t kc) { - switch (kc) { - case 0x0a: return 0x41; // 1 - case 0x0b: return 0x31; // 2 - case 0x0c: return 0x21; // 3 - case 0x0d: return 0x42; // 4 - case 0x0e: return 0x32; // 5 - case 0x0f: return 0x22; // 6 - case 0x10: return 0x43; // 7 - case 0x11: return 0x33; // 8 - case 0x12: return 0x23; // 9 - case 0x13: return 0x40; // 0 - case 0x14: return 0x12; // - - case 0x15: return 0x11; // + - case 0x16: return 0x67; // DEL - case 0x18: return 0x23; // Q - case 0x19: return 0x12; // W - case 0x1a: return 0x45; // E - case 0x1b: return 0x13; // R - case 0x1c: return 0x42; // T - case 0x1d: return 0x41; // Y - case 0x1e: return 0x32; // U - case 0x1f: return 0x54; // I - case 0x20: return 0x43; // O - case 0x21: return 0x33; // P - case 0x22: return 0x34; // ( - case 0x23: return 0x24; // ) - case 0x24: return 0x10; // Return - case 0x25: return KBD_ALPHA; // LCTRL - case 0x26: return 0x56; // A - case 0x27: return 0x52; // S - case 0x28: return 0x55; // D - case 0x29: return 0x35; // F - case 0x2a: return 0x25; // G - case 0x2b: return 0x15; // H - case 0x2c: return 0x44; // J - case 0x2d: return 0x34; // K - case 0x2e: return 0x24; // L - case 0x2f: return 0x30; // : - case 0x30: return 0x11; // " - case 0x32: return KBD_2ND; // Lshift - case 0x34: return 0x31; // Z - case 0x35: return 0x51; // X - case 0x36: return 0x36; // C - case 0x37: return 0x22; // V - case 0x38: return 0x46; // B - case 0x39: return 0x53; // N - case 0x3a: return 0x14; // M - case 0x3b: return 0x44; // , - case 0x3c: return 0x30; // . - case 0x3d: return 0x20; // ? - case 0x41: return 0x40; // Space - default: return 0; + // First, change keycode into symbol + xcb_get_keyboard_mapping_reply_t* km = xcb_get_keyboard_mapping_reply( + conn, xcb_get_keyboard_mapping(conn, kc, 1), NULL); + xcb_keysym_t* keysyms = (xcb_keysym_t*)(km + 1); + uint8_t res = 0; + for (int i=0; ilength; i++) { + switch (keysyms[0]) { + case XK_Shift_L: res = KBD_2ND; break; + case XK_Control_L: res = KBD_ALPHA; break; + case XK_Return: res = 0x10; break; + case XK_Delete: res = 0x67; break; + case ' ': res = 0x40; break; + case '1': res = 0x41; break; + case '2': res = 0x31; break; + case '3': res = 0x21; break; + case '4': res = 0x42; break; + case '5': res = 0x32; break; + case '6': res = 0x22; break; + case '7': res = 0x43; break; + case '8': res = 0x33; break; + case '9': res = 0x23; break; + case '0': res = 0x40; break; + case '-': res = 0x12; break; + case '+': res = 0x11; break; + case 'q': res = 0x23; break; + case 'w': res = 0x12; break; + case 'e': res = 0x45; break; + case 'r': res = 0x13; break; + case 't': res = 0x42; break; + case 'y': res = 0x41; break; + case 'u': res = 0x32; break; + case 'i': res = 0x54; break; + case 'o': res = 0x43; break; + case 'p': res = 0x33; break; + case '(': res = 0x34; break; + case ')': res = 0x24; break; + case 'a': res = 0x56; break; + case 's': res = 0x52; break; + case 'd': res = 0x55; break; + case 'f': res = 0x35; break; + case 'g': res = 0x25; break; + case 'h': res = 0x15; break; + case 'j': res = 0x44; break; + case 'k': res = 0x34; break; + case 'l': res = 0x24; break; + case ':': res = 0x30; break; + case '"': res = 0x11; break; + case 'z': res = 0x31; break; + case 'x': res = 0x51; break; + case 'c': res = 0x36; break; + case 'v': res = 0x22; break; + case 'b': res = 0x46; break; + case 'n': res = 0x53; break; + case 'm': res = 0x14; break; + case ',': res = 0x44; break; + case '.': res = 0x30; break; + case '?': res = 0x20; break; + } + if (res) { + break; + } } + free(km); + return res; } void create_window()