From 038230f7ec280ceef0f7c034da9f9dab2d7b06c4 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 26 Dec 2003 20:26:56 +0000 Subject: [PATCH] add support for OS time for keypress/release --- direct/src/showbase/ShowBase.py | 14 ++ .../src/display/graphicsWindowInputDevice.cxx | 16 +- panda/src/display/graphicsWindowInputDevice.h | 9 +- panda/src/putil/buttonEvent.I | 20 ++- panda/src/putil/buttonEvent.h | 12 +- panda/src/tform/Sources.pp | 4 +- panda/src/tform/buttonThrower.I | 148 ++++++++++++++++++ panda/src/tform/buttonThrower.cxx | 114 +------------- panda/src/tform/buttonThrower.h | 23 ++- panda/src/windisplay/winGraphicsWindow.I | 28 +++- panda/src/windisplay/winGraphicsWindow.cxx | 27 ++-- panda/src/windisplay/winGraphicsWindow.h | 8 +- 12 files changed, 268 insertions(+), 155 deletions(-) create mode 100644 panda/src/tform/buttonThrower.I diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 8b02110e15..fe190f3f1c 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -594,6 +594,20 @@ class ShowBase(DirectObject.DirectObject): mods.addButton(KeyboardButton.alt()) self.buttonThrower.node().setModifierButtons(mods) + # A special ButtonThrower to generate keyboard events and + # include the time from the OS. This is separate only to + # support legacy code that did not expect a time parameter; it + # will eventually be folded into the normal ButtonThrower, + # above. + + # Temporary hasattr() for old pandas. + if hasattr(ButtonThrower, "setTimeFlag"): + self.timeButtonThrower = self.mouseWatcher.attachNewNode(ButtonThrower('timeButtons')) + self.timeButtonThrower.node().setPrefix('time-') + self.timeButtonThrower.node().setTimeFlag(1) + else: + self.timeButtonThrower = None + # Tell the gui system about our new mouse watcher. self.aspect2d.node().setMouseWatcher(self.mouseWatcherNode) self.mouseWatcherNode.addRegion(PGMouseWatcherBackground()) diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index df63a2a0f3..8c9172a50b 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -154,8 +154,8 @@ get_button_event() { // Description: Records that the indicated button has been depressed. //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: -button_down(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_down)); +button_down(ButtonHandle button, double time) { + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_down, time)); } //////////////////////////////////////////////////////////////////// @@ -167,8 +167,8 @@ button_down(ButtonHandle button) { // state of modifier keys. //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: -button_resume_down(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down)); +button_resume_down(ButtonHandle button, double time) { + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time)); } //////////////////////////////////////////////////////////////////// @@ -177,8 +177,8 @@ button_resume_down(ButtonHandle button) { // Description: Records that the indicated button has been released. //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: -button_up(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_up)); +button_up(ButtonHandle button, double time) { + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_up, time)); } //////////////////////////////////////////////////////////////////// @@ -188,6 +188,6 @@ button_up(ButtonHandle button) { // generated. //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: -keystroke(int keycode) { - _button_events.push_back(ButtonEvent(keycode)); +keystroke(int keycode, double time) { + _button_events.push_back(ButtonEvent(keycode, time)); } diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index e34adbd50c..fc02b715ad 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -23,6 +23,7 @@ #include "buttonEvent.h" #include "mouseData.h" +#include "clockObject.h" #include "pdeque.h" #include "pvector.h" @@ -61,10 +62,10 @@ public: public: // The following interface is for the various kinds of // GraphicsWindows to record the data incoming on the device. - void button_down(ButtonHandle button); - void button_resume_down(ButtonHandle button); - void button_up(ButtonHandle button); - void keystroke(int keycode); + void button_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 keystroke(int keycode, 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/putil/buttonEvent.I b/panda/src/putil/buttonEvent.I index d6e5efc1a7..4ace4d2fbc 100644 --- a/panda/src/putil/buttonEvent.I +++ b/panda/src/putil/buttonEvent.I @@ -26,7 +26,8 @@ INLINE ButtonEvent:: ButtonEvent() : _button(ButtonHandle::none()), _keycode(0), - _type(T_down) + _type(T_down), + _time(0.0) { } @@ -36,10 +37,11 @@ ButtonEvent() : // Description: //////////////////////////////////////////////////////////////////// INLINE ButtonEvent:: -ButtonEvent(ButtonHandle button, ButtonEvent::Type type) : +ButtonEvent(ButtonHandle button, ButtonEvent::Type type, double time) : _button(button), _keycode(0), - _type(type) + _type(type), + _time(time) { } @@ -49,10 +51,11 @@ ButtonEvent(ButtonHandle button, ButtonEvent::Type type) : // Description: //////////////////////////////////////////////////////////////////// INLINE ButtonEvent:: -ButtonEvent(short keycode) : +ButtonEvent(short keycode, double time) : _button(ButtonHandle::none()), _keycode(keycode), - _type(T_keystroke) + _type(T_keystroke), + _time(time) { } @@ -65,7 +68,8 @@ INLINE ButtonEvent:: ButtonEvent(const ButtonEvent ©) : _button(copy._button), _keycode(copy._keycode), - _type(copy._type) + _type(copy._type), + _time(copy._time) { } @@ -79,12 +83,14 @@ operator = (const ButtonEvent ©) { _button = copy._button; _keycode = copy._keycode; _type = copy._type; + _time = copy._time; } //////////////////////////////////////////////////////////////////// // Function: ButtonEvent::Equality Operator // Access: Public -// Description: +// Description: The equality operator does not consider time +// significant. //////////////////////////////////////////////////////////////////// INLINE bool ButtonEvent:: operator == (const ButtonEvent &other) const { diff --git a/panda/src/putil/buttonEvent.h b/panda/src/putil/buttonEvent.h index 482099be76..be34b3d0c9 100644 --- a/panda/src/putil/buttonEvent.h +++ b/panda/src/putil/buttonEvent.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "buttonHandle.h" +#include "clockObject.h" //////////////////////////////////////////////////////////////////// // Class : ButtonEvent @@ -71,8 +72,8 @@ public: }; INLINE ButtonEvent(); - INLINE ButtonEvent(ButtonHandle button, Type type); - INLINE ButtonEvent(short keycode); + 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 ButtonEvent ©); INLINE void operator = (const ButtonEvent ©); @@ -90,7 +91,14 @@ public: // the Unicode character that was typed. short _keycode; + // This is the type of the button event (see above). Type _type; + + // This is the time the event occurred, as recorded from the OS if + // that information is available. It is in seconds elapsed from an + // arbitrary epoch, and it matches the time reported by + // ClockObject::get_global_clock(). + double _time; }; INLINE ostream &operator << (ostream &out, const ButtonEvent &be) { diff --git a/panda/src/tform/Sources.pp b/panda/src/tform/Sources.pp index d5382a3c48..441d5e324c 100644 --- a/panda/src/tform/Sources.pp +++ b/panda/src/tform/Sources.pp @@ -10,7 +10,7 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ - buttonThrower.h \ + buttonThrower.I buttonThrower.h \ config_tform.h \ driveInterface.I driveInterface.h \ mouseWatcher.I mouseWatcher.h \ @@ -31,7 +31,7 @@ transform2sg.cxx #define INSTALL_HEADERS \ - buttonThrower.h \ + buttonThrower.I buttonThrower.h \ driveInterface.I driveInterface.h \ mouseWatcher.I mouseWatcher.h \ mouseWatcherGroup.h \ diff --git a/panda/src/tform/buttonThrower.I b/panda/src/tform/buttonThrower.I new file mode 100644 index 0000000000..17e11ac036 --- /dev/null +++ b/panda/src/tform/buttonThrower.I @@ -0,0 +1,148 @@ +// Filename: buttonThrower.I +// Created by: drose (26Dec03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_prefix +// Access: Published +// Description: Sets the prefix which is prepended to all event names +// thrown by this object. +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_prefix(const string &prefix) { + _prefix = prefix; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::has_prefix +// Access: Published +// Description: Returns true if the ButtonThrower has a prefix set, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonThrower:: +has_prefix() const { + return !_prefix.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_prefix +// Access: Published +// Description: Returns the prefix that has been set on this +// ButtonThrower. See set_prefix(). +//////////////////////////////////////////////////////////////////// +INLINE string ButtonThrower:: +get_prefix() const { + return _prefix; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_time_flag +// Access: Published +// Description: Sets the flag that indicates whether the time of the +// button event should be passed as a parameter or not. +// When this is true, an additional parameter is +// generated on each event (before all the parameters +// named by add_parameter) that consists of a single +// double value, and reflects the time the button was +// pressed or released, as a value from +// ClockObject::get_global_clock(). +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_time_flag(bool time_flag) { + _time_flag = time_flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_time_flag +// Access: Published +// Description: Returns the flag that indicates whether the time of +// the button event should be passed as a parameter. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonThrower:: +get_time_flag() const { + return _time_flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_modifier_buttons +// Access: Published +// Description: Returns the set of ModifierButtons that the +// ButtonThrower will consider important enough to +// prepend the event name with. Normally, this set will +// be empty, and the ButtonThrower will therefore ignore +// all ModifierButtons attached to the key events, but +// if one or more buttons have been added to this set, +// and those modifier buttons are set on the button +// event, then the event name will be prepended with the +// names of the modifier buttons. +//////////////////////////////////////////////////////////////////// +INLINE const ModifierButtons &ButtonThrower:: +get_modifier_buttons() const { + return _mods; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_modifier_buttons +// Access: Published +// Description: Changes the set of ModifierButtons that the +// ButtonThrower will consider important enough to +// prepend the event name with. Normally, this set will +// be empty, and the ButtonThrower will therefore ignore +// all ModifierButtons attached to the key events, but +// if one or more buttons have been added to this set, +// then the event name will be prepended with the names +// of the modifier buttons. +// +// It is recommended that you change this setting by +// first calling get_modifier_buttons(), making +// adjustments, and passing the new value to +// set_modifier_buttons(). This way the current state +// of the modifier buttons will not be lost. +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_modifier_buttons(const ModifierButtons &mods) { + _mods = mods; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_throw_buttons_active +// Access: Published +// Description: Sets the flag that indicates whether the +// ButtonThrower will only process events for the +// explicitly named buttons or not. Normally this is +// false, meaning all buttons are processed; set it true +// to indicate that only some buttons should be +// processed. See add_throw_button(). +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_throw_buttons_active(bool flag) { + _throw_buttons_active = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_throw_buttons_active +// Access: Published +// Description: Returns the flag that indicates whether the +// ButtonThrower will only process events for the +// explicitly named buttons or not. See +// set_throw_buttons_active(). +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonThrower:: +get_throw_buttons_active() const { + return _throw_buttons_active; +} diff --git a/panda/src/tform/buttonThrower.cxx b/panda/src/tform/buttonThrower.cxx index 35a502470e..728a118432 100644 --- a/panda/src/tform/buttonThrower.cxx +++ b/panda/src/tform/buttonThrower.cxx @@ -43,6 +43,7 @@ ButtonThrower(const string &name) : _button_events = new ButtonEventList; + _time_flag = false; _throw_buttons_active = false; } @@ -56,40 +57,6 @@ ButtonThrower:: } -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::set_prefix -// Access: Published -// Description: Sets the prefix which is prepended to all event names -// thrown by this object. -//////////////////////////////////////////////////////////////////// -void ButtonThrower:: -set_prefix(const string &prefix) { - _prefix = prefix; -} - - -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::has_prefix -// Access: Published -// Description: Returns true if the ButtonThrower has a prefix set, -// false otherwise. -//////////////////////////////////////////////////////////////////// -bool ButtonThrower:: -has_prefix() const { - return !_prefix.empty(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::get_prefix -// Access: Published -// Description: Returns the prefix that has been set on this -// ButtonThrower. See set_prefix(). -//////////////////////////////////////////////////////////////////// -string ButtonThrower:: -get_prefix() const { - return _prefix; -} - //////////////////////////////////////////////////////////////////// // Function: ButtonThrower::add_parameter // Access: Public @@ -128,75 +95,6 @@ get_parameter(int n) const { return _parameters[n]; } -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::get_modifier_buttons -// Access: Published -// Description: Returns the set of ModifierButtons that the -// ButtonThrower will consider important enough to -// prepend the event name with. Normally, this set will -// be empty, and the ButtonThrower will therefore ignore -// all ModifierButtons attached to the key events, but -// if one or more buttons have been added to this set, -// and those modifier buttons are set on the button -// event, then the event name will be prepended with the -// names of the modifier buttons. -//////////////////////////////////////////////////////////////////// -const ModifierButtons &ButtonThrower:: -get_modifier_buttons() const { - return _mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::set_modifier_buttons -// Access: Published -// Description: Changes the set of ModifierButtons that the -// ButtonThrower will consider important enough to -// prepend the event name with. Normally, this set will -// be empty, and the ButtonThrower will therefore ignore -// all ModifierButtons attached to the key events, but -// if one or more buttons have been added to this set, -// then the event name will be prepended with the names -// of the modifier buttons. -// -// It is recommended that you change this setting by -// first calling get_modifier_buttons(), making -// adjustments, and passing the new value to -// set_modifier_buttons(). This way the current state -// of the modifier buttons will not be lost. -//////////////////////////////////////////////////////////////////// -void ButtonThrower:: -set_modifier_buttons(const ModifierButtons &mods) { - _mods = mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::set_throw_buttons_active -// Access: Published -// Description: Sets the flag that indicates whether the -// ButtonThrower will only process events for the -// explicitly named buttons or not. Normally this is -// false, meaning all buttons are processed; set it true -// to indicate that only some buttons should be -// processed. See add_throw_button(). -//////////////////////////////////////////////////////////////////// -void ButtonThrower:: -set_throw_buttons_active(bool flag) { - _throw_buttons_active = flag; -} - -//////////////////////////////////////////////////////////////////// -// Function: ButtonThrower::get_throw_buttons_active -// Access: Published -// Description: Returns the flag that indicates whether the -// ButtonThrower will only process events for the -// explicitly named buttons or not. See -// set_throw_buttons_active(). -//////////////////////////////////////////////////////////////////// -bool ButtonThrower:: -get_throw_buttons_active() const { - return _throw_buttons_active; -} - //////////////////////////////////////////////////////////////////// // Function: ButtonThrower::add_throw_button // Access: Published @@ -370,9 +268,13 @@ write(ostream &out, int indent_level) const { // all of the user-requested parameters. //////////////////////////////////////////////////////////////////// void ButtonThrower:: -do_throw_event(const string &event_name) { +do_throw_event(const string &event_name, double time) { Event *event = new Event(_prefix + event_name); + if (_time_flag) { + event->add_parameter(time); + } + ParameterList::const_iterator pi; for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) { event->add_parameter(*pi); @@ -419,7 +321,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { if (!_throw_buttons_active || has_throw_button(_mods, be._button)) { // Process this button. - do_throw_event(event_name); + do_throw_event(event_name, be._time); } else { // Don't process this button; instead, pass it down to future @@ -442,7 +344,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { // definition for the button at all, regardless of the state // of the modifier keys. if (!_throw_buttons_active || has_throw_button(be._button)) { - do_throw_event(event_name + "-up"); + do_throw_event(event_name + "-up", be._time); } if (_throw_buttons_active) { // Now pass the event on to future generations. We always diff --git a/panda/src/tform/buttonThrower.h b/panda/src/tform/buttonThrower.h index e6b504dd82..a8a46ccc42 100644 --- a/panda/src/tform/buttonThrower.h +++ b/panda/src/tform/buttonThrower.h @@ -45,19 +45,22 @@ PUBLISHED: ButtonThrower(const string &name); ~ButtonThrower(); - void set_prefix(const string &prefix); - bool has_prefix() const; - string get_prefix() const; + INLINE void set_prefix(const string &prefix); + INLINE bool has_prefix() const; + INLINE string get_prefix() const; + + INLINE void set_time_flag(bool time_flag); + INLINE bool get_time_flag() const; void add_parameter(const EventParameter &obj); int get_num_parameters() const; EventParameter get_parameter(int n) const; - const ModifierButtons &get_modifier_buttons() const; - void set_modifier_buttons(const ModifierButtons &mods); + INLINE const ModifierButtons &get_modifier_buttons() const; + INLINE void set_modifier_buttons(const ModifierButtons &mods); - void set_throw_buttons_active(bool flag); - bool get_throw_buttons_active() const; + INLINE void set_throw_buttons_active(bool flag); + INLINE bool get_throw_buttons_active() const; bool add_throw_button(const ModifierButtons &mods, const ButtonHandle &button); bool remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button); @@ -69,12 +72,14 @@ public: virtual void write(ostream &out, int indent_level = 0) const; private: - void do_throw_event(const string &event_name); + void do_throw_event(const string &event_name, double time); private: string _prefix; ModifierButtons _mods; + bool _time_flag; + typedef pvector ParameterList; ParameterList _parameters; @@ -114,4 +119,6 @@ private: static TypeHandle _type_handle; }; +#include "buttonThrower.I" + #endif diff --git a/panda/src/windisplay/winGraphicsWindow.I b/panda/src/windisplay/winGraphicsWindow.I index a925e658f0..f02a637aad 100644 --- a/panda/src/windisplay/winGraphicsWindow.I +++ b/panda/src/windisplay/winGraphicsWindow.I @@ -23,10 +23,10 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE void WinGraphicsWindow:: -handle_keypress(ButtonHandle key, int x, int y) { +handle_keypress(ButtonHandle key, int x, int y, double time) { _input_devices[0].set_pointer_in_window(x, y); if (key != ButtonHandle::none()) { - _input_devices[0].button_down(key); + _input_devices[0].button_down(key, time); } } @@ -38,9 +38,9 @@ handle_keypress(ButtonHandle key, int x, int y) { // tracking the state of modifier keys. //////////////////////////////////////////////////////////////////// INLINE void WinGraphicsWindow:: -handle_keyresume(ButtonHandle key) { +handle_keyresume(ButtonHandle key, double time) { if (key != ButtonHandle::none()) { - _input_devices[0].button_resume_down(key); + _input_devices[0].button_resume_down(key, time); } } @@ -50,9 +50,9 @@ handle_keyresume(ButtonHandle key) { // Description: //////////////////////////////////////////////////////////////////// INLINE void WinGraphicsWindow:: -handle_keyrelease(ButtonHandle key) { +handle_keyrelease(ButtonHandle key, double time) { if (key != ButtonHandle::none()) { - _input_devices[0].button_up(key); + _input_devices[0].button_up(key, time); } } @@ -108,3 +108,19 @@ set_cursor_out_of_window() { update_cursor_window(NULL); } } + +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::get_message_time +// Access: Private, Static +// Description: May be called only during the servicing of a Windows +// message. This returns the time the message was added +// to the Windows message queue (as reported via +// GetMessageTime()), converted into global clock units. +//////////////////////////////////////////////////////////////////// +INLINE double WinGraphicsWindow:: +get_message_time() { + DWORD now_ticks = GetTickCount(); + double now_time = ClockObject::get_global_clock()->get_real_time(); + DWORD elapsed_ticks = now_ticks - GetMessageTime(); + return now_time - (double)elapsed_ticks / 1000.0; +} diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index c4adfc07ad..ddb521137d 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -782,7 +782,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } SetCapture(hwnd); handle_keypress(MouseButton::button(button), - translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); + translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)), + get_message_time()); break; case WM_LBUTTONUP: @@ -801,7 +802,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { button = 2; } ReleaseCapture(); - handle_keyrelease(MouseButton::button(button)); + handle_keyrelease(MouseButton::button(button), get_message_time()); break; case WM_IME_NOTIFY: @@ -913,7 +914,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { POINT point; GetCursorPos(&point); ScreenToClient(hwnd, &point); - handle_keypress(lookup_key(wparam), point.x, point.y); + handle_keypress(lookup_key(wparam), point.x, point.y, + get_message_time()); if (wparam == VK_F10) { // bypass default windproc F10 behavior (it activates the main // menu, but we have none) @@ -944,12 +946,17 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { windisplay_cat.debug() << "keydown: " << wparam << " (" << lookup_key(wparam) << ")\n"; } - { + + // If this bit is not zero, this is just a keyrepeat echo; we + // ignore these for handle_keypress (we respect keyrepeat only + // for handle_keystroke). + if ((lparam & 0x40000000) == 0) { POINT point; GetCursorPos(&point); ScreenToClient(hwnd, &point); - handle_keypress(lookup_key(wparam), point.x, point.y); + handle_keypress(lookup_key(wparam), point.x, point.y, + get_message_time()); // Handle Cntrl-V paste from clipboard. Is there a better way // to detect this hotkey? @@ -987,7 +994,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { windisplay_cat.debug() << "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n"; } - handle_keyrelease(lookup_key(wparam)); + handle_keyrelease(lookup_key(wparam), get_message_time()); break; case WM_KILLFOCUS: @@ -1017,10 +1024,11 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // If we don't want to remember the keystate while the // window focus is lost, then generate a keyup event // right now for each key currently held. + double message_time = get_message_time(); for (int i = 0; i < num_virtual_keys; i++) { if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) { if ((_keyboard_state[i] & 0x80) != 0) { - handle_keyrelease(lookup_key(i)); + handle_keyrelease(lookup_key(i), message_time); _keyboard_state[i] &= ~0x80; } } @@ -1135,6 +1143,7 @@ resend_lost_keypresses() { BYTE new_keyboard_state[num_virtual_keys]; GetKeyboardState(new_keyboard_state); + double message_time = get_message_time(); for (int i = 0; i < num_virtual_keys; i++) { // Filter out these particular three. We don't want to test // these, because these are virtual duplicates for @@ -1152,14 +1161,14 @@ resend_lost_keypresses() { << "key has gone down: " << i << " (" << lookup_key(i) << ")\n"; } - handle_keyresume(lookup_key(i)); + handle_keyresume(lookup_key(i), message_time); } else { // The key is now released. if (windisplay_cat.is_debug()) { windisplay_cat.debug() << "key has gone up: " << i << " (" << lookup_key(i) << ")\n"; } - handle_keyrelease(lookup_key(i)); + handle_keyrelease(lookup_key(i), message_time); } } else { // This key is in the same state. diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index f1dbd9ccae..bc66337ff9 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -85,14 +85,16 @@ private: static void process_1_event(); - INLINE void handle_keypress(ButtonHandle key, int x, int y); - INLINE void handle_keyresume(ButtonHandle key); - INLINE void handle_keyrelease(ButtonHandle key); + INLINE void handle_keypress(ButtonHandle key, int x, int y, double time); + INLINE void handle_keyresume(ButtonHandle key, double time); + INLINE void handle_keyrelease(ButtonHandle key, double time); ButtonHandle lookup_key(WPARAM wparam) const; INLINE int translate_mouse(int pos) const; INLINE void set_cursor_in_window(); INLINE void set_cursor_out_of_window(); + INLINE static double get_message_time(); + void resend_lost_keypresses(); static void update_cursor_window(WinGraphicsWindow *to_window);