From 6739d86101b55808a52e0a9d112ce2cdde9bcc42 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 16 Feb 2002 00:09:53 +0000 Subject: [PATCH] support keystrokes in addition to button up/down --- panda/src/device/clientButtonDevice.cxx | 2 +- panda/src/device/virtualMouse.cxx | 4 +- .../src/display/graphicsWindowInputDevice.cxx | 15 ++- panda/src/display/graphicsWindowInputDevice.h | 1 + panda/src/glxdisplay/glxGraphicsWindow.cxx | 3 + panda/src/pgui/config_pgui.cxx | 7 ++ panda/src/pgui/config_pgui.h | 1 + panda/src/pgui/pgEntry.cxx | 117 +++++++++++++++++- panda/src/pgui/pgEntry.h | 1 + panda/src/pgui/pgItem.I | 24 ++++ panda/src/pgui/pgItem.cxx | 33 +++++ panda/src/pgui/pgItem.h | 4 + panda/src/pgui/pgMouseWatcherBackground.cxx | 11 ++ panda/src/pgui/pgMouseWatcherBackground.h | 1 + panda/src/pgui/pgMouseWatcherRegion.cxx | 13 ++ panda/src/pgui/pgMouseWatcherRegion.h | 1 + panda/src/putil/buttonEvent.I | 35 ++++-- panda/src/putil/buttonEvent.cxx | 17 ++- panda/src/putil/buttonEvent.h | 44 ++++++- panda/src/putil/modifierButtons.I | 9 +- panda/src/tform/buttonThrower.cxx | 12 +- panda/src/tform/driveInterface.cxx | 42 ++++--- panda/src/tform/mouseWatcher.cxx | 79 +++++++++++- panda/src/tform/mouseWatcher.h | 2 + panda/src/tform/mouseWatcherParameter.I | 35 ++++++ panda/src/tform/mouseWatcherParameter.h | 6 + panda/src/tform/mouseWatcherRegion.cxx | 10 ++ panda/src/tform/mouseWatcherRegion.h | 1 + 28 files changed, 480 insertions(+), 50 deletions(-) diff --git a/panda/src/device/clientButtonDevice.cxx b/panda/src/device/clientButtonDevice.cxx index 5f1a0ecfe6..a3df1aa90a 100644 --- a/panda/src/device/clientButtonDevice.cxx +++ b/panda/src/device/clientButtonDevice.cxx @@ -53,7 +53,7 @@ set_button_state(int index, bool down) { ButtonHandle handle = _buttons[index]._handle; if (handle != ButtonHandle::none()) { - _button_events->push_back(ButtonEvent(handle, down)); + _button_events->push_back(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up)); } } diff --git a/panda/src/device/virtualMouse.cxx b/panda/src/device/virtualMouse.cxx index f1629865e0..38dfbfa6a7 100644 --- a/panda/src/device/virtualMouse.cxx +++ b/panda/src/device/virtualMouse.cxx @@ -101,7 +101,7 @@ set_mouse_on(bool flag) { //////////////////////////////////////////////////////////////////// void VirtualMouse:: press_button(ButtonHandle button) { - _next_button_events->push_back(ButtonEvent(button, true)); + _next_button_events->push_back(ButtonEvent(button, ButtonEvent::T_down)); } //////////////////////////////////////////////////////////////////// @@ -112,7 +112,7 @@ press_button(ButtonHandle button) { //////////////////////////////////////////////////////////////////// void VirtualMouse:: release_button(ButtonHandle button) { - _next_button_events->push_back(ButtonEvent(button, false)); + _next_button_events->push_back(ButtonEvent(button, ButtonEvent::T_up)); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index f24c65e3a9..ceb8f09251 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -155,7 +155,7 @@ get_button_event() { //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: button_down(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, true)); + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_down)); } //////////////////////////////////////////////////////////////////// @@ -165,5 +165,16 @@ button_down(ButtonHandle button) { //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: button_up(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, false)); + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_up)); +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindowInputDevice::keystroke +// Access: Public +// Description: Records that the indicated keystroke has been +// generated. +//////////////////////////////////////////////////////////////////// +void GraphicsWindowInputDevice:: +keystroke(int keycode) { + _button_events.push_back(ButtonEvent(keycode)); } diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index a5cc91af8a..7995b181c2 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -63,6 +63,7 @@ public: // GraphicsWindows to record the data incoming on the device. void button_down(ButtonHandle button); void button_up(ButtonHandle button); + void keystroke(int keycode); INLINE void set_pointer_in_window(int x, int y); INLINE void set_pointer_out_of_window(); diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 265b6df6b0..3b5fa1bcb8 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -735,6 +735,9 @@ handle_keypress(ButtonHandle key, int x, int y) { _input_devices[0].set_pointer_in_window(x, y); if (key != ButtonHandle::none()) { _input_devices[0].button_down(key); + if (key.has_ascii_equivalent()) { + _input_devices[0].keystroke(key.get_ascii_equivalent()); + } } } diff --git a/panda/src/pgui/config_pgui.cxx b/panda/src/pgui/config_pgui.cxx index ed04c7d6bc..4c909c775e 100644 --- a/panda/src/pgui/config_pgui.cxx +++ b/panda/src/pgui/config_pgui.cxx @@ -36,8 +36,15 @@ ConfigureFn(config_pgui) { init_libpgui(); } +// If this is true, uses a QuickRenderTraverser to render PGItems; +// otherwise, uses a normal DirectRenderTraverser, which is more +// powerful but somewhat slower. const bool pgui_quick = config_pgui.GetBool("pgui-quick", true); +// Temporary variable to support old-style button press/release for +// pgentries, before keystrokes were implemented. +const bool use_keystrokes = config_pgui.GetBool("use-keystrokes", false); + //////////////////////////////////////////////////////////////////// // Function: init_libpgui diff --git a/panda/src/pgui/config_pgui.h b/panda/src/pgui/config_pgui.h index d7bacbb198..905f40e644 100644 --- a/panda/src/pgui/config_pgui.h +++ b/panda/src/pgui/config_pgui.h @@ -26,6 +26,7 @@ NotifyCategoryDecl(pgui, EXPCL_PANDA, EXPTP_PANDA); // Configure variables for pgui package. extern const bool pgui_quick; +extern const bool use_keystrokes; extern EXPCL_PANDA void init_libpgui(); diff --git a/panda/src/pgui/pgEntry.cxx b/panda/src/pgui/pgEntry.cxx index e8ce3ddbf7..541e35fe70 100644 --- a/panda/src/pgui/pgEntry.cxx +++ b/panda/src/pgui/pgEntry.cxx @@ -237,7 +237,7 @@ press(const MouseWatcherParameter ¶m, bool background) { _cursor_stale = true; } - } else if (button.has_ascii_equivalent()) { + } else if (!use_keystrokes && button.has_ascii_equivalent()) { char key = button.get_ascii_equivalent(); if (isprint(key)) { // A normal visible character. Add a new character to the @@ -340,6 +340,121 @@ press(const MouseWatcherParameter ¶m, bool background) { PGItem::press(param, background); } +//////////////////////////////////////////////////////////////////// +// Function: PGEntry::keystroke +// Access: Public, Virtual +// Description: This is a callback hook function, called whenever +// the user types a key. +//////////////////////////////////////////////////////////////////// +void PGEntry:: +keystroke(const MouseWatcherParameter ¶m, bool background) { + if (get_active()) { + if (param.has_keycode()) { + int keycode = param.get_keycode(); + + if (use_keystrokes) { + if (!isascii(keycode) || isprint(keycode)) { + // A normal visible character. Add a new character to the + // text entry, if there's room. + + string new_char(1, (char)keycode); + + if (get_max_chars() > 0 && (int)_text.length() >= get_max_chars()) { + overflow(param); + } else { + string new_text = + _text.substr(0, _cursor_position) + new_char + + _text.substr(_cursor_position); + + // Get a string to measure its length. In normal mode, + // we measure the text itself. In obscure mode, we + // measure a string of n asterisks. + string measure_text; + if (_obscure_mode) { + measure_text = get_display_text() + '*'; + } else { + measure_text = new_text; + } + + // Check the length. + bool too_long = false; + if (_max_width > 0.0f) { + TextNode *text_node = get_text_def(S_focus); + if (_num_lines <= 1) { + // If we have only one line, we can check the length + // by simply measuring the width of the text. + too_long = (text_node->calc_width(measure_text) > _max_width); + + } else { + // If we have multiple lines, we have to check the + // length by wordwrapping it and counting up the + // number of lines. + string ww_text = text_node->wordwrap_to(measure_text, _max_width, true); + int num_lines = 1; + size_t last_line_start = 0; + for (size_t p = 0; + p < ww_text.length() && !too_long; + ++p) { + if (ww_text[p] == '\n') { + last_line_start = p + 1; + num_lines++; + too_long = (num_lines > _num_lines); + } + } + + if (!too_long) { + // We must also ensure that the last line is not too + // long (it might be, because of additional + // whitespace on the end). + string last_line = ww_text.substr(last_line_start); + float last_line_width = text_node->calc_width(last_line); + if (num_lines == _num_lines) { + // Mainly we only care about this if we're on + // the very last line. + too_long = (last_line_width > _max_width); + + } else { + // If we're not on the very last line, the width + // is still important, just so we don't allow an + // infinite number of spaces to accumulate. + // However, we must allow at least *one* space + // on the end of a line. + if (_text.length() >= 1 && + _text[_text.length() - 1] == ' ') { + if (last_line_width > _max_width) { + // In this case, however, it's not exactly + // an overflow; we just want to reject the + // space. + return; + } + } + } + } + } + } + + if (too_long) { + overflow(param); + + } else { + _text = new_text; + if (_obscure_mode) { + _obscured_text = measure_text; + } + + _cursor_position += new_char.size(); + _cursor_stale = true; + _text_geom_stale = true; + type(param); + } + } + } + } + } + } + PGItem::keystroke(param, background); +} + //////////////////////////////////////////////////////////////////// // Function: PGEntry::accept // Access: Public, Virtual diff --git a/panda/src/pgui/pgEntry.h b/panda/src/pgui/pgEntry.h index bb22f9fb8f..f42d31d967 100644 --- a/panda/src/pgui/pgEntry.h +++ b/panda/src/pgui/pgEntry.h @@ -49,6 +49,7 @@ public: const AllTransitionsWrapper &trans); virtual void press(const MouseWatcherParameter ¶m, bool background); + virtual void keystroke(const MouseWatcherParameter ¶m, bool background); virtual void accept(const MouseWatcherParameter ¶m); virtual void overflow(const MouseWatcherParameter ¶m); diff --git a/panda/src/pgui/pgItem.I b/panda/src/pgui/pgItem.I index 3ec0f764fc..cf317ad584 100644 --- a/panda/src/pgui/pgItem.I +++ b/panda/src/pgui/pgItem.I @@ -317,6 +317,19 @@ get_release_prefix() { return "release-"; } +//////////////////////////////////////////////////////////////////// +// Function: PGItem::get_keystroke_prefix +// Access: Published, Static +// Description: Returns the prefix that is used to define the +// keystroke event for all PGItems. The keystroke event +// is the concatenation of this string followed by a +// hyphen and get_id(). +//////////////////////////////////////////////////////////////////// +INLINE string PGItem:: +get_keystroke_prefix() { + return "keystroke-"; +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::get_enter_event // Access: Published @@ -418,6 +431,17 @@ get_release_event(const ButtonHandle &button) const { return get_release_prefix() + button.get_name() + "-" + get_id(); } +//////////////////////////////////////////////////////////////////// +// Function: PGItem::get_keystroke_event +// Access: Published +// Description: Returns the event name that will be thrown when the +// item is active and any key is pressed by the user. +//////////////////////////////////////////////////////////////////// +INLINE string PGItem:: +get_keystroke_event() const { + return get_keystroke_prefix() + "-" + get_id(); +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::set_text_node // Access: Published, Static diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index b41120c016..70db87cb17 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -349,6 +349,22 @@ release(const MouseWatcherParameter ¶m, bool background) { } } +//////////////////////////////////////////////////////////////////// +// Function: PGItem::keystroke +// Access: Public, Virtual +// Description: This is a callback hook function, called whenever +// the user presses a key. +//////////////////////////////////////////////////////////////////// +void PGItem:: +keystroke(const MouseWatcherParameter ¶m, bool background) { + if (!background) { + PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); + string event = get_keystroke_event(); + play_sound(event); + throw_event(event, EventParameter(ep)); + } +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::background_press // Access: Public, Static @@ -383,6 +399,23 @@ background_release(const MouseWatcherParameter ¶m) { } } +//////////////////////////////////////////////////////////////////// +// Function: PGItem::background_keystroke +// Access: Public, Static +// Description: Calls keystroke() on all the PGItems with background +// focus. +//////////////////////////////////////////////////////////////////// +void PGItem:: +background_keystroke(const MouseWatcherParameter ¶m) { + BackgroundFocus::const_iterator fi; + for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) { + PGItem *item = *fi; + if (!item->get_focus()) { + item->keystroke(param, true); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::set_active // Access: Published, Virtual diff --git a/panda/src/pgui/pgItem.h b/panda/src/pgui/pgItem.h index d8d1e5490f..49361a46cb 100644 --- a/panda/src/pgui/pgItem.h +++ b/panda/src/pgui/pgItem.h @@ -81,9 +81,11 @@ public: virtual void focus_out(); virtual void press(const MouseWatcherParameter ¶m, bool background); virtual void release(const MouseWatcherParameter ¶m, bool background); + virtual void keystroke(const MouseWatcherParameter ¶m, bool background); static void background_press(const MouseWatcherParameter ¶m); static void background_release(const MouseWatcherParameter ¶m); + static void background_keystroke(const MouseWatcherParameter ¶m); PUBLISHED: INLINE void set_frame(float left, float right, float bottom, float top); @@ -127,6 +129,7 @@ PUBLISHED: INLINE static string get_focus_out_prefix(); INLINE static string get_press_prefix(); INLINE static string get_release_prefix(); + INLINE static string get_keystroke_prefix(); INLINE string get_enter_event() const; INLINE string get_exit_event() const; @@ -136,6 +139,7 @@ PUBLISHED: INLINE string get_focus_out_event() const; INLINE string get_press_event(const ButtonHandle &button) const; INLINE string get_release_event(const ButtonHandle &button) const; + INLINE string get_keystroke_event() const; #ifdef HAVE_AUDIO void set_sound(const string &event, AudioSound *sound); diff --git a/panda/src/pgui/pgMouseWatcherBackground.cxx b/panda/src/pgui/pgMouseWatcherBackground.cxx index 1625a66873..3c44ffeb0c 100644 --- a/panda/src/pgui/pgMouseWatcherBackground.cxx +++ b/panda/src/pgui/pgMouseWatcherBackground.cxx @@ -66,3 +66,14 @@ void PGMouseWatcherBackground:: release(const MouseWatcherParameter ¶m) { PGItem::background_release(param); } + +//////////////////////////////////////////////////////////////////// +// Function: PGMouseWatcherBackground::keystroke +// Access: Public, Virtual +// Description: This is a callback hook function, called whenever +// the user presses a key. +//////////////////////////////////////////////////////////////////// +void PGMouseWatcherBackground:: +keystroke(const MouseWatcherParameter ¶m) { + PGItem::background_keystroke(param); +} diff --git a/panda/src/pgui/pgMouseWatcherBackground.h b/panda/src/pgui/pgMouseWatcherBackground.h index 92ef9fb91f..3a9435f8d9 100644 --- a/panda/src/pgui/pgMouseWatcherBackground.h +++ b/panda/src/pgui/pgMouseWatcherBackground.h @@ -37,6 +37,7 @@ PUBLISHED: virtual void press(const MouseWatcherParameter ¶m); virtual void release(const MouseWatcherParameter ¶m); + virtual void keystroke(const MouseWatcherParameter ¶m); public: static TypeHandle get_class_type() { diff --git a/panda/src/pgui/pgMouseWatcherRegion.cxx b/panda/src/pgui/pgMouseWatcherRegion.cxx index 4bb3cdd95e..84ad639bd6 100644 --- a/panda/src/pgui/pgMouseWatcherRegion.cxx +++ b/panda/src/pgui/pgMouseWatcherRegion.cxx @@ -138,3 +138,16 @@ release(const MouseWatcherParameter ¶m) { _item->release(param, false); } } + +//////////////////////////////////////////////////////////////////// +// Function: PGMouseWatcherRegion::keystroke +// Access: Public, Virtual +// Description: This is a callback hook function, called whenever +// the user presses a key. +//////////////////////////////////////////////////////////////////// +void PGMouseWatcherRegion:: +keystroke(const MouseWatcherParameter ¶m) { + if (_item != (PGItem *)NULL) { + _item->keystroke(param, false); + } +} diff --git a/panda/src/pgui/pgMouseWatcherRegion.h b/panda/src/pgui/pgMouseWatcherRegion.h index ea30c05d35..34961476d0 100644 --- a/panda/src/pgui/pgMouseWatcherRegion.h +++ b/panda/src/pgui/pgMouseWatcherRegion.h @@ -43,6 +43,7 @@ public: virtual void without(const MouseWatcherParameter ¶m); virtual void press(const MouseWatcherParameter ¶m); virtual void release(const MouseWatcherParameter ¶m); + virtual void keystroke(const MouseWatcherParameter ¶m); private: PGItem *_item; diff --git a/panda/src/putil/buttonEvent.I b/panda/src/putil/buttonEvent.I index 09ba6edc40..d6e5efc1a7 100644 --- a/panda/src/putil/buttonEvent.I +++ b/panda/src/putil/buttonEvent.I @@ -25,7 +25,8 @@ INLINE ButtonEvent:: ButtonEvent() : _button(ButtonHandle::none()), - _down(false) + _keycode(0), + _type(T_down) { } @@ -35,9 +36,23 @@ ButtonEvent() : // Description: //////////////////////////////////////////////////////////////////// INLINE ButtonEvent:: -ButtonEvent(ButtonHandle button, bool down) : +ButtonEvent(ButtonHandle button, ButtonEvent::Type type) : _button(button), - _down(down) + _keycode(0), + _type(type) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonEvent::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ButtonEvent:: +ButtonEvent(short keycode) : + _button(ButtonHandle::none()), + _keycode(keycode), + _type(T_keystroke) { } @@ -49,7 +64,8 @@ ButtonEvent(ButtonHandle button, bool down) : INLINE ButtonEvent:: ButtonEvent(const ButtonEvent ©) : _button(copy._button), - _down(copy._down) + _keycode(copy._keycode), + _type(copy._type) { } @@ -61,7 +77,8 @@ ButtonEvent(const ButtonEvent ©) : INLINE void ButtonEvent:: operator = (const ButtonEvent ©) { _button = copy._button; - _down = copy._down; + _keycode = copy._keycode; + _type = copy._type; } //////////////////////////////////////////////////////////////////// @@ -72,7 +89,8 @@ operator = (const ButtonEvent ©) { INLINE bool ButtonEvent:: operator == (const ButtonEvent &other) const { return (_button == other._button && - _down == other._down); + _keycode == other._keycode && + _type == other._type); } //////////////////////////////////////////////////////////////////// @@ -95,6 +113,9 @@ operator < (const ButtonEvent &other) const { if (_button != other._button) { return _button < other._button; } + if (_keycode != other._keycode) { + return _keycode < other._keycode; + } - return _down < other._down; + return _type < other._type; } diff --git a/panda/src/putil/buttonEvent.cxx b/panda/src/putil/buttonEvent.cxx index d5dc184607..ca5a724f7d 100644 --- a/panda/src/putil/buttonEvent.cxx +++ b/panda/src/putil/buttonEvent.cxx @@ -25,10 +25,17 @@ //////////////////////////////////////////////////////////////////// void ButtonEvent:: output(ostream &out) const { - out << "button " << _button; - if (_down) { - out << " down"; - } else { - out << " up"; + switch (_type) { + case T_down: + out << "button " << _button << " down"; + break; + + case T_up: + out << "button " << _button << " up"; + break; + + case T_keystroke: + out << "keystroke " << _keycode; + break; } } diff --git a/panda/src/putil/buttonEvent.h b/panda/src/putil/buttonEvent.h index 1476489ced..09023b4319 100644 --- a/panda/src/putil/buttonEvent.h +++ b/panda/src/putil/buttonEvent.h @@ -19,19 +19,47 @@ #ifndef BUTTONEVENT_H #define BUTTONEVENT_H -#include +#include "pandabase.h" #include "buttonHandle.h" //////////////////////////////////////////////////////////////////// // Class : ButtonEvent -// Description : Records a transition of one button from up to down or -// vice-versa. +// Description : Records a button event of some kind. This is either +// a keyboard or mouse button (or some other kind of +// button) changing state from up to down, or +// vice-versa, or it is a single "keystroke". +// +// A keystroke is different than a button event in that +// (a) it does not necessarily correspond to a physical +// button on a keyboard, but might be the result of a +// combination of buttons (e.g. "A" is the result of +// shift + "a"); and (b) it does not manage separate +// "up" and "down" events, but is itself an +// instantaneous event. +// +// Normal up/down button events can be used to track the +// state of a particular button on the keyboard, while +// keystroke events are best used to monitor what a user +// is attempting to type. +// +// Button up/down events are defined across all the +// physical keys on the keyboard (and other buttons for +// which there is a corresponding ButtonHandle object), +// while keystroke events are defined across the entire +// Unicode character set. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA ButtonEvent { public: + enum Type { + T_down, + T_up, + T_keystroke + }; + INLINE ButtonEvent(); - INLINE ButtonEvent(ButtonHandle button, bool down); + INLINE ButtonEvent(ButtonHandle button, Type type); + INLINE ButtonEvent(short keycode); INLINE ButtonEvent(const ButtonEvent ©); INLINE void operator = (const ButtonEvent ©); @@ -41,8 +69,14 @@ public: void output(ostream &out) const; + // _button will be filled in if type is T_down or T_up. ButtonHandle _button; - bool _down; + + // _keycode will be filled in if type is T_keystroke. It will be + // the Unicode character that was typed. + short _keycode; + + Type _type; }; INLINE ostream &operator << (ostream &out, const ButtonEvent &be) { diff --git a/panda/src/putil/modifierButtons.I b/panda/src/putil/modifierButtons.I index 5e42f94c82..4bac3d2e7c 100644 --- a/panda/src/putil/modifierButtons.I +++ b/panda/src/putil/modifierButtons.I @@ -100,10 +100,15 @@ get_button(int index) const { //////////////////////////////////////////////////////////////////// INLINE bool ModifierButtons:: add_event(const ButtonEvent &event) { - if (event._down) { + switch (event._type) { + case ButtonEvent::T_down: return button_down(event._button); - } else { + + case ButtonEvent::T_up: return button_up(event._button); + + default: + return false; } } diff --git a/panda/src/tform/buttonThrower.cxx b/panda/src/tform/buttonThrower.cxx index bb8156d670..d6b3ca85c0 100644 --- a/panda/src/tform/buttonThrower.cxx +++ b/panda/src/tform/buttonThrower.cxx @@ -335,7 +335,7 @@ transmit_data(AllTransitionsWrapper &data) { const ButtonEvent &be = (*bi); string event_name = be._button.get_name(); - if (be._down) { + if (be._type == ButtonEvent::T_down) { // Button down. if (!_mods.button_down(be._button)) { // We only prepend modifier names on the button-down events, @@ -356,7 +356,7 @@ transmit_data(AllTransitionsWrapper &data) { new_b->push_back(be); } - } else { + } else if (be._type == ButtonEvent::T_up) { // Button up. _mods.button_up(be._button); @@ -376,6 +376,14 @@ transmit_data(AllTransitionsWrapper &data) { } new_b->push_back(be); } + + } else { + // Some other kind of button event (e.g. keypress). Don't + // throw an event for this, but do pass it down. + if (new_b == (ButtonEventDataTransition *)NULL) { + new_b = new ButtonEventDataTransition; + } + new_b->push_back(be); } } } diff --git a/panda/src/tform/driveInterface.cxx b/panda/src/tform/driveInterface.cxx index 69f42254c5..7e5ebc4459 100644 --- a/panda/src/tform/driveInterface.cxx +++ b/panda/src/tform/driveInterface.cxx @@ -435,27 +435,31 @@ transmit_data(AllTransitionsWrapper &data) { ButtonEventDataTransition::const_iterator bi; for (bi = b->begin(); bi != b->end(); ++bi) { const ButtonEvent &be = (*bi); - if (be._down) { - // We only trap button down events if (a) the mouse is in the - // window, and (b) we aren't set to ignore the mouse. - if (got_mouse && !_ignore_mouse) { + if (be._type != ButtonEvent::T_keystroke) { + bool down = (be._type == ButtonEvent::T_down); + + if (down) { + // We only trap button down events if (a) the mouse is in the + // window, and (b) we aren't set to ignore the mouse. + if (got_mouse && !_ignore_mouse) { + _mods.add_event(be); + } + } else { + // However, we always trap button up events, so we don't get + // confused and believe a button is still being held down when + // it is not. _mods.add_event(be); } - } else { - // However, we always trap button up events, so we don't get - // confused and believe a button is still being held down when - // it is not. - _mods.add_event(be); - } - - if (be._button == KeyboardButton::up()) { - _up_arrow.set_key(be._down); - } else if (be._button == KeyboardButton::down()) { - _down_arrow.set_key(be._down); - } else if (be._button == KeyboardButton::left()) { - _left_arrow.set_key(be._down); - } else if (be._button == KeyboardButton::right()) { - _right_arrow.set_key(be._down); + + if (be._button == KeyboardButton::up()) { + _up_arrow.set_key(down); + } else if (be._button == KeyboardButton::down()) { + _down_arrow.set_key(down); + } else if (be._button == KeyboardButton::left()) { + _left_arrow.set_key(down); + } else if (be._button == KeyboardButton::right()) { + _right_arrow.set_key(down); + } } } } diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index b3ec154f50..a46a5fe6d9 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -681,6 +681,37 @@ release(ButtonHandle button) { } } +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcher::keystroke +// Access: Protected +// Description: Records that the indicated keystroke has been +// generated. +//////////////////////////////////////////////////////////////////// +void MouseWatcher:: +keystroke(int keycode) { + MouseWatcherParameter param; + param.set_keycode(keycode); + param.set_modifier_buttons(_mods); + param.set_mouse(_mouse); + + // Send the event to every region that wants keyboard buttons, + // regardless of the mouse position. + if (_preferred_region != (MouseWatcherRegion *)NULL) { + // Our current region, the one under the mouse, always get + // all the keyboard events, even if it doesn't set its + // keyboard flag. + _preferred_region->keystroke(param); + } + + if ((_suppress_flags & MouseWatcherRegion::SF_other_button) == 0) { + // All the other regions only get the keyboard events if they + // set their global keyboard flag, *and* the current region does + // not suppress keyboard buttons. + param.set_outside(true); + global_keystroke(param); + } +} + //////////////////////////////////////////////////////////////////// // Function: MouseWatcher::global_keyboard_press // Access: Protected @@ -712,7 +743,6 @@ global_keyboard_press(const MouseWatcherParameter ¶m) { } } } - //////////////////////////////////////////////////////////////////// // Function: MouseWatcher::global_keyboard_release // Access: Protected @@ -745,6 +775,38 @@ global_keyboard_release(const MouseWatcherParameter ¶m) { } } +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcher::global_keystroke +// Access: Protected +// Description: Calls keystroke() on all regions that are interested +// in receiving global keyboard events, except for the +// current region (which already received this one). +//////////////////////////////////////////////////////////////////// +void MouseWatcher:: +global_keystroke(const MouseWatcherParameter ¶m) { + Regions::const_iterator ri; + for (ri = _regions.begin(); ri != _regions.end(); ++ri) { + MouseWatcherRegion *region = (*ri); + + if (region != _preferred_region && region->get_keyboard()) { + region->keystroke(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 != _preferred_region && region->get_keyboard()) { + region->keystroke(param); + } + } + } +} + //////////////////////////////////////////////////////////////////// // Function: MouseWatcher::enter_region // Access: Protected @@ -835,10 +897,18 @@ transmit_data(AllTransitionsWrapper &data) { const ButtonEvent &be = (*bi); _mods.add_event(be); - if (be._down) { + switch (be._type) { + case ButtonEvent::T_down: press(be._button); - } else { + break; + + case ButtonEvent::T_up: release(be._button); + break; + + case ButtonEvent::T_keystroke: + keystroke(be._keycode); + break; } } } @@ -864,7 +934,8 @@ transmit_data(AllTransitionsWrapper &data) { const ButtonEvent &be = (*bi); bool suppress = true; - if (MouseButton::is_mouse_button(be._button)) { + if (be._type != ButtonEvent::T_keystroke && + MouseButton::is_mouse_button(be._button)) { suppress = ((suppress_buttons & MouseWatcherRegion::SF_mouse_button) != 0); } else { suppress = ((suppress_buttons & MouseWatcherRegion::SF_other_button) != 0); diff --git a/panda/src/tform/mouseWatcher.h b/panda/src/tform/mouseWatcher.h index 0f6656cd36..0dd3f6aad2 100644 --- a/panda/src/tform/mouseWatcher.h +++ b/panda/src/tform/mouseWatcher.h @@ -135,8 +135,10 @@ protected: void press(ButtonHandle button); void release(ButtonHandle button); + void keystroke(int keycode); void global_keyboard_press(const MouseWatcherParameter ¶m); void global_keyboard_release(const MouseWatcherParameter ¶m); + void global_keystroke(const MouseWatcherParameter ¶m); INLINE void within_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m); INLINE void without_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m); diff --git a/panda/src/tform/mouseWatcherParameter.I b/panda/src/tform/mouseWatcherParameter.I index ddae66d2ba..94855dc45a 100644 --- a/panda/src/tform/mouseWatcherParameter.I +++ b/panda/src/tform/mouseWatcherParameter.I @@ -35,6 +35,7 @@ MouseWatcherParameter() { INLINE MouseWatcherParameter:: MouseWatcherParameter(const MouseWatcherParameter ©) : _button(copy._button), + _keycode(copy._keycode), _mods(copy._mods), _mouse(copy._mouse), _flags(copy._flags) @@ -49,6 +50,7 @@ MouseWatcherParameter(const MouseWatcherParameter ©) : INLINE void MouseWatcherParameter:: operator = (const MouseWatcherParameter ©) { _button = copy._button; + _keycode = copy._keycode; _mods = copy._mods; _mouse = copy._mouse; _flags = copy._flags; @@ -75,6 +77,17 @@ set_button(const ButtonHandle &button) { _flags |= F_has_button; } +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherParameter::set_keycode +// Access: Public +// Description: Sets the keycode associated with this event, if any. +//////////////////////////////////////////////////////////////////// +INLINE void MouseWatcherParameter:: +set_keycode(int keycode) { + _keycode = keycode; + _flags |= F_has_keycode; +} + //////////////////////////////////////////////////////////////////// // Function: MouseWatcherParameter::set_modifier_buttons // Access: Public @@ -138,6 +151,28 @@ get_button() const { return _button; } +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherParameter::has_keycode +// Access: Published +// Description: Returns true if this parameter has an associated +// keycode, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool MouseWatcherParameter:: +has_keycode() const { + return (_flags & F_has_keycode) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherParameter::get_keycode +// Access: Published +// Description: Returns the keycode associated with this event. If +// has_keycode(), above, returns false, this returns 0. +//////////////////////////////////////////////////////////////////// +INLINE int MouseWatcherParameter:: +get_keycode() const { + return _keycode; +} + //////////////////////////////////////////////////////////////////// // Function: MouseWatcherParameter::get_modifier_buttons // Access: Published diff --git a/panda/src/tform/mouseWatcherParameter.h b/panda/src/tform/mouseWatcherParameter.h index ef75bc666f..b38a88b888 100644 --- a/panda/src/tform/mouseWatcherParameter.h +++ b/panda/src/tform/mouseWatcherParameter.h @@ -39,6 +39,7 @@ public: INLINE ~MouseWatcherParameter(); INLINE void set_button(const ButtonHandle &button); + INLINE void set_keycode(int keycode); INLINE void set_modifier_buttons(const ModifierButtons &mods); INLINE void set_mouse(const LPoint2f &mouse); INLINE void set_outside(bool flag); @@ -47,6 +48,9 @@ PUBLISHED: INLINE bool has_button() const; INLINE ButtonHandle get_button() const; + INLINE bool has_keycode() const; + INLINE int get_keycode() const; + INLINE const ModifierButtons &get_modifier_buttons() const; INLINE bool has_mouse() const; @@ -58,6 +62,7 @@ PUBLISHED: public: ButtonHandle _button; + short _keycode; ModifierButtons _mods; LPoint2f _mouse; @@ -65,6 +70,7 @@ public: F_has_button = 0x001, F_has_mouse = 0x002, F_is_outside = 0x004, + F_has_keycode = 0x008, }; int _flags; }; diff --git a/panda/src/tform/mouseWatcherRegion.cxx b/panda/src/tform/mouseWatcherRegion.cxx index 79bb3848b1..4fad923c60 100644 --- a/panda/src/tform/mouseWatcherRegion.cxx +++ b/panda/src/tform/mouseWatcherRegion.cxx @@ -117,3 +117,13 @@ press(const MouseWatcherParameter &) { void MouseWatcherRegion:: release(const MouseWatcherParameter &) { } + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherRegion::keystroke +// Access: Public, Virtual +// Description: This is a callback hook function, called whenever a +// keystroke is generated by the user. +//////////////////////////////////////////////////////////////////// +void MouseWatcherRegion:: +keystroke(const MouseWatcherParameter &) { +} diff --git a/panda/src/tform/mouseWatcherRegion.h b/panda/src/tform/mouseWatcherRegion.h index 84dc8bde1f..a384a8fd4e 100644 --- a/panda/src/tform/mouseWatcherRegion.h +++ b/panda/src/tform/mouseWatcherRegion.h @@ -76,6 +76,7 @@ public: virtual void without(const MouseWatcherParameter ¶m); virtual void press(const MouseWatcherParameter ¶m); virtual void release(const MouseWatcherParameter ¶m); + virtual void keystroke(const MouseWatcherParameter ¶m); private: LVecBase4f _frame;