X11: fix XIM input method support
This commit is contained in:
parent
e458f4651e
commit
2567551469
@ -40,6 +40,8 @@ namespace
|
|||||||
// The shared display and its reference counter
|
// The shared display and its reference counter
|
||||||
Display* sharedDisplay = NULL;
|
Display* sharedDisplay = NULL;
|
||||||
unsigned int referenceCount = 0;
|
unsigned int referenceCount = 0;
|
||||||
|
XIM sharedXIM = NULL;
|
||||||
|
unsigned int referenceCountXIM = 0;
|
||||||
sf::Mutex mutex;
|
sf::Mutex mutex;
|
||||||
|
|
||||||
typedef std::map<std::string, Atom> AtomMap;
|
typedef std::map<std::string, Atom> AtomMap;
|
||||||
@ -85,6 +87,56 @@ void CloseDisplay(Display* display)
|
|||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
XIM OpenXIM()
|
||||||
|
{
|
||||||
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
assert(sharedDisplay != NULL);
|
||||||
|
|
||||||
|
if (referenceCountXIM == 0)
|
||||||
|
{
|
||||||
|
// Create a new XIM instance
|
||||||
|
|
||||||
|
// We need the default (environment) locale and X locale for opening
|
||||||
|
// the IM and properly receiving text
|
||||||
|
// First save the previous ones (this might be able to be written more elegantly?)
|
||||||
|
const char* p;
|
||||||
|
std::string prevLoc((p = setlocale(LC_ALL, NULL)) ? p : "");
|
||||||
|
std::string prevXLoc((p = XSetLocaleModifiers(NULL)) ? p : "");
|
||||||
|
|
||||||
|
// Set the locales from environment
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
|
||||||
|
// Create the input context
|
||||||
|
sharedXIM = XOpenIM(sharedDisplay, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
// Restore the previous locale
|
||||||
|
if (prevLoc.length() != 0)
|
||||||
|
setlocale(LC_ALL, prevLoc.c_str());
|
||||||
|
|
||||||
|
if (prevXLoc.length() != 0)
|
||||||
|
XSetLocaleModifiers(prevXLoc.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceCountXIM++;
|
||||||
|
|
||||||
|
return sharedXIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void CloseXIM(XIM xim)
|
||||||
|
{
|
||||||
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
assert(xim == sharedXIM);
|
||||||
|
|
||||||
|
referenceCountXIM--;
|
||||||
|
|
||||||
|
if ((referenceCountXIM == 0) && (xim != NULL))
|
||||||
|
XCloseIM(xim);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Atom getAtom(const std::string& name, bool onlyIfExists)
|
Atom getAtom(const std::string& name, bool onlyIfExists)
|
||||||
|
@ -55,6 +55,27 @@ Display* OpenDisplay();
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void CloseDisplay(Display* display);
|
void CloseDisplay(Display* display);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the shared XIM context for the Display
|
||||||
|
///
|
||||||
|
/// This function increments the reference count of the XIM context,
|
||||||
|
/// it must be matched with a call to CloseXIM.
|
||||||
|
///
|
||||||
|
/// It must be called with a display already opened.
|
||||||
|
///
|
||||||
|
/// \return XIM handle (a pointer) of the context
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
XIM OpenXIM();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Release a reference to the shared XIM context
|
||||||
|
///
|
||||||
|
/// \param xim XIM context to release
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void CloseXIM(XIM xim);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get the atom with the specified name
|
/// \brief Get the atom with the specified name
|
||||||
///
|
///
|
||||||
|
@ -101,7 +101,9 @@ namespace
|
|||||||
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
||||||
{
|
{
|
||||||
// Just check if the event matches the window
|
// Just check if the event matches the window
|
||||||
return event->xany.window == reinterpret_cast< ::Window >(userData);
|
// The input method sometimes sends ClientMessages with a different window ID,
|
||||||
|
// our event loop has to process them for the IM to work
|
||||||
|
return (event->xany.window == reinterpret_cast< ::Window >(userData)) || (event->type == ClientMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the name of the current executable
|
// Find the name of the current executable
|
||||||
@ -803,7 +805,7 @@ WindowImplX11::~WindowImplX11()
|
|||||||
|
|
||||||
// Close the input method
|
// Close the input method
|
||||||
if (m_inputMethod)
|
if (m_inputMethod)
|
||||||
XCloseIM(m_inputMethod);
|
CloseXIM(m_inputMethod);
|
||||||
|
|
||||||
// Close the connection with the X server
|
// Close the connection with the X server
|
||||||
CloseDisplay(m_display);
|
CloseDisplay(m_display);
|
||||||
@ -1607,7 +1609,7 @@ void WindowImplX11::initialize()
|
|||||||
using namespace WindowsImplX11Impl;
|
using namespace WindowsImplX11Impl;
|
||||||
|
|
||||||
// Create the input context
|
// Create the input context
|
||||||
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
|
m_inputMethod = OpenXIM();
|
||||||
|
|
||||||
if (m_inputMethod)
|
if (m_inputMethod)
|
||||||
{
|
{
|
||||||
@ -1844,6 +1846,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
|
|
||||||
// Close event
|
// Close event
|
||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
|
{
|
||||||
|
// Input methods might want random ClientMessage events
|
||||||
|
if (!XFilterEvent(&windowEvent, None))
|
||||||
{
|
{
|
||||||
static Atom wmProtocols = getAtom("WM_PROTOCOLS");
|
static Atom wmProtocols = getAtom("WM_PROTOCOLS");
|
||||||
|
|
||||||
@ -1868,6 +1873,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent);
|
XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1904,7 +1910,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
if (m_inputContext)
|
if (m_inputContext)
|
||||||
{
|
{
|
||||||
Status status;
|
Status status;
|
||||||
Uint8 keyBuffer[16];
|
Uint8 keyBuffer[64];
|
||||||
|
|
||||||
int length = Xutf8LookupString(
|
int length = Xutf8LookupString(
|
||||||
m_inputContext,
|
m_inputContext,
|
||||||
@ -1915,10 +1921,19 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
&status
|
&status
|
||||||
);
|
);
|
||||||
|
|
||||||
if (length > 0)
|
if (status == XBufferOverflow)
|
||||||
|
err() << "A TextEntered event has more than 64 bytes of UTF-8 input, and "
|
||||||
|
"has been discarded\nThis means either you have typed a very long string "
|
||||||
|
"(more than 20 chars), or your input method is broken in obscure ways." << std::endl;
|
||||||
|
else if (status == XLookupChars)
|
||||||
{
|
{
|
||||||
|
// There might be more than 1 characters in this event,
|
||||||
|
// so we must iterate it
|
||||||
Uint32 unicode = 0;
|
Uint32 unicode = 0;
|
||||||
Utf8::decode(keyBuffer, keyBuffer + length, unicode, 0);
|
Uint8* iter = keyBuffer;
|
||||||
|
while (iter < keyBuffer + length)
|
||||||
|
{
|
||||||
|
iter = Utf8::decode(iter, keyBuffer + length, unicode, 0);
|
||||||
if (unicode != 0)
|
if (unicode != 0)
|
||||||
{
|
{
|
||||||
Event textEvent;
|
Event textEvent;
|
||||||
@ -1928,6 +1943,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user