Ver Fonte

better internationalization input support

David Rose há 22 anos atrás
pai
commit
a84c3ffec4

+ 12 - 0
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;
+}

+ 32 - 0
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);
   }

+ 4 - 0
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 <X11/Xlib.h>
 #include <GL/glx.h>
@@ -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;

+ 39 - 7
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;

+ 2 - 0
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;