aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-11-08 02:07:23 +0100
committerdec05eba <dec05eba@protonmail.com>2021-11-08 02:07:23 +0100
commite3c90b41386986ef53e512994d6e2f7ceadfc177 (patch)
tree6fc1ad55e194a1c7663de3f2c9f178b1f67f2695
parent16b0ce3748f1b3ea788bbaf4caaeb342a8f58d6f (diff)
Add window function to get key state, allow invalid utf8
-rw-r--r--README.md4
-rw-r--r--include/mgl/graphics/text.h1
-rw-r--r--include/mgl/system/utf8.h8
-rw-r--r--include/mgl/window/key.h5
-rw-r--r--include/mgl/window/window.h2
-rw-r--r--src/graphics/text.c26
-rw-r--r--src/system/utf8.c74
-rw-r--r--src/window/window.c65
8 files changed, 109 insertions, 76 deletions
diff --git a/README.md b/README.md
index 620699a..f959d7c 100644
--- a/README.md
+++ b/README.md
@@ -5,4 +5,6 @@ Right now mgl only supports x11.
## Build
`xlib`
## Runtime
-`libglvnd (libGL.so)` \ No newline at end of file
+`libglvnd (libGL.so)`
+# Notes
+Every window _get_ function is cached from the last event poll, no calls to x11 is made.
diff --git a/include/mgl/graphics/text.h b/include/mgl/graphics/text.h
index aca0650..2311d23 100644
--- a/include/mgl/graphics/text.h
+++ b/include/mgl/graphics/text.h
@@ -34,7 +34,6 @@ void mgl_text_deinit(mgl_text *self);
/*
Note: keeps a reference to |text|. |text| needs to be valid as long as |self| is used.
|text| may be NULL.
- |str| will be checked if its a valid utf8 string.
*/
int mgl_text_set_string(mgl_text *self, const char *str, size_t str_size);
/* |font| may be NULL */
diff --git a/include/mgl/system/utf8.h b/include/mgl/system/utf8.h
index 663e7e3..f745be7 100644
--- a/include/mgl/system/utf8.h
+++ b/include/mgl/system/utf8.h
@@ -5,13 +5,7 @@
#include <stdint.h>
#include <stdbool.h>
-bool mgl_utf8_is_valid(const unsigned char *str, size_t size);
-
-/*
- Returns the byte length of the decoded codepoint.
- Note: does not validate if the input |str| is a valid utf8 string.
-*/
-size_t mgl_utf8_decode(const unsigned char *str, uint32_t *decoded_codepoint);
+bool mgl_utf8_decode(const unsigned char *str, size_t size, uint32_t *decoded_codepoint, size_t *codepoint_length);
#endif /* MGL_UTF8_H */
diff --git a/include/mgl/window/key.h b/include/mgl/window/key.h
index 90a3366..0cd3c03 100644
--- a/include/mgl/window/key.h
+++ b/include/mgl/window/key.h
@@ -103,7 +103,10 @@ typedef enum {
MGL_KEY_F13,
MGL_KEY_F14,
MGL_KEY_F15,
- MGL_KEY_PAUSE
+ MGL_KEY_PAUSE,
+
+ /* This should always be the last key */
+ __MGL_NUM_KEYS__
} mgl_key;
#endif /* _MGL_KEY_H_ */
diff --git a/include/mgl/window/window.h b/include/mgl/window/window.h
index 9d7086c..c6fce87 100644
--- a/include/mgl/window/window.h
+++ b/include/mgl/window/window.h
@@ -3,6 +3,7 @@
#include "../graphics/color.h"
#include "../system/vec.h"
+#include "key.h"
#include <stdbool.h>
/* Vsync is automatically set for created windows, if supported by the system */
@@ -48,5 +49,6 @@ void mgl_window_set_view(mgl_window *self, mgl_view *new_view);
void mgl_window_get_view(mgl_window *self, mgl_view *view);
bool mgl_window_is_open(const mgl_window *self);
+bool mgl_window_is_key_pressed(const mgl_window *self, mgl_key key);
#endif /* MGL_WINDOW_H */
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);
+}