Add support for IMEs on Linux

This commit is contained in:
yw05 2021-03-30 13:52:45 +02:00 committed by sfan5
parent 32004b9c5f
commit 3ef5902815

@ -13,6 +13,7 @@
#include <locale.h> #include <locale.h>
#include "IEventReceiver.h" #include "IEventReceiver.h"
#include "ISceneManager.h" #include "ISceneManager.h"
#include "IGUIElement.h"
#include "IGUIEnvironment.h" #include "IGUIEnvironment.h"
#include "os.h" #include "os.h"
#include "CTimer.h" #include "CTimer.h"
@ -705,6 +706,14 @@ bool CIrrDeviceLinux::createInputContext()
return false; return false;
} }
// Load XMODIFIERS (e.g. for IMEs)
if (!XSetLocaleModifiers(""))
{
setlocale(LC_CTYPE, oldLocale.c_str());
os::Printer::log("XSetLocaleModifiers failed. Falling back to non-i18n input.", ELL_WARNING);
return false;
}
XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL); XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL);
if ( !XInputMethod ) if ( !XInputMethod )
{ {
@ -820,7 +829,7 @@ bool CIrrDeviceLinux::run()
{ {
XEvent event; XEvent event;
XNextEvent(XDisplay, &event); XNextEvent(XDisplay, &event);
if (XFilterEvent(&event, XWindow)) if (acceptsIME() && XFilterEvent(&event, None))
continue; continue;
switch (event.type) switch (event.type)
@ -998,19 +1007,30 @@ bool CIrrDeviceLinux::run()
SKeyMap mp; SKeyMap mp;
if ( XInputContext ) if ( XInputContext )
{ {
wchar_t buf[8]={0}; wchar_t buf[64]={0};
Status status; Status status;
int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf), &mp.X11Key, &status); int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf)/sizeof(wchar_t)-1, &mp.X11Key, &status);
if ( status == XBufferOverflow ) if ( status == XBufferOverflow )
{ {
os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION); os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION);
} }
if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) ) if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) )
{ {
if ( strLen > 1 ) if (strLen > 1)
os::Printer::log("Additional returned characters dropped", ELL_INFORMATION); {
// Multiple characters: send string event
irrevent.EventType = irr::EET_STRING_INPUT_EVENT;
irrevent.StringInput.Str = new core::stringw(buf);
postEventFromUser(irrevent);
delete irrevent.StringInput.Str;
irrevent.StringInput.Str = NULL;
break;
}
else
{
irrevent.KeyInput.Char = buf[0]; irrevent.KeyInput.Char = buf[0];
} }
}
else else
{ {
#if 0 // Most of those are fine - but useful to have the info when debugging Irrlicht itself. #if 0 // Most of those are fine - but useful to have the info when debugging Irrlicht itself.
@ -1044,7 +1064,6 @@ bool CIrrDeviceLinux::run()
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0; irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0; irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
irrevent.KeyInput.Key = getKeyCode(event); irrevent.KeyInput.Key = getKeyCode(event);
postEventFromUser(irrevent); postEventFromUser(irrevent);
} }
break; break;
@ -1138,6 +1157,22 @@ bool CIrrDeviceLinux::run()
} // end switch } // end switch
} // end while } // end while
// Update IME information
if (GUIEnvironment)
{
gui::IGUIElement *elem = GUIEnvironment->getFocus();
if (elem && elem->acceptsIME())
{
core::rect<s32> r = elem->getAbsolutePosition();
XPoint p;
p.x = (short)r.UpperLeftCorner.X;
p.y = (short)r.LowerRightCorner.Y;
XVaNestedList l = XVaCreateNestedList(0, XNSpotLocation, &p, NULL);
XSetICValues(XInputContext, XNPreeditAttributes, l, NULL);
XFree(l);
}
}
} }
#endif //_IRR_COMPILE_WITH_X11_ #endif //_IRR_COMPILE_WITH_X11_