From 3526bf913402b4061fd19b2f77b9f1dd1a60b2a5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 20 Jul 2019 11:19:02 +0200 Subject: Unify key and character fields and separate text events Only one field is necessary to store any kind of key, including special keys, since PuglKey occupies a reserved Unicode region. This is generally much simpler to deal with since there is only one value to dispatch on. Text events are separated from key events (like Windows but unlike MacOS or X11) because it is not possible to derive text events from key press events when they occur on Windows. Since merging the two has been the source of some confusion, this approach has some advantages anyway, even though it introduces the need to handle another event type. In the process, text input has been almost completely rewritten. I have tested this with a compose key on X11 and dead keys on Windows and MacOS and everything seems to work correctly, though there may (as always) still be issues with more exotic input methods. --- pugl/pugl_x11.c | 67 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'pugl/pugl_x11.c') diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c index d5e51b4..f10902f 100644 --- a/pugl/pugl_x11.c +++ b/pugl/pugl_x11.c @@ -253,34 +253,55 @@ keySymToSpecial(KeySym sym) return (PuglKey)0; } -static void -translateKey(PuglView* view, XEvent* xevent, PuglEventKey* event) +static int +lookupString(XIC xic, XEvent* xevent, char* str, KeySym* sym) { - KeySym sym = 0; - memset(event->string, 0, 8); - event->filter = XFilterEvent(xevent, None); - if (xevent->type == KeyRelease || event->filter || !view->impl->xic) { - if (XLookupString(&xevent->xkey, event->string, 7, &sym, NULL) == 1) { - event->character = (uint8_t)event->string[0]; - } - } else { - /* TODO: Not sure about this. On my system, some characters work with - Xutf8LookupString but not with XmbLookupString, and some are the - opposite. */ - Status status = 0; + Status status = 0; + #ifdef X_HAVE_UTF8_STRING - const int n = Xutf8LookupString( - view->impl->xic, &xevent->xkey, event->string, 7, &sym, &status); + const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status); #else - const int n = XmbLookupString( - view->impl->xic, &xevent->xkey, event->string, 7, &sym, &status); + const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status); #endif - if (n > 0) { - event->character = puglDecodeUTF8((const uint8_t*)event->string); + + return status == XBufferOverflow ? 0 : n; +} + +static void +translateKey(PuglView* view, XEvent* xevent, PuglEvent* event) +{ + const unsigned state = xevent->xkey.state; + const bool filter = XFilterEvent(xevent, None); + + event->key.keycode = xevent->xkey.keycode; + xevent->xkey.state = 0; + + // Lookup unshifted key + char ustr[8] = {0}; + KeySym sym = 0; + const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL); + const PuglKey special = keySymToSpecial(sym); + + event->key.key = ((special || ufound <= 0) + ? special + : puglDecodeUTF8((const uint8_t*)ustr)); + + if (xevent->type == KeyPress && !filter && !special) { + // Lookup shifted key for possible text event + xevent->xkey.state = state; + + char sstr[8] = {0}; + const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym); + if (sfound > 0) { + // Dispatch key event now + puglDispatchEvent(view, event); + + // "Return" a text event in its place + event->text.type = PUGL_TEXT; + event->text.character = puglDecodeUTF8((const uint8_t*)sstr); + memcpy(event->text.string, sstr, sizeof(sstr)); } } - event->special = keySymToSpecial(sym); - event->keycode = xevent->xkey.keycode; } static uint32_t @@ -387,7 +408,7 @@ translateEvent(PuglView* view, XEvent xevent) event.key.x_root = xevent.xkey.x_root; event.key.y_root = xevent.xkey.y_root; event.key.state = translateModifiers(xevent.xkey.state); - translateKey(view, &xevent, &event.key); + translateKey(view, &xevent, &event); break; case EnterNotify: case LeaveNotify: -- cgit v1.2.1