Browse Source

add initial support for IME candidate strings in-game

David Rose 22 years ago
parent
commit
a28b2a8006

+ 13 - 0
panda/src/display/graphicsWindowInputDevice.cxx

@@ -191,3 +191,16 @@ void GraphicsWindowInputDevice::
 keystroke(int keycode, double time) {
 keystroke(int keycode, double time) {
   _button_events.push_back(ButtonEvent(keycode, time));
   _button_events.push_back(ButtonEvent(keycode, time));
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::candidate
+//       Access: Public
+//  Description: Records that the indicated candidate string has been
+//               highlighted.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindowInputDevice::
+candidate(const wstring &candidate_string, size_t highlight_start, 
+          size_t highlight_end, double time) {
+  _button_events.push_back(ButtonEvent(candidate_string, 
+                                       highlight_start, highlight_end));
+}

+ 2 - 0
panda/src/display/graphicsWindowInputDevice.h

@@ -66,6 +66,8 @@ public:
   void button_resume_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
   void button_resume_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
   void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
   void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
   void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
   void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
+  void candidate(const wstring &candidate_string, size_t highlight_start, 
+                 size_t higlight_end, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE void set_pointer_in_window(int x, int y);
   INLINE void set_pointer_in_window(int x, int y);
   INLINE void set_pointer_out_of_window();
   INLINE void set_pointer_out_of_window();
 
 

+ 28 - 0
panda/src/event/buttonEvent.I

@@ -40,6 +40,8 @@ INLINE ButtonEvent::
 ButtonEvent(ButtonHandle button, ButtonEvent::Type type, double time) :
 ButtonEvent(ButtonHandle button, ButtonEvent::Type type, double time) :
   _button(button),
   _button(button),
   _keycode(0),
   _keycode(0),
+  _highlight_start(0),
+  _highlight_end(0),
   _type(type),
   _type(type),
   _time(time)
   _time(time)
 {
 {
@@ -54,11 +56,31 @@ INLINE ButtonEvent::
 ButtonEvent(short keycode, double time) :
 ButtonEvent(short keycode, double time) :
   _button(ButtonHandle::none()),
   _button(ButtonHandle::none()),
   _keycode(keycode),
   _keycode(keycode),
+  _highlight_start(0),
+  _highlight_end(0),
   _type(T_keystroke),
   _type(T_keystroke),
   _time(time)
   _time(time)
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonEvent::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ButtonEvent::
+ButtonEvent(const wstring &candidate_string, size_t highlight_start, 
+            size_t highlight_end, double time) :
+  _button(ButtonHandle::none()),
+  _keycode(0),
+  _candidate_string(candidate_string),
+  _highlight_start(highlight_start),
+  _highlight_end(highlight_end),
+  _type(T_candidate),
+  _time(time)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ButtonEvent::Copy Constructor
 //     Function: ButtonEvent::Copy Constructor
 //       Access: Public
 //       Access: Public
@@ -68,6 +90,9 @@ INLINE ButtonEvent::
 ButtonEvent(const ButtonEvent &copy) :
 ButtonEvent(const ButtonEvent &copy) :
   _button(copy._button),
   _button(copy._button),
   _keycode(copy._keycode),
   _keycode(copy._keycode),
+  _candidate_string(copy._candidate_string),
+  _highlight_start(copy._highlight_start),
+  _highlight_end(copy._highlight_end),
   _type(copy._type),
   _type(copy._type),
   _time(copy._time)
   _time(copy._time)
 {
 {
@@ -82,6 +107,9 @@ INLINE void ButtonEvent::
 operator = (const ButtonEvent &copy) {
 operator = (const ButtonEvent &copy) {
   _button = copy._button;
   _button = copy._button;
   _keycode = copy._keycode;
   _keycode = copy._keycode;
+  _candidate_string = copy._candidate_string;
+  _highlight_start = copy._highlight_start;
+  _highlight_end = copy._highlight_end;
   _type = copy._type;
   _type = copy._type;
   _time = copy._time;
   _time = copy._time;
 }
 }

+ 22 - 0
panda/src/event/buttonEvent.cxx

@@ -20,6 +20,7 @@
 #include "datagram.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "buttonRegistry.h"
 #include "buttonRegistry.h"
+#include "textEncoder.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ButtonEvent::output
 //     Function: ButtonEvent::output
@@ -44,6 +45,12 @@ output(ostream &out) const {
   case T_keystroke:
   case T_keystroke:
     out << "keystroke " << _keycode;
     out << "keystroke " << _keycode;
     break;
     break;
+
+  case T_candidate:
+    out << "candidate "
+        << TextEncoder::encode_wtext(_candidate_string,
+                                     TextEncoder::get_default_encoding());
+    break;
   }
   }
 }
 }
 
 
@@ -69,6 +76,15 @@ write_datagram(Datagram &dg) const {
   case T_keystroke:
   case T_keystroke:
     dg.add_int16(_keycode);
     dg.add_int16(_keycode);
     break;
     break;
+
+  case T_candidate:
+    // We should probably store the wtext directly in the datagram
+    // rather than encoding it, but I don't feel like adding
+    // add_wstring() to datagram right now.
+    dg.add_string(TextEncoder::encode_wtext(_candidate_string,
+                                            TextEncoder::get_default_encoding()));
+    dg.add_uint16(_highlight_start);
+    dg.add_uint16(_highlight_end);
   }
   }
 }
 }
 
 
@@ -90,5 +106,11 @@ read_datagram(DatagramIterator &scan) {
   case T_keystroke:
   case T_keystroke:
     _keycode = scan.get_int16();
     _keycode = scan.get_int16();
     break;
     break;
+
+  case T_candidate:
+    _candidate_string = TextEncoder::decode_text(scan.get_string(),
+                                                 TextEncoder::get_default_encoding());
+    _highlight_start = scan.get_uint16();
+    _highlight_end = scan.get_uint16();
   }
   }
 }
 }

+ 13 - 1
panda/src/event/buttonEvent.h

@@ -72,12 +72,19 @@ public:
 
 
     // T_keystroke is a special keystroke event, and is sent along
     // T_keystroke is a special keystroke event, and is sent along
     // with a Unicode keycode value, not a ButtonHandle.
     // with a Unicode keycode value, not a ButtonHandle.
-    T_keystroke
+    T_keystroke,
+
+    // T_candidate is used to indicate that the user is using the IME
+    // and has in the process of selecting some possible text to type
+    // from a menu.
+    T_candidate,
   };
   };
 
 
   INLINE ButtonEvent();
   INLINE ButtonEvent();
   INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(short keycode, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(short keycode, double time = ClockObject::get_global_clock()->get_frame_time());
+  INLINE ButtonEvent(const wstring &candidate_string, size_t highlight_start, 
+                     size_t higlight_end, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(const ButtonEvent &copy);
   INLINE ButtonEvent(const ButtonEvent &copy);
   INLINE void operator = (const ButtonEvent &copy);
   INLINE void operator = (const ButtonEvent &copy);
 
 
@@ -101,6 +108,11 @@ public:
   // the Unicode character that was typed.
   // the Unicode character that was typed.
   short _keycode;
   short _keycode;
 
 
+  // _candidate_string will be filled in if type is T_candidate.
+  wstring _candidate_string;
+  size_t _highlight_start;
+  size_t _highlight_end;
+
   // This is the type of the button event (see above).
   // This is the type of the button event (see above).
   Type _type;
   Type _type;
 
 

+ 15 - 0
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -27,6 +27,7 @@
 #include "glgsg.h"
 #include "glgsg.h"
 #include "clockObject.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
+#include "textEncoder.h"
 
 
 #include <errno.h>
 #include <errno.h>
 #include <sys/time.h>
 #include <sys/time.h>
@@ -309,6 +310,20 @@ process_events() {
     case KeyPress:
     case KeyPress:
       handle_keystroke(event.xkey);
       handle_keystroke(event.xkey);
       handle_keypress(event.xkey);
       handle_keypress(event.xkey);
+
+      /*
+      // Temp hack for testing.  We pretend that we have received a
+      // candidate string every type the user types the backslash key.
+      {
+        KeySym key = XLookupKeysym(&event.xkey, 0);
+
+        if (key == XK_backslash) {
+          cerr << "Pressed backslash, sending candidate\n";
+          wstring candidate_string = TextEncoder::decode_text("This is a candidate string", TextEncoder::get_default_encoding());
+          _input_devices[0].candidate(candidate_string, 5, 7);
+        }
+      }
+      */
       break;
       break;
 
 
     case KeyRelease:
     case KeyRelease:

+ 28 - 0
panda/src/pgui/pgEntry.cxx

@@ -27,6 +27,7 @@
 #include "keyboardButton.h"
 #include "keyboardButton.h"
 #include "mouseButton.h"
 #include "mouseButton.h"
 #include "lineSegs.h"
 #include "lineSegs.h"
+#include "textEncoder.h"
 
 
 #include <math.h>
 #include <math.h>
 
 
@@ -456,6 +457,33 @@ keystroke(const MouseWatcherParameter &param, bool background) {
   PGItem::keystroke(param, background);
   PGItem::keystroke(param, background);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PGEntry::candidate
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever
+//               the user selects an item from the IME menu.
+////////////////////////////////////////////////////////////////////
+void PGEntry::
+candidate(const MouseWatcherParameter &param, bool background) {
+  if (get_active()) {
+    if (param.has_candidate()) {
+      // Do something with the candidate string.
+      TextEncoder te;
+      const wstring &cs = param.get_candidate_string();
+      size_t hs = param.get_highlight_start();
+      size_t he = param.get_highlight_end();
+
+      pgui_cat.info()
+        << "Candidate: "
+        << te.encode_wtext(cs.substr(0, hs))
+        << " (" << te.encode_wtext(cs.substr(hs, he - hs)) << ") "
+        << te.encode_wtext(cs.substr(he))
+        << "\n";
+    }
+  }
+  PGItem::candidate(param, background);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PGEntry::accept
 //     Function: PGEntry::accept
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 1 - 0
panda/src/pgui/pgEntry.h

@@ -57,6 +57,7 @@ public:
 
 
   virtual void press(const MouseWatcherParameter &param, bool background);
   virtual void press(const MouseWatcherParameter &param, bool background);
   virtual void keystroke(const MouseWatcherParameter &param, bool background);
   virtual void keystroke(const MouseWatcherParameter &param, bool background);
+  virtual void candidate(const MouseWatcherParameter &param, bool background);
 
 
   virtual void accept(const MouseWatcherParameter &param);
   virtual void accept(const MouseWatcherParameter &param);
   virtual void overflow(const MouseWatcherParameter &param);
   virtual void overflow(const MouseWatcherParameter &param);

+ 11 - 0
panda/src/pgui/pgItem.cxx

@@ -442,6 +442,17 @@ keystroke(const MouseWatcherParameter &param, bool background) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PGItem::keystroke
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever
+//               the user highlights an option in the IME window.
+////////////////////////////////////////////////////////////////////
+void PGItem::
+candidate(const MouseWatcherParameter &param, bool background) {
+  // We don't throw sound events for candidate selections for now.
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PGItem::background_press
 //     Function: PGItem::background_press
 //       Access: Public, Static
 //       Access: Public, Static

+ 1 - 0
panda/src/pgui/pgItem.h

@@ -78,6 +78,7 @@ public:
   virtual void press(const MouseWatcherParameter &param, bool background);
   virtual void press(const MouseWatcherParameter &param, bool background);
   virtual void release(const MouseWatcherParameter &param, bool background);
   virtual void release(const MouseWatcherParameter &param, bool background);
   virtual void keystroke(const MouseWatcherParameter &param, bool background);
   virtual void keystroke(const MouseWatcherParameter &param, bool background);
+  virtual void candidate(const MouseWatcherParameter &param, bool background);
 
 
   static void background_press(const MouseWatcherParameter &param);
   static void background_press(const MouseWatcherParameter &param);
   static void background_release(const MouseWatcherParameter &param);
   static void background_release(const MouseWatcherParameter &param);

+ 13 - 0
panda/src/pgui/pgMouseWatcherRegion.cxx

@@ -151,3 +151,16 @@ keystroke(const MouseWatcherParameter &param) {
     _item->keystroke(param, false);
     _item->keystroke(param, false);
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PGMouseWatcherRegion::candidate
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever 
+//               the user selects an option from the IME menu.
+////////////////////////////////////////////////////////////////////
+void PGMouseWatcherRegion::
+candidate(const MouseWatcherParameter &param) {
+  if (_item != (PGItem *)NULL) {
+    _item->candidate(param, false);
+  }
+}

+ 1 - 0
panda/src/pgui/pgMouseWatcherRegion.h

@@ -44,6 +44,7 @@ public:
   virtual void press(const MouseWatcherParameter &param);
   virtual void press(const MouseWatcherParameter &param);
   virtual void release(const MouseWatcherParameter &param);
   virtual void release(const MouseWatcherParameter &param);
   virtual void keystroke(const MouseWatcherParameter &param);
   virtual void keystroke(const MouseWatcherParameter &param);
+  virtual void candidate(const MouseWatcherParameter &param);
 
 
 private:
 private:
   PGItem *_item;
   PGItem *_item;

+ 46 - 0
panda/src/tform/mouseWatcher.cxx

@@ -737,6 +737,48 @@ keystroke(int keycode) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcher::candidate
+//       Access: Protected
+//  Description: Records that the indicated candidate string has been
+//               highlighted in the IME.
+////////////////////////////////////////////////////////////////////
+void MouseWatcher::
+candidate(const wstring &candidate_string, size_t highlight_start, 
+          size_t highlight_end) {
+  MouseWatcherParameter param;
+  param.set_candidate(candidate_string, highlight_start, highlight_end);
+  param.set_modifier_buttons(_mods);
+  param.set_mouse(_mouse);
+
+  // Candidate strings go to all those regions that want keyboard
+  // events, exactly like keystrokes, above.
+
+  Regions::const_iterator ri;
+  for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
+    MouseWatcherRegion *region = (*ri);
+
+    if (region->get_keyboard()) {
+      param.set_outside(region != _preferred_region);
+      region->candidate(param);
+    }
+  }
+
+  // Also check all of our sub-groups.
+  Groups::const_iterator gi;
+  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
+    MouseWatcherGroup *group = (*gi);
+    for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
+      MouseWatcherRegion *region = (*ri);
+
+      if (region->get_keyboard()) {
+        param.set_outside(region != _preferred_region);
+        region->candidate(param);
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MouseWatcher::global_keyboard_press
 //     Function: MouseWatcher::global_keyboard_press
 //       Access: Protected
 //       Access: Protected
@@ -973,6 +1015,10 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
         keystroke(be._keycode);
         keystroke(be._keycode);
         break;
         break;
 
 
+      case ButtonEvent::T_candidate:
+        candidate(be._candidate_string, be._highlight_start, be._highlight_end);
+        break;
+
       case ButtonEvent::T_resume_down:
       case ButtonEvent::T_resume_down:
         // Ignore this, since the button wasn't pressed just now.
         // Ignore this, since the button wasn't pressed just now.
         break;
         break;

+ 3 - 0
panda/src/tform/mouseWatcher.h

@@ -139,6 +139,9 @@ protected:
   void press(ButtonHandle button);
   void press(ButtonHandle button);
   void release(ButtonHandle button);
   void release(ButtonHandle button);
   void keystroke(int keycode);
   void keystroke(int keycode);
+  void candidate(const wstring &candidate, size_t highlight_start, 
+                 size_t highlight_end);
+                 
   void global_keyboard_press(const MouseWatcherParameter &param);
   void global_keyboard_press(const MouseWatcherParameter &param);
   void global_keyboard_release(const MouseWatcherParameter &param);
   void global_keyboard_release(const MouseWatcherParameter &param);
 
 

+ 84 - 0
panda/src/tform/mouseWatcherParameter.I

@@ -88,6 +88,21 @@ set_keycode(int keycode) {
   _flags |= F_has_keycode;
   _flags |= F_has_keycode;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::set_candidate
+//       Access: Public
+//  Description: Sets the candidate string associated with this event,
+//               if any.
+////////////////////////////////////////////////////////////////////
+INLINE void MouseWatcherParameter::
+set_candidate(const wstring &candidate_string,
+              size_t highlight_start, size_t highlight_end) {
+  _candidate_string = candidate_string;
+  _highlight_start = highlight_start;
+  _highlight_end = highlight_end;
+  _flags |= F_has_candidate;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MouseWatcherParameter::set_modifier_buttons
 //     Function: MouseWatcherParameter::set_modifier_buttons
 //       Access: Public
 //       Access: Public
@@ -173,6 +188,75 @@ get_keycode() const {
   return _keycode;
   return _keycode;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::has_candidate
+//       Access: Published
+//  Description: Returns true if this parameter has an associated
+//               candidate string, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool MouseWatcherParameter::
+has_candidate() const {
+  return (_flags & F_has_candidate) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::get_candidate_string
+//       Access: Published
+//  Description: Returns the candidate string associated with this
+//               event.  If has_candidate(), above, returns false,
+//               this returns the empty string.
+////////////////////////////////////////////////////////////////////
+INLINE const wstring &MouseWatcherParameter::
+get_candidate_string() const {
+  return _candidate_string;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::get_candidate_string_encoded
+//       Access: Published
+//  Description: Returns the candidate string associated with this
+//               event.  If has_candidate(), above, returns false,
+//               this returns the empty string.
+////////////////////////////////////////////////////////////////////
+INLINE string MouseWatcherParameter::
+get_candidate_string_encoded() const {
+  return get_candidate_string_encoded(TextEncoder::get_default_encoding());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::get_candidate_string_encoded
+//       Access: Published
+//  Description: Returns the candidate string associated with this
+//               event.  If has_candidate(), above, returns false,
+//               this returns the empty string.
+////////////////////////////////////////////////////////////////////
+INLINE string MouseWatcherParameter::
+get_candidate_string_encoded(TextEncoder::Encoding encoding) const {
+  return TextEncoder::encode_wtext(_candidate_string, encoding);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::get_highlight_start
+//       Access: Published
+//  Description: Returns the first highlighted character in the
+//               candidate string.
+////////////////////////////////////////////////////////////////////
+INLINE size_t MouseWatcherParameter::
+get_highlight_start() const {
+  return _highlight_start;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherParameter::get_highlight_end
+//       Access: Published
+//  Description: Returns one more than the last highlighted character
+//               in the candidate string.
+////////////////////////////////////////////////////////////////////
+INLINE size_t MouseWatcherParameter::
+get_highlight_end() const {
+  return _highlight_end;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MouseWatcherParameter::get_modifier_buttons
 //     Function: MouseWatcherParameter::get_modifier_buttons
 //       Access: Published
 //       Access: Published

+ 23 - 4
panda/src/tform/mouseWatcherParameter.h

@@ -23,6 +23,7 @@
 
 
 #include "buttonHandle.h"
 #include "buttonHandle.h"
 #include "modifierButtons.h"
 #include "modifierButtons.h"
+#include "textEncoder.h"
 #include "luse.h"
 #include "luse.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -40,6 +41,9 @@ public:
 
 
   INLINE void set_button(const ButtonHandle &button);
   INLINE void set_button(const ButtonHandle &button);
   INLINE void set_keycode(int keycode);
   INLINE void set_keycode(int keycode);
+  INLINE void set_candidate(const wstring &candidate_string,
+                            size_t highlight_start, 
+                            size_t higlight_end);
   INLINE void set_modifier_buttons(const ModifierButtons &mods);
   INLINE void set_modifier_buttons(const ModifierButtons &mods);
   INLINE void set_mouse(const LPoint2f &mouse);
   INLINE void set_mouse(const LPoint2f &mouse);
   INLINE void set_outside(bool flag);
   INLINE void set_outside(bool flag);
@@ -51,6 +55,17 @@ PUBLISHED:
   INLINE bool has_keycode() const;
   INLINE bool has_keycode() const;
   INLINE int get_keycode() const;
   INLINE int get_keycode() const;
 
 
+  INLINE bool has_candidate() const;
+
+public:
+  INLINE const wstring &get_candidate_string() const;
+
+PUBLISHED:
+  INLINE string get_candidate_string_encoded() const;
+  INLINE string get_candidate_string_encoded(TextEncoder::Encoding encoding) const;
+  INLINE size_t get_highlight_start() const;
+  INLINE size_t get_highlight_end() const;
+
   INLINE const ModifierButtons &get_modifier_buttons() const;
   INLINE const ModifierButtons &get_modifier_buttons() const;
 
 
   INLINE bool has_mouse() const;
   INLINE bool has_mouse() const;
@@ -63,14 +78,18 @@ PUBLISHED:
 public:
 public:
   ButtonHandle _button;
   ButtonHandle _button;
   short _keycode;
   short _keycode;
+  wstring _candidate_string;
+  size_t _highlight_start;
+  size_t _highlight_end;
   ModifierButtons _mods;
   ModifierButtons _mods;
   LPoint2f _mouse;
   LPoint2f _mouse;
 
 
   enum Flags {
   enum Flags {
-    F_has_button  = 0x001,
-    F_has_mouse   = 0x002,
-    F_is_outside  = 0x004,
-    F_has_keycode = 0x008,
+    F_has_button    = 0x001,
+    F_has_mouse     = 0x002,
+    F_is_outside    = 0x004,
+    F_has_keycode   = 0x008,
+    F_has_candidate = 0x010,
   };
   };
   int _flags;
   int _flags;
 };
 };

+ 10 - 0
panda/src/tform/mouseWatcherRegion.cxx

@@ -127,3 +127,13 @@ release(const MouseWatcherParameter &) {
 void MouseWatcherRegion::
 void MouseWatcherRegion::
 keystroke(const MouseWatcherParameter &) {
 keystroke(const MouseWatcherParameter &) {
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MouseWatcherRegion::candidate
+//       Access: Public, Virtual
+//  Description: This is a callback hook function, called whenever an
+//               IME candidate is highlighted by the user.
+////////////////////////////////////////////////////////////////////
+void MouseWatcherRegion::
+candidate(const MouseWatcherParameter &) {
+}

+ 1 - 0
panda/src/tform/mouseWatcherRegion.h

@@ -77,6 +77,7 @@ public:
   virtual void press(const MouseWatcherParameter &param);
   virtual void press(const MouseWatcherParameter &param);
   virtual void release(const MouseWatcherParameter &param);
   virtual void release(const MouseWatcherParameter &param);
   virtual void keystroke(const MouseWatcherParameter &param);
   virtual void keystroke(const MouseWatcherParameter &param);
+  virtual void candidate(const MouseWatcherParameter &param);
 
 
 private:
 private:
   LVecBase4f _frame;
   LVecBase4f _frame;