From a97e134450f47ba0e90541e6791f72cbf1f65e27 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sun, 11 Aug 2024 13:19:05 +0200 Subject: UTF-8 --- examples/ui.c | 163 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 55 deletions(-) (limited to 'examples/ui.c') diff --git a/examples/ui.c b/examples/ui.c index d51ad99..d853c4b 100755 --- a/examples/ui.c +++ b/examples/ui.c @@ -66,6 +66,7 @@ typedef unsigned short u16; typedef unsigned u32; typedef unsigned long long u64; typedef char c8; +typedef int c32; typedef signed char b8; typedef float f32; typedef double f64; @@ -117,29 +118,34 @@ enum { MOD_CAPS, MOD_NUM, MOD_SCROLL, - KEY_KP_, - KEY_F_ = KEY_KP_ + 64, + KEY_F_, + KEY_KP_ = KEY_F_ + 64, }; typedef struct { - c8 *title; - i32 frame_width; - i32 frame_height; - u32 *pixels; - i64 input_size; - i16 *input; - i64 clipboard_size; - c8 *clipboard; // TODO - b8 done; - b8 has_focus; - b8 has_cursor; - i32 cursor_x; - i32 cursor_y; - i32 cursor_dx; - i32 cursor_dy; - i64 wheel_dy; - b8 key_down[512]; - b8 key_pressed[512]; + u32 key; + c32 c; +} Input_Key; + +typedef struct { + c8 * title; + i32 frame_width; + i32 frame_height; + u32 * pixels; + i64 input_size; + Input_Key *input; + i64 clipboard_size; + c8 * clipboard; // TODO + b8 done; + b8 has_focus; + b8 has_cursor; + i32 cursor_x; + i32 cursor_y; + i32 cursor_dx; + i32 cursor_dy; + i64 wheel_dy; + b8 key_down[512]; + b8 key_pressed[512]; } Platform; typedef struct { @@ -196,7 +202,7 @@ u64 bitfont[] = { #define BITFONT_LEN ((i64) (sizeof bitfont / sizeof *bitfont)) -i64 char_column_offset(c8 c, i64 column_index) { +i64 char_column_offset(c32 c, i64 column_index) { if (column_index < 0 || column_index >= CHAR_NUM_BITS_X) return -1; return (c - 32) * CHAR_NUM_BITS + column_index * CHAR_NUM_BITS_Y; @@ -214,7 +220,7 @@ b8 char_bit(i64 column_offset, i64 row_index) { return !!(bitfont[qword_index] & mask); } -u64 char_column_convolved(c8 c, i64 column_index) { +u64 char_column_convolved(c32 c, i64 column_index) { if (column_index < 0 || column_index >= CHAR_NUM_BITS_X) return 0; @@ -235,7 +241,7 @@ u64 char_column_convolved(c8 c, i64 column_index) { return column; } -b8 char_column_empty(c8 c, i64 column_index) { +b8 char_column_empty(c32 c, i64 column_index) { if (column_index < 0 || column_index >= CHAR_NUM_BITS_X) return 1; @@ -248,7 +254,7 @@ b8 char_column_empty(c8 c, i64 column_index) { return 1; } -i64 char_width(c8 c) { +i64 char_width(c32 c) { if (c < 32) return 0; if (c == ' ') @@ -263,7 +269,7 @@ i64 char_width(c8 c) { return width; } -i64 char_spacing(i64 num_chars, c8 *text, i64 index) { +i64 char_spacing(i64 num_chars, c32 *text, i64 index) { assert(text != NULL); if (index < 0 || index + 1 >= num_chars) @@ -278,7 +284,7 @@ i64 char_spacing(i64 num_chars, c8 *text, i64 index) { return 0; } -i64 text_cursor(i64 num_chars, c8 *text) { +i64 text_cursor(i64 num_chars, c32 *text) { assert(text != NULL); i64 cursor = 0; @@ -301,7 +307,7 @@ i64 text_cursor(i64 num_chars, c8 *text) { return cursor; } -i64 enum_text_columns(i64 num_chars, c8 *text) { +i64 enum_text_columns(i64 num_chars, c32 *text) { assert(text != NULL); i64 cols = 0; @@ -334,7 +340,7 @@ i64 enum_text_columns(i64 num_chars, c8 *text) { return cols; } -i64 enum_text_rows(i64 num_chars, c8 *text) { +i64 enum_text_rows(i64 num_chars, c32 *text) { assert(text != NULL); i64 rows = 0; @@ -349,7 +355,7 @@ i64 enum_text_rows(i64 num_chars, c8 *text) { return rows; } -void print_text(u32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_chars, c8 *text) { +void print_text(u32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_chars, c32 *text) { assert(text != NULL); f64 x = x0; @@ -422,7 +428,7 @@ void draw_panel(u32 op, u32 color, f64 x0, f64 y0, f64 width, f64 height) { platform.pixels[j * platform.frame_width + i] = color; } -void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c8 *text) { +void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c32 *text) { assert(max_scale_x > 1e-6); assert(max_scale_y > 1e-6); @@ -443,7 +449,7 @@ void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_sc print_text(color, x0, y0, kx, ky, num_chars, text); } -void draw_text_cursor(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c8 *text) { +void draw_text_cursor(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c32 *text) { assert(max_scale_x > 1e-6); assert(max_scale_y > 1e-6); @@ -523,8 +529,8 @@ i32 main(i32 argc, c8 **argv) { b8 button_1_down = 0; b8 button_1_checked = 0; - i64 text_len = 0; - static c8 text[512] = ""; + i64 text_len = 0; + static c32 text[512] = {0}; i64 cursor = 0; i64 selection = 0; @@ -577,7 +583,7 @@ i32 main(i32 argc, c8 **argv) { color = 0xffffff; for (i64 i = 0; i < platform.input_size; ++i) - switch (platform.input[i]) { + switch (platform.input[i].key) { case KEY_LEFT: if (platform.key_down[MOD_SHIFT]) { if (cursor > 0) @@ -635,8 +641,14 @@ i32 main(i32 argc, c8 **argv) { } break; + case '\n': + case '\r': + case '\t': + platform.input[i].c = platform.input[i].key; + // fallthrough + default: - if (platform.input[i] > 0 && platform.input[i] < 128) { + if (platform.input[i].c) { if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; @@ -650,7 +662,7 @@ i32 main(i32 argc, c8 **argv) { if (text_len < (i64) sizeof text) { for (i64 i = text_len; i > cursor; --i) text[i] = text[i - 1]; - text[cursor++] = (c8) platform.input[i]; + text[cursor++] = platform.input[i].c; ++text_len; } } @@ -728,14 +740,16 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data) { #include #include -static i16 _key_table[512] = {0}; -static u32 _buffer[MAX_NUM_PIXELS] = {0}; -static i16 _input[MAX_INPUT_SIZE] = {0}; -static XImage _image = {0}; -static Display *_display = NULL; -static GC _gc = NULL; -static Window _window = 0; -static Atom _wm_delete_window = 0; +static i16 _key_table[512] = {0}; +static u32 _buffer[MAX_NUM_PIXELS] = {0}; +static Input_Key _input[MAX_INPUT_SIZE] = {0}; +static XImage _image = {0}; +static Display * _display = NULL; +static GC _gc = NULL; +static XIM _im = NULL; +static XIC _ic = NULL; +static Window _window = 0; +static Atom _wm_delete_window = 0; void p_init(void) { _display = XOpenDisplay(NULL); @@ -846,6 +860,7 @@ void p_init(void) { Visual *visual = DefaultVisual(_display, screen); _gc = DefaultGC(_display, screen); + assert(_gc != NULL); XSetGraphicsExposures(_display, _gc, False); @@ -857,6 +872,14 @@ void p_init(void) { _window = XCreateWindow(_display, XDefaultRootWindow(_display), x, y, platform.frame_width, platform.frame_height, 0, depth, InputOutput, visual, CWEventMask, &(XSetWindowAttributes) { .event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | SubstructureNotifyMask, }); + _im = XOpenIM(_display, NULL, NULL, NULL); + assert(_im != NULL); + + _ic = XCreateIC(_im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, _window, NULL); + assert(_ic != NULL); + + XSetICFocus(_ic); + platform.pixels = _buffer; platform.input = _input; @@ -894,8 +917,36 @@ void p_cleanup(void) { XCloseDisplay (_display); } +c32 c32_from_utf8(i64 len, c8 *s) { + if (len <= 1 && + (s[0] & 0x80) == 0) + return s[0]; + if (len <= 2 && + (s[0] & 0xe0) == 0xc0 && + (s[1] & 0xc0) == 0x80) + return (s[1] & 0x3f) + | ((s[0] & 0x1f) << 6); + if (len <= 3 && + (s[0] & 0xf0) == 0xe0 && + (s[1] & 0xc0) == 0x80 && + (s[2] & 0xc0) == 0x80) + return (s[2] & 0x3f) + | ((s[1] & 0x3f) << 6) + | ((s[0] & 0x0f) << 12); + if (len <= 4 && + (s[0] & 0xf8) == 0xf0 && + (s[1] & 0xc0) == 0x80 && + (s[2] & 0xc0) == 0x80 && + (s[3] & 0xc0) == 0x80) + return (s[3] & 0x3f) + | ((s[2] & 0x3f) << 6) + | ((s[1] & 0x3f) << 12) + | ((s[0] & 0x07) << 18); + return 0; +} + i32 p_handle_events(void) { - i32 num_events = XEventsQueued(_display, QueuedAlready); + i32 num_events = 0; memset(platform.key_pressed, 0, sizeof platform.key_pressed); @@ -906,8 +957,11 @@ i32 p_handle_events(void) { XEvent ev; - for (i32 i = 0; i < num_events; ++i) { + while (XEventsQueued(_display, QueuedAlready) > 0) { + ++num_events; + XNextEvent(_display, &ev); + XFilterEvent(&ev, _window); switch (ev.type) { case DestroyNotify: @@ -968,17 +1022,12 @@ i32 p_handle_events(void) { platform.key_down[MOD_SCROLL] = !!(ev.xkey.state & Mod3Mask); if (platform.input_size < MAX_INPUT_SIZE) { if (k < 32 || k >= 128) - platform.input[platform.input_size++] = k; + platform.input[platform.input_size++] = (Input_Key) { .key = k, .c = 0, }; else { c8 buf[16]; - i32 len = XLookupString(&ev.xkey, buf, sizeof buf - 1, NULL, NULL); - buf[len] = '\0'; - printf("key:"); - for (i32 i = 0; i < len; ++i) - printf("%02x", buf[i]); - printf("\n"); - for (i32 i = 0; i < len && platform.input_size < MAX_INPUT_SIZE; ++i, ++platform.input_size) - platform.input[platform.input_size] = buf[i]; + i32 len = Xutf8LookupString(_ic, &ev.xkey, buf, sizeof buf - 1, NULL, NULL); + if (len > 0) + platform.input[platform.input_size++] = (Input_Key) { .key = k, .c = c32_from_utf8(len, buf), }; } } } break; @@ -1002,6 +1051,10 @@ i32 p_handle_events(void) { case FocusIn: platform.has_focus = 1; break; case FocusOut: platform.has_focus = 0; break; + case MappingNotify: + XRefreshKeyboardMapping(&ev.xmapping); + break; + case ClientMessage: if ((Atom) ev.xclient.data.l[0] == _wm_delete_window) platform.done = 1; -- cgit v1.2.3