|
@@ -97,15 +97,54 @@ static int translateKey(int keycode)
|
|
|
|
|
|
// Translates an X Window event to Unicode
|
|
|
//
|
|
|
-static int translateChar(XKeyEvent* event)
|
|
|
+static wchar_t * translateChar(XEvent * event, _GLFWwindow * window, int * count)
|
|
|
{
|
|
|
KeySym keysym;
|
|
|
+ static wchar_t buffer[16];
|
|
|
|
|
|
- // Get X11 keysym
|
|
|
- XLookupString(event, NULL, 0, &keysym, NULL);
|
|
|
+ // If there is no input method / context available, use the old fallback
|
|
|
+ // mechanism
|
|
|
+ if (!window || !window->x11.ic)
|
|
|
+ {
|
|
|
+ long uc;
|
|
|
+
|
|
|
+ // Get X11 keysym
|
|
|
+ XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
|
|
|
+
|
|
|
+ // Convert to Unicode (see x11_unicode.c)
|
|
|
+ uc = _glfwKeySym2Unicode(keysym);
|
|
|
+ if (uc < 0 || uc > 0xFFFF)
|
|
|
+ {
|
|
|
+ *count = 0;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ buffer[0] = (unsigned int)uc;
|
|
|
+ *count = 1;
|
|
|
+ }
|
|
|
+ // Else lookup the wide char string with respect to dead characters
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Status dummy;
|
|
|
+
|
|
|
+ // Check if the given event is a dead char. In that case, it does not
|
|
|
+ // produce a unicode char.
|
|
|
+ if (XFilterEvent(event, None))
|
|
|
+ {
|
|
|
+ *count = 0;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Retrieve unicode string
|
|
|
+ *count = XwcLookupString(window->x11.ic, &event->xkey, buffer, 16 * sizeof(wchar_t), 0, &dummy);
|
|
|
+ if (*count < 0)
|
|
|
+ {
|
|
|
+ *count = 0;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Convert to Unicode (see x11_unicode.c)
|
|
|
- return (int) _glfwKeySym2Unicode(keysym);
|
|
|
+ return buffer;
|
|
|
}
|
|
|
|
|
|
// Return the GLFW window corresponding to the specified X11 window
|
|
@@ -201,6 +240,8 @@ static GLboolean createWindow(_GLFWwindow* window,
|
|
|
unsigned long wamask;
|
|
|
XSetWindowAttributes wa;
|
|
|
XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
|
|
|
+
|
|
|
+ window->x11.ic = NULL;
|
|
|
|
|
|
// Every window needs a colormap
|
|
|
// Create one based on the visual used by the current context
|
|
@@ -436,6 +477,13 @@ static GLboolean createWindow(_GLFWwindow* window,
|
|
|
|
|
|
XRRSelectInput(_glfw.x11.display, window->x11.handle,
|
|
|
RRScreenChangeNotifyMask);
|
|
|
+
|
|
|
+ // Try to create an input context. If this function returns NULL, ic is
|
|
|
+ // set to NULL and we know we have to use fallback mechanisms to parse
|
|
|
+ // char events.
|
|
|
+ window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle,
|
|
|
+ XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
|
|
+ window->x11.handle, XNFocusWindow, window->x11.handle, NULL);
|
|
|
|
|
|
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
|
|
|
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
|
|
@@ -828,16 +876,20 @@ static void processEvent(XEvent *event)
|
|
|
{
|
|
|
case KeyPress:
|
|
|
{
|
|
|
+ int i, n_chars;
|
|
|
const int key = translateKey(event->xkey.keycode);
|
|
|
const int mods = translateState(event->xkey.state);
|
|
|
- const int character = translateChar(&event->xkey);
|
|
|
+ const wchar_t * characters = translateChar(event, window, &n_chars);
|
|
|
|
|
|
_glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
|
|
|
|
|
|
- if (character != -1)
|
|
|
+ for (i = 0; i < n_chars; i++)
|
|
|
{
|
|
|
- const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
|
|
- _glfwInputChar(window, character, mods, plain);
|
|
|
+ if (characters[i] != -1)
|
|
|
+ {
|
|
|
+ const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
|
|
+ _glfwInputChar(window, (unsigned int)characters[i], mods, plain);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
break;
|
|
@@ -1366,6 +1418,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|
|
{
|
|
|
if (window->monitor)
|
|
|
leaveFullscreenMode(window);
|
|
|
+
|
|
|
+ if (window->x11.ic)
|
|
|
+ {
|
|
|
+ XDestroyIC(window->x11.ic);
|
|
|
+ window->x11.ic = NULL;
|
|
|
+ }
|
|
|
|
|
|
_glfwDestroyContext(window);
|
|
|
|