From a84c3ffec4eaa4fe782f6ff16f1fb00301dd66a6 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 26 Dec 2003 23:00:28 +0000 Subject: [PATCH] better internationalization input support --- panda/src/glxdisplay/glxGraphicsPipe.I | 12 ++++++ panda/src/glxdisplay/glxGraphicsPipe.cxx | 32 +++++++++++++++ panda/src/glxdisplay/glxGraphicsPipe.h | 4 ++ panda/src/glxdisplay/glxGraphicsWindow.cxx | 46 ++++++++++++++++++---- panda/src/glxdisplay/glxGraphicsWindow.h | 2 + 5 files changed, 89 insertions(+), 7 deletions(-) diff --git a/panda/src/glxdisplay/glxGraphicsPipe.I b/panda/src/glxdisplay/glxGraphicsPipe.I index 677a761288..2501bdc96c 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.I +++ b/panda/src/glxdisplay/glxGraphicsPipe.I @@ -59,3 +59,15 @@ INLINE Atom glxGraphicsPipe:: get_wm_delete_window() const { return _wm_delete_window; } + +//////////////////////////////////////////////////////////////////// +// Function: glxGraphicsPipe::get_im +// Access: Public +// Description: Returns the input method opened for the pipe, or NULL +// if the input method could not be opened for some +// reason. +//////////////////////////////////////////////////////////////////// +INLINE XIM glxGraphicsPipe:: +get_im() const { + return _im; +} diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index 22116716a9..0989d48dd4 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -46,6 +46,8 @@ glxGraphicsPipe(const string &display) { display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY"); } + setlocale(LC_ALL, ""); + _is_valid = false; _supports_fullscreen = false; _display = NULL; @@ -61,6 +63,12 @@ glxGraphicsPipe(const string &display) { return; } + if (!XSupportsLocale()) { + glxdisplay_cat.warning() + << "X does not support locale " << setlocale(LC_ALL, NULL) << "\n"; + } + XSetLocaleModifiers(""); + int errorBase, eventBase; if (!glXQueryExtension(_display, &errorBase, &eventBase)) { glxdisplay_cat.error() @@ -75,6 +83,27 @@ glxGraphicsPipe(const string &display) { _display_height = DisplayHeight(_display, _screen); _is_valid = true; + // Connect to an input method for supporting international text + // entry. + _im = XOpenIM(_display, NULL, NULL, NULL); + if (_im == (XIM)NULL) { + glxdisplay_cat.warning() + << "Couldn't open input method.\n"; + } + + // What styles does the current input method support? + /* + XIMStyles *im_supported_styles; + XGetIMValues(_im, XNQueryInputStyle, &im_supported_styles, NULL); + + for (int i = 0; i < im_supported_styles->count_styles; i++) { + XIMStyle style = im_supported_styles->supported_styles[i]; + cerr << "style " << i << ". " << hex << style << dec << "\n"; + } + + XFree(im_supported_styles); + */ + // Get the X atom number. _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false); } @@ -86,6 +115,9 @@ glxGraphicsPipe(const string &display) { //////////////////////////////////////////////////////////////////// glxGraphicsPipe:: ~glxGraphicsPipe() { + if (_im) { + XCloseIM(_im); + } if (_display) { XCloseDisplay(_display); } diff --git a/panda/src/glxdisplay/glxGraphicsPipe.h b/panda/src/glxdisplay/glxGraphicsPipe.h index e4a3c6a05e..aca330f271 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.h +++ b/panda/src/glxdisplay/glxGraphicsPipe.h @@ -32,6 +32,8 @@ typedef int Window; typedef int XErrorEvent; typedef int XVisualInfo; typedef int Atom; +typedef int XIM; +typedef int XIC; #else #include #include @@ -54,6 +56,7 @@ public: INLINE Display *get_display() const; INLINE int get_screen() const; INLINE Window get_root() const; + INLINE XIM get_im() const; INLINE Atom get_wm_delete_window() const; @@ -73,6 +76,7 @@ private: Display *_display; int _screen; Window _root; + XIM _im; Atom _wm_protocols; Atom _wm_delete_window; diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 2122769ce3..6994dd8939 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -48,6 +48,7 @@ glxGraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) : _display = glx_pipe->get_display(); _screen = glx_pipe->get_screen(); _xwindow = (Window)NULL; + _ic = (XIC)NULL; _awaiting_configure = false; _wm_delete_window = glx_pipe->get_wm_delete_window(); @@ -162,6 +163,10 @@ process_events() { XEvent event; while (XCheckIfEvent(_display, &event, check_event, (char *)this)) { + if (XFilterEvent(&event, None)) { + continue; + } + WindowProperties properties; ButtonHandle button; @@ -195,13 +200,22 @@ process_events() { case KeyPress: { _input_devices[0].set_pointer_in_window(event.xkey.x, event.xkey.y); - int index = ((event.xkey.state & ShiftMask) != 0) ? 1 : 0; - // First, get the keystroke, as modified by the shift key. - KeySym key = XLookupKeysym(&event.xkey, index); - if (key > 0 && key < 128) { - // If it's an ASCII key, press it. - _input_devices[0].keystroke(key); + // First, get the keystroke as a wide-character sequence. + static const int buffer_size = 256; + wchar_t buffer[buffer_size]; + Status status; + int len = XwcLookupString(_ic, &event.xkey, buffer, buffer_size, NULL, + &status); + if (status == XBufferOverflow) { + glxdisplay_cat.error() + << "Overflowed input buffer.\n"; + } + + // Now each of the returned wide characters represents a + // keystroke. + for (int i = 0; i < len; i++) { + _input_devices[0].keystroke(buffer[i]); } // Now get the raw unshifted button. @@ -349,9 +363,14 @@ set_properties_now(WindowProperties &properties) { //////////////////////////////////////////////////////////////////// void glxGraphicsWindow:: close_window() { + if (_ic != (XIC)NULL) { + XDestroyIC(_ic); + _ic = (XIC)NULL; + } + if (_xwindow != (Window)NULL) { XDestroyWindow(_display, _xwindow); - _xwindow = (Window)0; + _xwindow = (Window)NULL; // This may be necessary if we just closed the last X window in an // application, so the server hears the close request. @@ -423,6 +442,19 @@ open_window() { } set_wm_properties(_properties); + // We don't specify any fancy properties of the XIC. It would be + // nicer if we could support fancy IM's that want preedit callbacks, + // etc., but that can wait until we have an X server that actually + // supports these to test it on. + _ic = XCreateIC + (glx_pipe->get_im(), + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + NULL); + if (_ic == (XIC)NULL) { + glxdisplay_cat.warning() + << "Couldn't create input context.\n"; + } + XMapWindow(_display, _xwindow); return true; diff --git a/panda/src/glxdisplay/glxGraphicsWindow.h b/panda/src/glxdisplay/glxGraphicsWindow.h index bdf5ba9cee..198f653a67 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.h +++ b/panda/src/glxdisplay/glxGraphicsWindow.h @@ -65,6 +65,8 @@ private: int _screen; Window _xwindow; Colormap _colormap; + XIC _ic; + long _event_mask; bool _awaiting_configure; Atom _wm_delete_window;