From e3c90b41386986ef53e512994d6e2f7ceadfc177 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 8 Nov 2021 02:07:23 +0100 Subject: Add window function to get key state, allow invalid utf8 --- src/graphics/text.c | 26 ++++++++++--------- src/system/utf8.c | 74 +++++++++++++++++++++++------------------------------ src/window/window.c | 65 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 99 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/graphics/text.c b/src/graphics/text.c index 2f410d4..28840ce 100644 --- a/src/graphics/text.c +++ b/src/graphics/text.c @@ -20,8 +20,13 @@ static mgl_vec2f mgl_text_calculate_bounds(mgl_text *self) { float width = 0.0f; for(size_t i = 0; i < self->text_size;) { unsigned char *cp = (unsigned char*)&self->text[i]; - uint32_t codepoint = 0; - const size_t clen = mgl_utf8_decode(cp, &codepoint); + uint32_t codepoint; + size_t clen; + if(!mgl_utf8_decode(cp, self->text_size - i, &codepoint, &clen)) { + codepoint = *cp; + clen = 1; + } + if(codepoint == '\t') { if(mgl_font_get_glyph(self->font, ' ', &glyph) == 0) { width += (glyph.advance * TAB_WIDTH); @@ -60,20 +65,12 @@ void mgl_text_deinit(mgl_text *self) { } int mgl_text_set_string(mgl_text *self, const char *str, size_t str_size) { - if(str) { - if(!mgl_utf8_is_valid((const unsigned char*)str, str_size)) { - fprintf(stderr, "Error: mgl_text_set_string received an invalid utf8 string\n"); - return -1; - } - } - self->text = str; self->text_size = str_size; if(self->text && self->text_size > 0 && self->font) self->bounds = mgl_text_calculate_bounds(self); else self->bounds = (mgl_vec2f){ 0.0f, 0.0f }; - return 0; } @@ -128,8 +125,13 @@ void mgl_text_draw(mgl_context *context, mgl_text *text) { context->gl.glBegin(GL_QUADS); for(size_t i = 0; i < text->text_size;) { unsigned char *cp = (unsigned char*)&text->text[i]; - uint32_t codepoint = 0; - const size_t clen = mgl_utf8_decode(cp, &codepoint); + uint32_t codepoint; + size_t clen; + if(!mgl_utf8_decode(cp, text->text_size - i, &codepoint, &clen)) { + codepoint = *cp; + clen = 1; + } + if(codepoint == '\t') { if(mgl_font_get_glyph(text->font, ' ', &glyph) == 0) { position.x += (glyph.advance * TAB_WIDTH); diff --git a/src/system/utf8.c b/src/system/utf8.c index cb14691..35b0f2f 100644 --- a/src/system/utf8.c +++ b/src/system/utf8.c @@ -1,54 +1,42 @@ #include "../../include/mgl/system/utf8.h" +static inline bool utf8_get_codepoint_length(unsigned char b, size_t *codepoint_length) { + if((b & 0x80) == 0) { + *codepoint_length = 1; + return true; + } else if((b & 0xE0) == 0xC0) { + *codepoint_length = 2; + return true; + } else if((b & 0xF0) == 0xE0) { + *codepoint_length = 3; + return true; + } else if((b & 0xF8) == 0xF0) { + *codepoint_length = 4; + return true; + } else { + return false; + } +} + /* TODO: Optimize (remove branching, etc) */ -bool mgl_utf8_is_valid(const unsigned char *str, size_t size) { - size_t i = 0; - while(i < size) { - size_t codepoint_length = 0; - const unsigned char b = str[i]; +bool mgl_utf8_decode(const unsigned char *str, size_t size, uint32_t *decoded_codepoint, size_t *codepoint_length) { + if(size == 0) + return false; - if((b & 0x80) == 0) - codepoint_length = 1; - else if((b & 0xE0) == 0xC0) - codepoint_length = 2; - else if((b & 0xF0) == 0xE0) - codepoint_length = 3; - else if((b & 0xF8) == 0xF0) - codepoint_length = 4; - else - return false; + size_t clen; + if(!utf8_get_codepoint_length(str[0], &clen)) + return false; - const size_t next = i + codepoint_length; - if(next > size) - return false; + if(size < clen) + return false; - /* TODO: Remove this overflow check? */ - /* Check overflow */ - if(next <= i) + for(size_t i = 1; i < clen; ++i) { + if((str[i] & 0xC0) != 0x80) return false; - - ++i; - for(; i < next; ++i) { - if((str[i] & 0xC0) != 0x80) - return false; - } } - return true; -} - -static inline size_t utf8_get_codepoint_length(unsigned char b) { - const unsigned int length1 = b >> 7; - const unsigned int length2 = length1 & ((b & 0x40) >> 6); - const unsigned int length3 = length2 & ((b & 0x20) >> 5); - const unsigned int length4 = length3 & ((b & 0x10) >> 4); - return (length1 ^ 0x01) + length1 + length2 + length3 + length4; -} -/* TODO: Optimize (remove branching, etc) */ -size_t mgl_utf8_decode(const unsigned char *str, uint32_t *decoded_codepoint) { - const size_t length = utf8_get_codepoint_length(str[0]); uint32_t codepoint; - switch(length) { + switch(clen) { case 1: codepoint = (uint32_t)(str[0] & 0x7F); break; @@ -68,6 +56,8 @@ size_t mgl_utf8_decode(const unsigned char *str, uint32_t *decoded_codepoint) { codepoint |= (uint32_t)(str[3] & 0x3F); break; } + + *codepoint_length = clen; *decoded_codepoint = codepoint; - return length; + return true; } diff --git a/src/window/window.c b/src/window/window.c index 05cd5f5..642609b 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -57,8 +57,20 @@ typedef struct { an event for all of them. */ x11_events_circular_buffer events; + bool key_pressed[__MGL_NUM_KEYS__]; } x11_context; +static void x11_context_init(x11_context *self) { + self->glx_context = NULL; + self->xim = NULL; + self->xic = NULL; + x11_events_circular_buffer_init(&self->events); + + for(size_t i = 0; i < __MGL_NUM_KEYS__; ++i) { + self->key_pressed[i] = false; + } +} + static bool x11_context_append_event(x11_context *self, const mgl_event *event) { return x11_events_circular_buffer_append(&self->events, event); } @@ -67,6 +79,20 @@ static bool x11_context_pop_event(x11_context *self, mgl_event *event) { return x11_events_circular_buffer_pop(&self->events, event); } +/* Returns true if the state changed */ +static bool x11_context_update_key_state(x11_context *self, mgl_key key, bool key_pressed) { + if(self->key_pressed[key] != key_pressed) { + self->key_pressed[key] = key_pressed; + return true; + } else { + return false; + } +} + +static bool x11_context_is_key_pressed(const x11_context *self, mgl_key key) { + return self->key_pressed[key]; +} + /* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */ /* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */ @@ -118,10 +144,7 @@ static int mgl_window_init(mgl_window *self, const char *title, int width, int h } x11_context *x11_context = self->context; - x11_context->glx_context = NULL, - x11_context->xim = NULL, - x11_context->xic = NULL; - x11_events_circular_buffer_init(&x11_context->events); + x11_context_init(x11_context); mgl_context *context = mgl_get_context(); @@ -281,6 +304,14 @@ static mgl_key x11_keysym_to_mgl_key(KeySym key_sym) { case XK_Tab: return MGL_KEY_TAB; case XK_Return: return MGL_KEY_ENTER; case XK_Escape: return MGL_KEY_ESCAPE; + case XK_Control_L: return MGL_KEY_LCONTROL; + case XK_Shift_L: return MGL_KEY_LSHIFT; + case XK_Alt_L: return MGL_KEY_LALT; + case XK_Super_L: return MGL_KEY_LSYSTEM; + case XK_Control_R: return MGL_KEY_RCONTROL; + case XK_Shift_R: return MGL_KEY_RSHIFT; + case XK_Alt_R: return MGL_KEY_RALT; + case XK_Super_R: return MGL_KEY_RSYSTEM; case XK_Delete: return MGL_KEY_DELETE; case XK_Home: return MGL_KEY_HOME; case XK_Left: return MGL_KEY_LEFT; @@ -320,12 +351,13 @@ static mgl_mouse_button x11_button_to_mgl_button(unsigned int button) { return MGL_BUTTON_UNKNOWN; } -static void mgl_window_handle_key_event(mgl_window *self, XKeyEvent *xkey, mgl_event *event, mgl_context *context) { +static void mgl_window_handle_key_event(mgl_window *self, XKeyEvent *xkey, mgl_event *event, mgl_context *context, bool pressed) { event->key.code = x11_keysym_to_mgl_key(XKeycodeToKeysym(context->connection, xkey->keycode, 0)); event->key.alt = ((xkey->state & Mod1Mask) != 0); event->key.control = ((xkey->state & ControlMask) != 0); event->key.shift = ((xkey->state & ShiftMask) != 0); - event->key.system = ((xkey->state & Mod5Mask) != 0); /* TODO: Fix, doesn't work */ + event->key.system = ((xkey->state & Mod4Mask) != 0); /* TODO: Fix, doesn't work */ + x11_context_update_key_state(self->context, event->key.code, pressed); } static void mgl_window_handle_text_event(mgl_window *self, XEvent *xev) { @@ -344,12 +376,15 @@ static void mgl_window_handle_text_event(mgl_window *self, XEvent *xev) { return; /* TODO: Set XIC location on screen with XSetICValues */ - if(!mgl_utf8_is_valid((const unsigned char*)buf, input_str_len)) - return; for(size_t i = 0; i < input_str_len;) { - uint32_t codepoint = 0; - const size_t clen = mgl_utf8_decode((const unsigned char*)&buf[i], &codepoint); + const unsigned char *cp = (const unsigned char*)&buf[i]; + uint32_t codepoint; + size_t clen; + if(!mgl_utf8_decode(cp, input_str_len - i, &codepoint, &clen)) { + codepoint = *cp; + clen = 1; + } mgl_event text_event; text_event.type = MGL_EVENT_TEXT_ENTERED; @@ -370,13 +405,13 @@ static void mgl_window_on_receive_event(mgl_window *self, XEvent *xev, mgl_event switch(xev->type) { case KeyPress: { event->type = MGL_EVENT_KEY_PRESSED; - mgl_window_handle_key_event(self, &xev->xkey, event, context); + mgl_window_handle_key_event(self, &xev->xkey, event, context, true); mgl_window_handle_text_event(self, xev); return; } case KeyRelease: { event->type = MGL_EVENT_KEY_RELEASED; - mgl_window_handle_key_event(self, &xev->xkey, event, context); + mgl_window_handle_key_event(self, &xev->xkey, event, context, false); return; } case ButtonPress: { @@ -480,3 +515,9 @@ void mgl_window_get_view(mgl_window *self, mgl_view *view) { bool mgl_window_is_open(const mgl_window *self) { return self->open; } + +bool mgl_window_is_key_pressed(const mgl_window *self, mgl_key key) { + if(key < 0 || key >= __MGL_NUM_KEYS__) + return false; + return x11_context_is_key_pressed(self->context, key); +} -- cgit v1.2.3