diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index 7c9dfba8ca..f6c1872278 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -191,3 +191,16 @@ void GraphicsWindowInputDevice:: keystroke(int keycode, double 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)); +} diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index 25fc16dc14..8a84236d7d 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/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_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 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_out_of_window(); diff --git a/panda/src/event/buttonEvent.I b/panda/src/event/buttonEvent.I index f20a70b3fa..459b481146 100644 --- a/panda/src/event/buttonEvent.I +++ b/panda/src/event/buttonEvent.I @@ -40,6 +40,8 @@ INLINE ButtonEvent:: ButtonEvent(ButtonHandle button, ButtonEvent::Type type, double time) : _button(button), _keycode(0), + _highlight_start(0), + _highlight_end(0), _type(type), _time(time) { @@ -54,11 +56,31 @@ INLINE ButtonEvent:: ButtonEvent(short keycode, double time) : _button(ButtonHandle::none()), _keycode(keycode), + _highlight_start(0), + _highlight_end(0), _type(T_keystroke), _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 // Access: Public @@ -68,6 +90,9 @@ INLINE ButtonEvent:: ButtonEvent(const ButtonEvent ©) : _button(copy._button), _keycode(copy._keycode), + _candidate_string(copy._candidate_string), + _highlight_start(copy._highlight_start), + _highlight_end(copy._highlight_end), _type(copy._type), _time(copy._time) { @@ -82,6 +107,9 @@ INLINE void ButtonEvent:: operator = (const ButtonEvent ©) { _button = copy._button; _keycode = copy._keycode; + _candidate_string = copy._candidate_string; + _highlight_start = copy._highlight_start; + _highlight_end = copy._highlight_end; _type = copy._type; _time = copy._time; } diff --git a/panda/src/event/buttonEvent.cxx b/panda/src/event/buttonEvent.cxx index b647471816..412344b8f1 100644 --- a/panda/src/event/buttonEvent.cxx +++ b/panda/src/event/buttonEvent.cxx @@ -20,6 +20,7 @@ #include "datagram.h" #include "datagramIterator.h" #include "buttonRegistry.h" +#include "textEncoder.h" //////////////////////////////////////////////////////////////////// // Function: ButtonEvent::output @@ -44,6 +45,12 @@ output(ostream &out) const { case T_keystroke: out << "keystroke " << _keycode; 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: dg.add_int16(_keycode); 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: _keycode = scan.get_int16(); 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(); } } diff --git a/panda/src/event/buttonEvent.h b/panda/src/event/buttonEvent.h index 7148d7ee2e..89447a0718 100644 --- a/panda/src/event/buttonEvent.h +++ b/panda/src/event/buttonEvent.h @@ -72,12 +72,19 @@ public: // T_keystroke is a special keystroke event, and is sent along // 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(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(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 ©); INLINE void operator = (const ButtonEvent ©); @@ -101,6 +108,11 @@ public: // the Unicode character that was typed. 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). Type _type; diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 190cf1c195..c31ad72dfb 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -27,6 +27,7 @@ #include "glgsg.h" #include "clockObject.h" #include "pStatTimer.h" +#include "textEncoder.h" #include #include @@ -309,6 +310,20 @@ process_events() { case KeyPress: handle_keystroke(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; case KeyRelease: diff --git a/panda/src/pgui/pgEntry.cxx b/panda/src/pgui/pgEntry.cxx index b9465fa396..1a7ab75458 100644 --- a/panda/src/pgui/pgEntry.cxx +++ b/panda/src/pgui/pgEntry.cxx @@ -27,6 +27,7 @@ #include "keyboardButton.h" #include "mouseButton.h" #include "lineSegs.h" +#include "textEncoder.h" #include @@ -456,6 +457,33 @@ keystroke(const MouseWatcherParameter ¶m, bool 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 ¶m, 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 // Access: Public, Virtual diff --git a/panda/src/pgui/pgEntry.h b/panda/src/pgui/pgEntry.h index 2e4e4f44ae..94d6617354 100644 --- a/panda/src/pgui/pgEntry.h +++ b/panda/src/pgui/pgEntry.h @@ -57,6 +57,7 @@ public: virtual void press(const MouseWatcherParameter ¶m, bool background); virtual void keystroke(const MouseWatcherParameter ¶m, bool background); + virtual void candidate(const MouseWatcherParameter ¶m, bool background); virtual void accept(const MouseWatcherParameter ¶m); virtual void overflow(const MouseWatcherParameter ¶m); diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index 6dee87fb70..e286e18490 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -442,6 +442,17 @@ keystroke(const MouseWatcherParameter ¶m, 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 ¶m, bool background) { + // We don't throw sound events for candidate selections for now. +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::background_press // Access: Public, Static diff --git a/panda/src/pgui/pgItem.h b/panda/src/pgui/pgItem.h index 6e0f1218d0..c6f39813a9 100644 --- a/panda/src/pgui/pgItem.h +++ b/panda/src/pgui/pgItem.h @@ -78,6 +78,7 @@ public: virtual void press(const MouseWatcherParameter ¶m, bool background); virtual void release(const MouseWatcherParameter ¶m, bool background); virtual void keystroke(const MouseWatcherParameter ¶m, bool background); + virtual void candidate(const MouseWatcherParameter ¶m, bool background); static void background_press(const MouseWatcherParameter ¶m); static void background_release(const MouseWatcherParameter ¶m); diff --git a/panda/src/pgui/pgMouseWatcherRegion.cxx b/panda/src/pgui/pgMouseWatcherRegion.cxx index 9eb0e1c6bb..ee8378abaf 100644 --- a/panda/src/pgui/pgMouseWatcherRegion.cxx +++ b/panda/src/pgui/pgMouseWatcherRegion.cxx @@ -151,3 +151,16 @@ keystroke(const MouseWatcherParameter ¶m) { _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 ¶m) { + if (_item != (PGItem *)NULL) { + _item->candidate(param, false); + } +} diff --git a/panda/src/pgui/pgMouseWatcherRegion.h b/panda/src/pgui/pgMouseWatcherRegion.h index 0d9592beb3..fb1c456d4b 100644 --- a/panda/src/pgui/pgMouseWatcherRegion.h +++ b/panda/src/pgui/pgMouseWatcherRegion.h @@ -44,6 +44,7 @@ public: virtual void press(const MouseWatcherParameter ¶m); virtual void release(const MouseWatcherParameter ¶m); virtual void keystroke(const MouseWatcherParameter ¶m); + virtual void candidate(const MouseWatcherParameter ¶m); private: PGItem *_item; diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index 01a1956c2a..edd0f61aca 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/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 // Access: Protected @@ -973,6 +1015,10 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { keystroke(be._keycode); break; + case ButtonEvent::T_candidate: + candidate(be._candidate_string, be._highlight_start, be._highlight_end); + break; + case ButtonEvent::T_resume_down: // Ignore this, since the button wasn't pressed just now. break; diff --git a/panda/src/tform/mouseWatcher.h b/panda/src/tform/mouseWatcher.h index e40e0b6be1..04c4bd9cef 100644 --- a/panda/src/tform/mouseWatcher.h +++ b/panda/src/tform/mouseWatcher.h @@ -139,6 +139,9 @@ protected: void press(ButtonHandle button); void release(ButtonHandle button); void keystroke(int keycode); + void candidate(const wstring &candidate, size_t highlight_start, + size_t highlight_end); + void global_keyboard_press(const MouseWatcherParameter ¶m); void global_keyboard_release(const MouseWatcherParameter ¶m); diff --git a/panda/src/tform/mouseWatcherParameter.I b/panda/src/tform/mouseWatcherParameter.I index 7a2b91fc49..84790ceeb4 100644 --- a/panda/src/tform/mouseWatcherParameter.I +++ b/panda/src/tform/mouseWatcherParameter.I @@ -88,6 +88,21 @@ set_keycode(int 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 // Access: Public @@ -173,6 +188,75 @@ get_keycode() const { 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 // Access: Published diff --git a/panda/src/tform/mouseWatcherParameter.h b/panda/src/tform/mouseWatcherParameter.h index be65654751..7be2b41758 100644 --- a/panda/src/tform/mouseWatcherParameter.h +++ b/panda/src/tform/mouseWatcherParameter.h @@ -23,6 +23,7 @@ #include "buttonHandle.h" #include "modifierButtons.h" +#include "textEncoder.h" #include "luse.h" //////////////////////////////////////////////////////////////////// @@ -40,6 +41,9 @@ public: INLINE void set_button(const ButtonHandle &button); 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_mouse(const LPoint2f &mouse); INLINE void set_outside(bool flag); @@ -51,6 +55,17 @@ PUBLISHED: INLINE bool has_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 bool has_mouse() const; @@ -63,14 +78,18 @@ PUBLISHED: public: ButtonHandle _button; short _keycode; + wstring _candidate_string; + size_t _highlight_start; + size_t _highlight_end; ModifierButtons _mods; LPoint2f _mouse; 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; }; diff --git a/panda/src/tform/mouseWatcherRegion.cxx b/panda/src/tform/mouseWatcherRegion.cxx index 78576972ae..e1d47e67f8 100644 --- a/panda/src/tform/mouseWatcherRegion.cxx +++ b/panda/src/tform/mouseWatcherRegion.cxx @@ -127,3 +127,13 @@ release(const MouseWatcherParameter &) { void MouseWatcherRegion:: 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 &) { +} diff --git a/panda/src/tform/mouseWatcherRegion.h b/panda/src/tform/mouseWatcherRegion.h index 92b75e8027..d692b3f45b 100644 --- a/panda/src/tform/mouseWatcherRegion.h +++ b/panda/src/tform/mouseWatcherRegion.h @@ -77,6 +77,7 @@ public: virtual void press(const MouseWatcherParameter ¶m); virtual void release(const MouseWatcherParameter ¶m); virtual void keystroke(const MouseWatcherParameter ¶m); + virtual void candidate(const MouseWatcherParameter ¶m); private: LVecBase4f _frame;