mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 21:14:35 +00:00
Cleanup of basic XIM support.
Shortened and simplified the code. Removed reporting of XIM sentinel key press event. Added credit. Updated changelog. Closes #151.
This commit is contained in:
parent
cec63f3cb5
commit
c769061a8a
@ -118,6 +118,7 @@ GLFW bundles a number of dependencies in the `deps/` directory.
|
|||||||
- [X11] Bugfix: Workaround for legacy Compiz caused flickering during resize
|
- [X11] Bugfix: Workaround for legacy Compiz caused flickering during resize
|
||||||
- [X11] Bugfix: The name pointer of joysticks were not cleared on disconnection
|
- [X11] Bugfix: The name pointer of joysticks were not cleared on disconnection
|
||||||
- [X11] Bugfix: Video mode dimensions were not rotated to match the CRTC
|
- [X11] Bugfix: Video mode dimensions were not rotated to match the CRTC
|
||||||
|
- [X11] Bugfix: Unicode character input ignored dead keys
|
||||||
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
@ -174,6 +175,7 @@ skills.
|
|||||||
- Sylvain Hellegouarch
|
- Sylvain Hellegouarch
|
||||||
- Matthew Henry
|
- Matthew Henry
|
||||||
- heromyth
|
- heromyth
|
||||||
|
- Lucas Hinderberger
|
||||||
- Paul Holden
|
- Paul Holden
|
||||||
- Toni Jovanoski
|
- Toni Jovanoski
|
||||||
- Arseny Kapoulkine
|
- Arseny Kapoulkine
|
||||||
|
@ -329,6 +329,30 @@ static void updateKeyCodeLUT(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether the IM has a usable style
|
||||||
|
//
|
||||||
|
static GLboolean hasUsableInputMethodStyle(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
GLboolean found = GL_FALSE;
|
||||||
|
XIMStyles* styles = NULL;
|
||||||
|
|
||||||
|
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < styles->count_styles; i++)
|
||||||
|
{
|
||||||
|
if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
|
||||||
|
{
|
||||||
|
found = GL_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(styles);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether the specified atom is supported
|
// Check whether the specified atom is supported
|
||||||
//
|
//
|
||||||
static Atom getSupportedAtom(Atom* supportedAtoms,
|
static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||||
@ -449,9 +473,6 @@ static void detectEWMH(void)
|
|||||||
//
|
//
|
||||||
static GLboolean initExtensions(void)
|
static GLboolean initExtensions(void)
|
||||||
{
|
{
|
||||||
unsigned int u;
|
|
||||||
XIMStyles * styles = NULL;
|
|
||||||
|
|
||||||
// Find or create window manager atoms
|
// Find or create window manager atoms
|
||||||
_glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
|
_glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display,
|
||||||
"WM_PROTOCOLS",
|
"WM_PROTOCOLS",
|
||||||
@ -582,43 +603,6 @@ static GLboolean initExtensions(void)
|
|||||||
_glfw.x11.SAVE_TARGETS =
|
_glfw.x11.SAVE_TARGETS =
|
||||||
XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
|
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
|
// Find Xdnd (drag and drop) atoms, if available
|
||||||
_glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
|
_glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
|
||||||
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
|
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
|
||||||
@ -726,8 +710,6 @@ int _glfwPlatformInit(void)
|
|||||||
{
|
{
|
||||||
XInitThreads();
|
XInitThreads();
|
||||||
|
|
||||||
_glfw.x11.im = NULL;
|
|
||||||
|
|
||||||
_glfw.x11.display = XOpenDisplay(NULL);
|
_glfw.x11.display = XOpenDisplay(NULL);
|
||||||
if (!_glfw.x11.display)
|
if (!_glfw.x11.display)
|
||||||
{
|
{
|
||||||
@ -744,6 +726,21 @@ int _glfwPlatformInit(void)
|
|||||||
|
|
||||||
_glfw.x11.cursor = createNULLCursor();
|
_glfw.x11.cursor = createNULLCursor();
|
||||||
|
|
||||||
|
if (XSupportsLocale())
|
||||||
|
{
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
|
||||||
|
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
|
||||||
|
if (_glfw.x11.im)
|
||||||
|
{
|
||||||
|
if (!hasUsableInputMethodStyle())
|
||||||
|
{
|
||||||
|
XCloseIM(_glfw.x11.im);
|
||||||
|
_glfw.x11.im = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!_glfwInitContextAPI())
|
if (!_glfwInitContextAPI())
|
||||||
return GL_FALSE;
|
return GL_FALSE;
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ typedef struct _GLFWwindowX11
|
|||||||
{
|
{
|
||||||
Colormap colormap;
|
Colormap colormap;
|
||||||
Window handle;
|
Window handle;
|
||||||
|
XIC ic;
|
||||||
|
|
||||||
GLboolean overrideRedirect;
|
GLboolean overrideRedirect;
|
||||||
|
|
||||||
@ -90,8 +91,6 @@ typedef struct _GLFWwindowX11
|
|||||||
// The last position the cursor was warped to by GLFW
|
// The last position the cursor was warped to by GLFW
|
||||||
int warpPosX, warpPosY;
|
int warpPosX, warpPosY;
|
||||||
|
|
||||||
// The window's input context
|
|
||||||
XIC ic;
|
|
||||||
} _GLFWwindowX11;
|
} _GLFWwindowX11;
|
||||||
|
|
||||||
|
|
||||||
@ -107,6 +106,8 @@ typedef struct _GLFWlibraryX11
|
|||||||
Cursor cursor;
|
Cursor cursor;
|
||||||
// Context for mapping window XIDs to _GLFWwindow pointers
|
// Context for mapping window XIDs to _GLFWwindow pointers
|
||||||
XContext context;
|
XContext context;
|
||||||
|
// XIM input method
|
||||||
|
XIM im;
|
||||||
// True if window manager supports EWMH
|
// True if window manager supports EWMH
|
||||||
GLboolean hasEWMH;
|
GLboolean hasEWMH;
|
||||||
// Most recent error code received by X error handler
|
// Most recent error code received by X error handler
|
||||||
@ -204,9 +205,6 @@ typedef struct _GLFWlibraryX11
|
|||||||
Window source;
|
Window source;
|
||||||
} xdnd;
|
} xdnd;
|
||||||
|
|
||||||
// Input method and context
|
|
||||||
XIM im;
|
|
||||||
|
|
||||||
} _GLFWlibraryX11;
|
} _GLFWlibraryX11;
|
||||||
|
|
||||||
|
|
||||||
|
108
src/x11_window.c
108
src/x11_window.c
@ -95,58 +95,6 @@ static int translateKey(int keycode)
|
|||||||
return _glfw.x11.keyCodeLUT[keycode];
|
return _glfw.x11.keyCodeLUT[keycode];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translates an X Window event to Unicode
|
|
||||||
//
|
|
||||||
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->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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the GLFW window corresponding to the specified X11 window
|
// Return the GLFW window corresponding to the specified X11 window
|
||||||
//
|
//
|
||||||
static _GLFWwindow* findWindowByHandle(Window handle)
|
static _GLFWwindow* findWindowByHandle(Window handle)
|
||||||
@ -241,8 +189,6 @@ static GLboolean createWindow(_GLFWwindow* window,
|
|||||||
XSetWindowAttributes wa;
|
XSetWindowAttributes wa;
|
||||||
XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
|
XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
|
||||||
|
|
||||||
window->x11.ic = NULL;
|
|
||||||
|
|
||||||
// Every window needs a colormap
|
// Every window needs a colormap
|
||||||
// Create one based on the visual used by the current context
|
// Create one based on the visual used by the current context
|
||||||
// TODO: Decouple this from context creation
|
// TODO: Decouple this from context creation
|
||||||
@ -478,12 +424,17 @@ static GLboolean createWindow(_GLFWwindow* window,
|
|||||||
XRRSelectInput(_glfw.x11.display, window->x11.handle,
|
XRRSelectInput(_glfw.x11.display, window->x11.handle,
|
||||||
RRScreenChangeNotifyMask);
|
RRScreenChangeNotifyMask);
|
||||||
|
|
||||||
// Try to create an input context. If this function returns NULL, ic is
|
if (_glfw.x11.im)
|
||||||
// set to NULL and we know we have to use fallback mechanisms to parse
|
{
|
||||||
// char events.
|
window->x11.ic = XCreateIC(_glfw.x11.im,
|
||||||
window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle,
|
XNInputStyle,
|
||||||
XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
XIMPreeditNothing | XIMStatusNothing,
|
||||||
window->x11.handle, XNFocusWindow, window->x11.handle, NULL);
|
XNClientWindow,
|
||||||
|
window->x11.handle,
|
||||||
|
XNFocusWindow,
|
||||||
|
window->x11.handle,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
|
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
|
||||||
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
|
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
|
||||||
@ -876,20 +827,45 @@ static void processEvent(XEvent *event)
|
|||||||
{
|
{
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
{
|
{
|
||||||
int i, n_chars;
|
|
||||||
const int key = translateKey(event->xkey.keycode);
|
const int key = translateKey(event->xkey.keycode);
|
||||||
const int mods = translateState(event->xkey.state);
|
const int mods = translateState(event->xkey.state);
|
||||||
const wchar_t * characters = translateChar(event, window, &n_chars);
|
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||||
|
|
||||||
|
if (event->xkey.keycode)
|
||||||
_glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
|
_glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
|
||||||
|
|
||||||
for (i = 0; i < n_chars; i++)
|
if (window->x11.ic)
|
||||||
{
|
{
|
||||||
if (characters[i] != -1)
|
// Translate keys to characters with XIM input context
|
||||||
|
|
||||||
|
int i;
|
||||||
|
Status status;
|
||||||
|
wchar_t buffer[16];
|
||||||
|
|
||||||
|
if (XFilterEvent(event, None))
|
||||||
{
|
{
|
||||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
// Discard intermediary (dead key) events for character input
|
||||||
_glfwInputChar(window, (unsigned int)characters[i], mods, plain);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int count = XwcLookupString(window->x11.ic,
|
||||||
|
&event->xkey,
|
||||||
|
buffer, sizeof(buffer),
|
||||||
|
NULL, &status);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
_glfwInputChar(window, buffer[i], mods, plain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Translate keys to characters with fallback lookup table
|
||||||
|
|
||||||
|
KeySym keysym;
|
||||||
|
XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
|
||||||
|
|
||||||
|
const long character = _glfwKeySym2Unicode(keysym);
|
||||||
|
if (character != -1)
|
||||||
|
_glfwInputChar(window, character, mods, plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user