Author | Jakob Wakeling <[email protected]> |
Date | 2024-03-10 06:35:51 |
Commit | ccd60e6699b2d7bee0da5001872d696de05ba521 |
Parent | 7fd7b2117f51ff042e2fc3f38c6fd00a7c3c005b |
Implement basic X11 windows, events, and drawing
Diffstat
A | src/draw.c | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/draw.h | | | 87 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/keys.h | | | 136 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/x11/draw.c | | | 204 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/x11/keys.c | | | 137 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 612 insertions, 0 deletions
diff --git a/src/draw.c b/src/draw.c new file mode 100644 index 0000000..f236fb5 --- /dev/null +++ b/src/draw.c @@ -0,0 +1,48 @@ +// Copyright (C) 2024, Jakob Wakeling +// All rights reserved. + +#include "draw.h" + +#include <stdlib.h> + +bool draw_debug = false; + +draw_buffer *draw_buffer_init(int32_t w, int32_t h) { + draw_buffer *buf = calloc(1, sizeof(draw_buffer)); if (buf == NULL) { return NULL; } + *buf = (draw_buffer){ .bounds = {0, 0, w, h}, .buf = malloc((w * h) * sizeof(uint32_t)) }; + if (buf->buf == NULL) { free(buf); return NULL; } return buf; +} + +void draw_buffer_free(draw_buffer **buf) { + free((*buf)->buf); free(*buf); *buf = NULL; +} + +void draw_buffer_copy(draw_buffer *dst, draw_buffer *src, point dp, rect sr) { + for (int32_t x = 0; x < dst->bounds.w && x < (src->bounds.w - src->bounds.x); x += 1) { + for (int32_t y = 0; y < dst->bounds.h && y < (src->bounds.h - src->bounds.y); y += 1) { + dst->buf[((y + dp.y) * dst->bounds.w) + (x + dp.x)] = src->buf[((y + sr.y) * src->bounds.w) + (x + sr.x)]; + } + } +} + +void draw_buffer_clear(draw_buffer *buf, uint32_t colour) { + for (int64_t i = 0; i < buf->bounds.w * buf->bounds.h; i += 1) { buf->buf[i] = colour; } +} + +void draw_buffer_rect(draw_buffer *buf, point p, rect r, uint32_t colour) { + for (int32_t x = p.x + r.x; x < p.x + r.w; x += 1) for (int32_t y = p.y + r.y; y < p.y + r.h; y += 1) { + if (x >= 0 && x < buf->bounds.w && y >= 0 && y < buf->bounds.h) { + buf->buf[(y * buf->bounds.w) + x] = colour; + } + } +} + +void draw_buffer_circle(draw_buffer *buf, point p, int32_t r, uint32_t colour) { + for (int32_t x = -r; x < r; x += 1) for (int32_t y = -r; y < r; y += 1) { + if ((x * x) + (y * y) < (r * r)) { + if (p.x + x >= 0 && p.x + x < buf->bounds.w && p.y + y >= 0 && p.y + y < buf->bounds.h) { + buf->buf[((p.y + y) * buf->bounds.w) + (p.x + x)] = colour; + } + } + } +} diff --git a/src/draw.h b/src/draw.h new file mode 100644 index 0000000..c7777d6 --- /dev/null +++ b/src/draw.h @@ -0,0 +1,87 @@ +// Copyright (C) 2024, Jakob Wakeling +// All rights reserved. + +#ifndef DRAW_DRAW_H_RNC24Y6G +#define DRAW_DRAW_H_RNC24Y6G + +#include "keys.h" + +#include <stdint.h> + +typedef enum { + DRAW_MOD_SHIFT = 0x01, + DRAW_MOD_CONTROL = 0x02, + DRAW_MOD_ALT = 0x04, + DRAW_MOD_SUPER = 0x08, + DRAW_MOD_CAPS_LOCK = 0x10, + DRAW_MOD_NUM_LOCK = 0x20, +} draw_mod_k; + +typedef enum { + DRAW_MOUSE_NONE = 0, + DRAW_MOUSE_LEFT = 1, + DRAW_MOUSE_MIDDLE = 2, + DRAW_MOUSE_RIGHT = 3, + DRAW_MOUSE_SCROLL_UP = 4, + DRAW_MOUSE_SCROLL_DOWN = 5, + DRAW_MOUSE_SCROLL_LEFT = 6, + DRAW_MOUSE_SCROLL_RIGHT = 7, + DRAW_MOUSE_BACK = 8, + DRAW_MOUSE_FORWARD = 9, +} draw_mouse_k; + +typedef enum { + DRAW_EVENT_EXIT = -1, + DRAW_EVENT_NONE = 0, + DRAW_EVENT_KEY, + DRAW_EVENT_MOUSE, + DRAW_EVENT_PAINT, + DRAW_EVENT_MOVE, + DRAW_EVENT_RESIZE, +} draw_event_k; + +typedef enum { DRAW_PRESS, DRAW_RELEASE, DRAW_REPEAT } draw_direction; + +typedef struct { draw_key_k code; draw_mod_k modifiers; draw_direction direction; } draw_event_key; +typedef struct { int32_t x, y; draw_mouse_k button; draw_mod_k modifiers; draw_direction direction; } draw_event_mouse; + +typedef struct { int32_t x, y, w, h; } draw_event_paint; +typedef struct { int32_t w, h; } draw_event_resize; + +typedef struct { + draw_event_k kind; + union { + draw_event_key key; + draw_event_mouse mouse; + draw_event_paint paint; + draw_event_resize resize; + }; +} draw_event; + +typedef struct draw_window_s draw_window; + +typedef struct { int32_t x, y; } point; +typedef struct { int32_t x, y, w, h; } rect; +typedef struct { rect bounds; uint32_t *buf; } draw_buffer; + +extern bool draw_debug; + +extern int draw_window_init(draw_window **window, int32_t w, int32_t h, const char *title, uint32_t flags); +extern void draw_window_free(draw_window **window); + +extern draw_event draw_window_event(draw_window *window); +extern void draw_window_repaint(draw_window *window); + +extern int draw_window_draw(draw_window *w, point dp, draw_buffer *buf, rect br); +extern void draw_window_clear(draw_window *w, uint32_t colour); + +extern draw_buffer *draw_buffer_init(int32_t w, int32_t h); +extern void draw_buffer_free(draw_buffer **buf); + +extern void draw_buffer_copy(draw_buffer *dst, draw_buffer *src, point dp, rect sr); + +extern void draw_buffer_clear(draw_buffer *buf, uint32_t colour); +extern void draw_buffer_rect(draw_buffer *buf, point p, rect r, uint32_t colour); +extern void draw_buffer_circle(draw_buffer *buf, point p, int32_t r, uint32_t colour); + +#endif // DRAW_DRAW_H_RNC24Y6G diff --git a/src/keys.h b/src/keys.h new file mode 100644 index 0000000..97cdc94 --- /dev/null +++ b/src/keys.h @@ -0,0 +1,136 @@ +// Copyright (C) 2024, Jakob Wakeling +// All rights reserved. + +#ifndef DRAW_KEYS_H_YB0TUA76 +#define DRAW_KEYS_H_YB0TUA76 + +typedef enum { + DRAW_KEY_UNKNOWN = -1, + + DRAW_KEY_SPACE = 0x0020, + DRAW_KEY_APOSTROPHE = 0x0027, + DRAW_KEY_COMMA = 0x002c, + DRAW_KEY_MINUS = 0x002d, + DRAW_KEY_PERIOD = 0x002e, + DRAW_KEY_SLASH = 0x002f, + + DRAW_KEY_0 = 0x0030, + DRAW_KEY_1 = 0x0031, + DRAW_KEY_2 = 0x0032, + DRAW_KEY_3 = 0x0033, + DRAW_KEY_4 = 0x0034, + DRAW_KEY_5 = 0x0035, + DRAW_KEY_6 = 0x0036, + DRAW_KEY_7 = 0x0037, + DRAW_KEY_8 = 0x0038, + DRAW_KEY_9 = 0x0039, + + DRAW_KEY_SEMICOLON = 0x003b, + DRAW_KEY_EQUAL = 0x003d, + + DRAW_KEY_A = 0x0041, + DRAW_KEY_B = 0x0042, + DRAW_KEY_C = 0x0043, + DRAW_KEY_D = 0x0044, + DRAW_KEY_E = 0x0045, + DRAW_KEY_F = 0x0046, + DRAW_KEY_G = 0x0047, + DRAW_KEY_H = 0x0048, + DRAW_KEY_I = 0x0049, + DRAW_KEY_J = 0x004a, + DRAW_KEY_K = 0x004b, + DRAW_KEY_L = 0x004c, + DRAW_KEY_M = 0x004d, + DRAW_KEY_N = 0x004e, + DRAW_KEY_O = 0x004f, + DRAW_KEY_P = 0x0050, + DRAW_KEY_Q = 0x0051, + DRAW_KEY_R = 0x0052, + DRAW_KEY_S = 0x0053, + DRAW_KEY_T = 0x0054, + DRAW_KEY_U = 0x0055, + DRAW_KEY_V = 0x0056, + DRAW_KEY_W = 0x0057, + DRAW_KEY_X = 0x0058, + DRAW_KEY_Y = 0x0059, + DRAW_KEY_Z = 0x005a, + + DRAW_KEY_LEFT_BRACKET = 0x005b, + DRAW_KEY_BACKSLASH = 0x005c, + DRAW_KEY_RIGHT_BRACKET = 0x005d, + DRAW_KEY_TILDE = 0x0060, + + DRAW_KEY_ESCAPE = 0x0100, + DRAW_KEY_BACKSPACE = 0x0101, + DRAW_KEY_TAB = 0x0102, + DRAW_KEY_CAPS_LOCK = 0x0103, + DRAW_KEY_ENTER = 0x0104, + + DRAW_KEY_F1 = 0x0105, + DRAW_KEY_F2 = 0x0106, + DRAW_KEY_F3 = 0x0107, + DRAW_KEY_F4 = 0x0108, + DRAW_KEY_F5 = 0x0109, + DRAW_KEY_F6 = 0x010a, + DRAW_KEY_F7 = 0x010b, + DRAW_KEY_F8 = 0x010c, + DRAW_KEY_F9 = 0x010d, + DRAW_KEY_F10 = 0x010e, + DRAW_KEY_F11 = 0x010f, + DRAW_KEY_F12 = 0x0110, + DRAW_KEY_F13 = 0x0111, + DRAW_KEY_F14 = 0x0112, + DRAW_KEY_F15 = 0x0113, + DRAW_KEY_F16 = 0x0114, + DRAW_KEY_F17 = 0x0115, + DRAW_KEY_F18 = 0x0116, + DRAW_KEY_F19 = 0x0117, + DRAW_KEY_F20 = 0x0118, + DRAW_KEY_F21 = 0x0119, + DRAW_KEY_F22 = 0x011a, + DRAW_KEY_F23 = 0x011b, + DRAW_KEY_F24 = 0x011c, + + DRAW_KEY_SYSRQ = 0x011d, + DRAW_KEY_SCROLL_LOCK = 0x011e, + DRAW_KEY_PAUSE = 0x011f, + DRAW_KEY_INSERT = 0x0120, + DRAW_KEY_DELETE = 0x0121, + DRAW_KEY_HOME = 0x0122, + DRAW_KEY_END = 0x0123, + DRAW_KEY_PAGE_UP = 0x0124, + DRAW_KEY_PAGE_DOWN = 0x0125, + DRAW_KEY_LEFT = 0x0126, + DRAW_KEY_RIGHT = 0x0127, + DRAW_KEY_UP = 0x0128, + DRAW_KEY_DOWN = 0x0129, + + DRAW_KEY_NUM_LOCK = 0x0200, + DRAW_KEY_KP_SLASH = 0x0201, + DRAW_KEY_KP_ASTERISK = 0x0202, + DRAW_KEY_KP_MINUS = 0x0203, + DRAW_KEY_KP_PLUS = 0x0204, + DRAW_KEY_KP_ENTER = 0x0205, + DRAW_KEY_KP_0 = 0x0210, + DRAW_KEY_KP_1 = 0x0211, + DRAW_KEY_KP_2 = 0x0212, + DRAW_KEY_KP_3 = 0x0213, + DRAW_KEY_KP_4 = 0x0214, + DRAW_KEY_KP_5 = 0x0215, + DRAW_KEY_KP_6 = 0x0216, + DRAW_KEY_KP_7 = 0x0217, + DRAW_KEY_KP_8 = 0x0218, + DRAW_KEY_KP_9 = 0x0219, + DRAW_KEY_KP_DOT = 0x021a, + + DRAW_KEY_LEFT_SHIFT = 0x0f00, + DRAW_KEY_LEFT_CONTROL = 0x0f01, + DRAW_KEY_LEFT_ALT = 0x0f02, + DRAW_KEY_LEFT_SUPER = 0x0f03, + DRAW_KEY_RIGHT_SHIFT = 0x0f04, + DRAW_KEY_RIGHT_CONTROL = 0x0f05, + DRAW_KEY_RIGHT_ALT = 0x0f06, + DRAW_KEY_RIGHT_SUPER = 0x0f07, +} draw_key_k; + +#endif // DRAW_KEYS_H_YB0TUA76 diff --git a/src/x11/draw.c b/src/x11/draw.c new file mode 100644 index 0000000..bbe3365 --- /dev/null +++ b/src/x11/draw.c @@ -0,0 +1,204 @@ +// Copyright (C) 2024, Jakob Wakeling +// All rights reserved. + +#include "../draw.h" + +#include <xcb/xcb.h> +#include <xcb/xcb_keysyms.h> +#include <xcb/xproto.h> + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> + +enum : xcb_atom_t { + ATOM_REPAINT = 0x0f00, +}; + +struct keymap { xcb_keysym_t keysym; draw_key_k key; }; + +struct draw_window_s { + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t window; + xcb_key_symbols_t *symbols; + + uint32_t x, y, w, h; +}; + +extern const struct keymap keymap[]; +extern const size_t keymap_size; + +static inline draw_mod_k mod(uint16_t state); +static inline draw_key_k keymap_find(draw_window *window, xcb_keycode_t keycode); + +int draw_window_init(draw_window **window, int32_t w, int32_t h, const char *title, uint32_t flags) { + (*window) = calloc(1, sizeof(draw_window)); if ((*window) == NULL) { return -1; } + + (*window)->connection = xcb_connect(NULL, NULL); + if (xcb_connection_has_error((*window)->connection)) { return -1; } + + (*window)->screen = xcb_setup_roots_iterator(xcb_get_setup((*window)->connection)).data; + + (*window)->window = xcb_generate_id((*window)->connection); + if ((*window)->window == -1) { xcb_disconnect((*window)->connection); return -1; } + + uint32_t mask = XCB_CW_EVENT_MASK; + uint32_t values[1] = { + XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_BUTTON_MOTION + }; + + xcb_create_window( + (*window)->connection, XCB_COPY_FROM_PARENT, (*window)->window, (*window)->screen->root, 0, 0, w, h, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, (*window)->screen->root_visual, mask, values + ); + + (*window)->symbols = xcb_key_symbols_alloc((*window)->connection); + (*window)->w = w; (*window)->h = h; + + xcb_map_window((*window)->connection, (*window)->window); + xcb_flush((*window)->connection); + + return 0; +} + +void draw_window_free(draw_window **window) { + if (*window == NULL) { return; } + + xcb_key_symbols_free((*window)->symbols); + xcb_destroy_window((*window)->connection, (*window)->window); + xcb_disconnect((*window)->connection); + + free(*window); *window = NULL; +} + +draw_event draw_window_event(draw_window *window) { + xcb_generic_event_t *_e = xcb_wait_for_event(window->connection); + if (_e == NULL) { + if (draw_debug) { printf("xcb_wait_for_event returned NULL\n"); } + return (draw_event){ .kind = DRAW_EVENT_EXIT }; + } + + draw_event event = {}; + + /* TODO handle modifiers */ + switch (_e->response_type & ~0x80) { + case XCB_KEY_PRESS: { + xcb_key_press_event_t *e = (xcb_key_press_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_KEY, .key = { + .code = keymap_find(window, e->detail), .modifiers = mod(e->state), .direction = DRAW_PRESS, + }}; + } break; + case XCB_KEY_RELEASE: { + xcb_key_release_event_t *e = (xcb_key_release_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_KEY, .key = { + .code = keymap_find(window, e->detail), .modifiers = mod(e->state), .direction = DRAW_RELEASE, + }}; + } break; + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *e = (xcb_button_press_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_MOUSE, .mouse = { + .x = e->event_x, .y = e->event_y, .button = e->detail, .modifiers = mod(e->state), + .direction = DRAW_PRESS, + }}; + } break; + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *e = (xcb_button_release_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_MOUSE, .mouse = { + .x = e->event_x, .y = e->event_y, .button = e->detail, .modifiers = mod(e->state), + .direction = DRAW_RELEASE, + }}; + } break; + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_MOUSE, .mouse = { + .x = e->event_x, .y = e->event_y, .button = e->detail, .modifiers = mod(e->state), + .direction = DRAW_REPEAT, + }}; + } break; + case XCB_EXPOSE: { + xcb_expose_event_t *e = (xcb_expose_event_t *)_e; + event = (draw_event){ .kind = DRAW_EVENT_PAINT, .paint = { e->x, e->y, e->width, e->height }}; + if (draw_debug) { printf("Exposed %d, %d, %d, %d\n", e->x, e->y, e->width, e->height); } + } break; + case XCB_CONFIGURE_NOTIFY: { + xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *)_e; + + if (e->width != window->w || e->height != window->h) { + window->w = e->width; window->h = e->height; + event = (draw_event){ .kind = DRAW_EVENT_RESIZE, .resize = { e->width, e->height }}; + if (draw_debug) { printf("Resized to %d, %d\n", e->width, e->height); } + } + } break; + case XCB_CLIENT_MESSAGE: { + xcb_client_message_event_t *e = (xcb_client_message_event_t *)_e; + switch (e->type) { + case ATOM_REPAINT: { + event = (draw_event){ .kind = DRAW_EVENT_PAINT, .paint = { 0, 0, window->w, window->h }}; + } break; + } + } break; + default: { if (draw_debug) { printf("Unhandled X11 event: %d\n", _e->response_type & ~0x80); }} break; + } + + free(_e); return event; +} + +void draw_window_repaint(draw_window *window) { + xcb_client_message_event_t e = { + .response_type = XCB_CLIENT_MESSAGE, .format = 32, .window = window->window, .type = ATOM_REPAINT, + .data.data32 = {} + }; + + xcb_send_event(window->connection, 0, window->window, XCB_EVENT_MASK_NO_EVENT, (const char *)&e); + xcb_flush(window->connection); +} + +int draw_window_draw(draw_window *w, point dp, draw_buffer *buf, rect br) { + if (w == NULL) { return 1; } + + xcb_gcontext_t gc = xcb_generate_id(w->connection); + + + xcb_create_gc(w->connection, gc, w->window, 0, NULL); + xcb_put_image( + w->connection, XCB_IMAGE_FORMAT_Z_PIXMAP, w->window, gc, br.w, br.h, dp.x, dp.y, 0, 24, + (buf->bounds.w * buf->bounds.h) * sizeof (*buf->buf), (uint8_t *)buf->buf + ); + xcb_free_gc(w->connection, gc); + xcb_flush(w->connection); + + return 0; +} + +void draw_window_clear(draw_window *w, uint32_t colour) { + if (w == NULL) { return; } + + xcb_gcontext_t gc = xcb_generate_id(w->connection); + xcb_create_gc(w->connection, gc, w->window, 0, NULL); + xcb_change_gc(w->connection, gc, XCB_GC_FOREGROUND, (uint32_t[]){colour}); + xcb_poly_fill_rectangle(w->connection, w->window, gc, 1, (xcb_rectangle_t[]){{ + .x = 0, .y = 0, .width = w->w, .height = w->h, + }}); + xcb_free_gc(w->connection, gc); + xcb_flush(w->connection); +} + +static inline draw_mod_k mod(uint16_t state) { + draw_mod_k mod = 0; + mod |= ((state & XCB_MOD_MASK_SHIFT) != 0) * DRAW_MOD_SHIFT; + mod |= ((state & XCB_MOD_MASK_CONTROL) != 0) * DRAW_MOD_CONTROL; + mod |= ((state & XCB_MOD_MASK_1) != 0) * DRAW_MOD_ALT; + mod |= ((state & XCB_MOD_MASK_4) != 0) * DRAW_MOD_SUPER; + mod |= ((state & XCB_MOD_MASK_LOCK) != 0) * DRAW_MOD_CAPS_LOCK; + mod |= ((state & XCB_MOD_MASK_2) != 0) * DRAW_MOD_NUM_LOCK; + return mod; +} + +static inline draw_key_k keymap_find(draw_window *window, xcb_keycode_t keycode) { + xcb_keysym_t keysym = xcb_key_symbols_get_keysym(window->symbols, keycode, 0); + for (size_t i = 0; i < keymap_size; i += 1) { if (keymap[i].keysym == keysym) { return keymap[i].key; }} + return DRAW_KEY_UNKNOWN; +} diff --git a/src/x11/keys.c b/src/x11/keys.c new file mode 100644 index 0000000..be76519 --- /dev/null +++ b/src/x11/keys.c @@ -0,0 +1,137 @@ +// Copyright (C) 2024, Jakob Wakeling +// All rights reserved. + +#include "../keys.h" + +#include <xcb/xcb_keysyms.h> +#include <X11/keysym.h> + +struct keymap { xcb_keysym_t keysym; draw_key_k key; }; + +const struct keymap keymap[] = { + { XK_space, DRAW_KEY_SPACE }, + { XK_apostrophe, DRAW_KEY_APOSTROPHE }, + { XK_comma, DRAW_KEY_COMMA }, + { XK_minus, DRAW_KEY_MINUS }, + { XK_period, DRAW_KEY_PERIOD }, + { XK_slash, DRAW_KEY_SLASH }, + + { XK_0, DRAW_KEY_0 }, + { XK_1, DRAW_KEY_1 }, + { XK_2, DRAW_KEY_2 }, + { XK_3, DRAW_KEY_3 }, + { XK_4, DRAW_KEY_4 }, + { XK_5, DRAW_KEY_5 }, + { XK_6, DRAW_KEY_6 }, + { XK_7, DRAW_KEY_7 }, + { XK_8, DRAW_KEY_8 }, + { XK_9, DRAW_KEY_9 }, + + { XK_semicolon, DRAW_KEY_SEMICOLON }, + { XK_equal, DRAW_KEY_EQUAL }, + + { XK_a, DRAW_KEY_A }, + { XK_b, DRAW_KEY_B }, + { XK_c, DRAW_KEY_C }, + { XK_d, DRAW_KEY_D }, + { XK_e, DRAW_KEY_E }, + { XK_f, DRAW_KEY_F }, + { XK_g, DRAW_KEY_G }, + { XK_h, DRAW_KEY_H }, + { XK_i, DRAW_KEY_I }, + { XK_j, DRAW_KEY_J }, + { XK_k, DRAW_KEY_K }, + { XK_l, DRAW_KEY_L }, + { XK_m, DRAW_KEY_M }, + { XK_n, DRAW_KEY_N }, + { XK_o, DRAW_KEY_O }, + { XK_p, DRAW_KEY_P }, + { XK_q, DRAW_KEY_Q }, + { XK_r, DRAW_KEY_R }, + { XK_s, DRAW_KEY_S }, + { XK_t, DRAW_KEY_T }, + { XK_u, DRAW_KEY_U }, + { XK_v, DRAW_KEY_V }, + { XK_w, DRAW_KEY_W }, + { XK_x, DRAW_KEY_X }, + { XK_y, DRAW_KEY_Y }, + { XK_z, DRAW_KEY_Z }, + + { XK_bracketleft, DRAW_KEY_LEFT_BRACKET }, + { XK_backslash, DRAW_KEY_BACKSLASH }, + { XK_bracketright, DRAW_KEY_RIGHT_BRACKET }, + { XK_grave, DRAW_KEY_TILDE }, + { XK_Escape, DRAW_KEY_ESCAPE }, + { XK_BackSpace, DRAW_KEY_BACKSPACE }, + { XK_Tab, DRAW_KEY_TAB }, + { XK_Caps_Lock, DRAW_KEY_CAPS_LOCK }, + { XK_Return, DRAW_KEY_ENTER }, + + { XK_F1, DRAW_KEY_F1 }, + { XK_F2, DRAW_KEY_F2 }, + { XK_F3, DRAW_KEY_F3 }, + { XK_F4, DRAW_KEY_F4 }, + { XK_F5, DRAW_KEY_F5 }, + { XK_F6, DRAW_KEY_F6 }, + { XK_F7, DRAW_KEY_F7 }, + { XK_F8, DRAW_KEY_F8 }, + { XK_F9, DRAW_KEY_F9 }, + { XK_F10, DRAW_KEY_F10 }, + { XK_F11, DRAW_KEY_F11 }, + { XK_F12, DRAW_KEY_F12 }, + { XK_F13, DRAW_KEY_F13 }, + { XK_F14, DRAW_KEY_F14 }, + { XK_F15, DRAW_KEY_F15 }, + { XK_F16, DRAW_KEY_F16 }, + { XK_F17, DRAW_KEY_F17 }, + { XK_F18, DRAW_KEY_F18 }, + { XK_F19, DRAW_KEY_F19 }, + { XK_F20, DRAW_KEY_F20 }, + { XK_F21, DRAW_KEY_F21 }, + { XK_F22, DRAW_KEY_F22 }, + { XK_F23, DRAW_KEY_F23 }, + { XK_F24, DRAW_KEY_F24 }, + + { XK_Sys_Req, DRAW_KEY_SYSRQ }, + { XK_Scroll_Lock, DRAW_KEY_SCROLL_LOCK }, + { XK_Pause, DRAW_KEY_PAUSE }, + { XK_Insert, DRAW_KEY_INSERT }, + { XK_Delete, DRAW_KEY_DELETE }, + { XK_Home, DRAW_KEY_HOME }, + { XK_End, DRAW_KEY_END }, + { XK_Page_Up, DRAW_KEY_PAGE_UP }, + { XK_Page_Down, DRAW_KEY_PAGE_DOWN }, + { XK_Left, DRAW_KEY_LEFT }, + { XK_Up, DRAW_KEY_UP }, + { XK_Right, DRAW_KEY_RIGHT }, + { XK_Down, DRAW_KEY_DOWN }, + + { XK_Num_Lock, DRAW_KEY_NUM_LOCK }, + { XK_KP_Divide, DRAW_KEY_KP_SLASH }, + { XK_KP_Multiply, DRAW_KEY_KP_ASTERISK }, + { XK_KP_Subtract, DRAW_KEY_KP_MINUS }, + { XK_KP_Add, DRAW_KEY_KP_PLUS }, + { XK_KP_Enter, DRAW_KEY_KP_ENTER }, + { XK_KP_Insert, DRAW_KEY_KP_0 }, + { XK_KP_End, DRAW_KEY_KP_1 }, + { XK_KP_Down, DRAW_KEY_KP_2 }, + { XK_KP_Page_Down, DRAW_KEY_KP_3 }, + { XK_KP_Left, DRAW_KEY_KP_4 }, + { XK_KP_Begin, DRAW_KEY_KP_5 }, + { XK_KP_Right, DRAW_KEY_KP_6 }, + { XK_KP_Home, DRAW_KEY_KP_7 }, + { XK_KP_Up, DRAW_KEY_KP_8 }, + { XK_KP_Page_Up, DRAW_KEY_KP_9 }, + { XK_KP_Delete, DRAW_KEY_KP_DOT }, + + { XK_Shift_L, DRAW_KEY_LEFT_SHIFT }, + { XK_Control_L, DRAW_KEY_LEFT_CONTROL }, + { XK_Alt_L, DRAW_KEY_LEFT_ALT }, + { XK_Super_L, DRAW_KEY_LEFT_SUPER }, + { XK_Shift_R, DRAW_KEY_RIGHT_SHIFT }, + { XK_Control_R, DRAW_KEY_RIGHT_CONTROL }, + { XK_Alt_R, DRAW_KEY_RIGHT_ALT }, + { XK_Super_R, DRAW_KEY_RIGHT_SUPER }, +}; + +const size_t keymap_size = sizeof(keymap) / sizeof(*keymap);