mirror of
https://github.com/glfw/glfw.git
synced 2024-11-29 21:37:27 +00:00
Fixed dead keys in X11.
The library will now try to create an X input context to handle dead keys properly on international keyboards. This makes it possible to enter for example an e with accent grave on a German keyboard without further efforts. A fallback mechanism is provided in case the client does not support X input method / context creation. In that case, the library will behave as it did before.
This commit is contained in:
parent
49579165a7
commit
cec63f3cb5
@ -449,6 +449,9 @@ static void detectEWMH(void)
|
||||
//
|
||||
static GLboolean initExtensions(void)
|
||||
{
|
||||
unsigned int u;
|
||||
XIMStyles * styles = NULL;
|
||||
|
||||
// Find or create window manager atoms
|
||||
_glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
|
||||
"WM_PROTOCOLS",
|
||||
@ -579,6 +582,43 @@ static GLboolean initExtensions(void)
|
||||
_glfw.x11.SAVE_TARGETS =
|
||||
XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Optional extensions (function returns always true from here!)
|
||||
|
||||
// Open input method
|
||||
if (!XSupportsLocale())
|
||||
return GL_TRUE;
|
||||
|
||||
XSetLocaleModifiers("");
|
||||
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
|
||||
if (!_glfw.x11.im)
|
||||
return GL_TRUE;
|
||||
|
||||
// Get available input styles
|
||||
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) || !styles)
|
||||
{
|
||||
XCloseIM(_glfw.x11.im);
|
||||
_glfw.x11.im = NULL;
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
// Search for needed input style
|
||||
for (u = 0; u < styles->count_styles; u++)
|
||||
{
|
||||
if (styles->supported_styles[u] == (XIMPreeditNothing | XIMStatusNothing))
|
||||
break;
|
||||
}
|
||||
|
||||
if (u >= styles->count_styles)
|
||||
{
|
||||
XFree(styles);
|
||||
XCloseIM(_glfw.x11.im);
|
||||
_glfw.x11.im = NULL;
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
XFree(styles);
|
||||
|
||||
// Find Xdnd (drag and drop) atoms, if available
|
||||
_glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
|
||||
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
|
||||
@ -686,6 +726,8 @@ int _glfwPlatformInit(void)
|
||||
{
|
||||
XInitThreads();
|
||||
|
||||
_glfw.x11.im = NULL;
|
||||
|
||||
_glfw.x11.display = XOpenDisplay(NULL);
|
||||
if (!_glfw.x11.display)
|
||||
{
|
||||
@ -721,6 +763,12 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
free(_glfw.x11.clipboardString);
|
||||
|
||||
if (_glfw.x11.im)
|
||||
{
|
||||
XCloseIM(_glfw.x11.im);
|
||||
_glfw.x11.im = NULL;
|
||||
}
|
||||
|
||||
_glfwTerminateJoysticks();
|
||||
_glfwTerminateContextAPI();
|
||||
|
||||
|
@ -90,6 +90,8 @@ typedef struct _GLFWwindowX11
|
||||
// The last position the cursor was warped to by GLFW
|
||||
int warpPosX, warpPosY;
|
||||
|
||||
// The window's input context
|
||||
XIC ic;
|
||||
} _GLFWwindowX11;
|
||||
|
||||
|
||||
@ -202,6 +204,9 @@ typedef struct _GLFWlibraryX11
|
||||
Window source;
|
||||
} xdnd;
|
||||
|
||||
// Input method and context
|
||||
XIM im;
|
||||
|
||||
} _GLFWlibraryX11;
|
||||
|
||||
|
||||
|
@ -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];
|
||||
|
||||
// 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, NULL, 0, &keysym, NULL);
|
||||
XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
|
||||
|
||||
// Convert to Unicode (see x11_unicode.c)
|
||||
return (int) _glfwKeySym2Unicode(keysym);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Return the GLFW window corresponding to the specified X11 window
|
||||
@ -202,6 +241,8 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
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
|
||||
// TODO: Decouple this from context creation
|
||||
@ -437,6 +478,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++)
|
||||
{
|
||||
if (characters[i] != -1)
|
||||
{
|
||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
_glfwInputChar(window, character, mods, plain);
|
||||
_glfwInputChar(window, (unsigned int)characters[i], mods, plain);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1367,6 +1419,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
if (window->monitor)
|
||||
leaveFullscreenMode(window);
|
||||
|
||||
if (window->x11.ic)
|
||||
{
|
||||
XDestroyIC(window->x11.ic);
|
||||
window->x11.ic = NULL;
|
||||
}
|
||||
|
||||
_glfwDestroyContext(window);
|
||||
|
||||
if (window->x11.handle)
|
||||
|
Loading…
Reference in New Issue
Block a user