From 85a5be984fc726cd5dd97e404e8333ba410ef632 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 7 Mar 2014 12:52:15 +0000 Subject: [PATCH] Raw button event support, with X11 implementation (untransformed QWERTY) --- .../src/display/graphicsWindowInputDevice.cxx | 22 +++ panda/src/display/graphicsWindowInputDevice.h | 22 +-- panda/src/event/buttonEvent.cxx | 8 ++ panda/src/event/buttonEvent.h | 9 +- panda/src/tform/buttonThrower.I | 47 +++++++ panda/src/tform/buttonThrower.cxx | 48 ++++++- panda/src/tform/buttonThrower.h | 9 +- panda/src/tform/mouseWatcher.cxx | 6 + panda/src/x11display/x11GraphicsWindow.cxx | 131 ++++++++++++++++++ panda/src/x11display/x11GraphicsWindow.h | 1 + 10 files changed, 285 insertions(+), 18 deletions(-) diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index e6f9fdf483..9cbffb3e64 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -365,3 +365,25 @@ focus_lost(double time) { } _buttons_held.clear(); } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindowInputDevice::raw_button_down +// Access: Public +// Description: Records that the indicated button has been depressed. +//////////////////////////////////////////////////////////////////// +void GraphicsWindowInputDevice:: +raw_button_down(ButtonHandle button, double time) { + LightMutexHolder holder(_lock); + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_down, time)); +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindowInputDevice::raw_button_up +// Access: Public +// Description: Records that the indicated button has been released. +//////////////////////////////////////////////////////////////////// +void GraphicsWindowInputDevice:: +raw_button_up(ButtonHandle button, double time) { + LightMutexHolder holder(_lock); + _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_up, time)); +} diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index 367feebd26..99843c32ee 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -45,27 +45,27 @@ public: static GraphicsWindowInputDevice pointer_only(GraphicsWindow *host, const string &name); static GraphicsWindowInputDevice keyboard_only(GraphicsWindow *host, const string &name); static GraphicsWindowInputDevice pointer_and_keyboard(GraphicsWindow *host, const string &name); - + INLINE GraphicsWindowInputDevice(); GraphicsWindowInputDevice(const GraphicsWindowInputDevice ©); void operator = (const GraphicsWindowInputDevice ©); ~GraphicsWindowInputDevice(); - + INLINE string get_name() const; INLINE bool has_pointer() const; INLINE bool has_keyboard() const; INLINE void set_device_index(int index); - + INLINE MouseData get_pointer() const; INLINE MouseData get_raw_pointer() const; - + INLINE void enable_pointer_events(); INLINE void disable_pointer_events(); - + void enable_pointer_mode(double speed); void disable_pointer_mode(); - + bool has_button_event() const; ButtonEvent get_button_event(); bool has_pointer_event() const; @@ -81,6 +81,8 @@ PUBLISHED: void candidate(const wstring &candidate_string, size_t highlight_start, size_t highlight_end, size_t cursor_pos); void focus_lost(double time = ClockObject::get_global_clock()->get_frame_time()); + void raw_button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time()); + void raw_button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time()); INLINE void set_pointer_in_window(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time()); INLINE void set_pointer_out_of_window(double time = ClockObject::get_global_clock()->get_frame_time()); @@ -102,17 +104,17 @@ private: typedef pdeque ButtonEvents; LightMutex _lock; - + GraphicsWindow *_host; - + string _name; int _flags; int _device_index; int _event_sequence; - + bool _pointer_mode_enable; double _pointer_speed; - + bool _enable_pointer_events; MouseData _mouse_data; MouseData _true_mouse_data; diff --git a/panda/src/event/buttonEvent.cxx b/panda/src/event/buttonEvent.cxx index 3a212f34a1..774b5ec0a6 100644 --- a/panda/src/event/buttonEvent.cxx +++ b/panda/src/event/buttonEvent.cxx @@ -55,6 +55,14 @@ output(ostream &out) const { case T_move: out << "move"; break; + + case T_raw_down: + out << "raw button " << _button << " down"; + break; + + case T_raw_up: + out << "raw button " << _button << " up"; + break; } } diff --git a/panda/src/event/buttonEvent.h b/panda/src/event/buttonEvent.h index 7469de0e82..adc395d405 100644 --- a/panda/src/event/buttonEvent.h +++ b/panda/src/event/buttonEvent.h @@ -81,10 +81,17 @@ public: // from a menu. T_candidate, - // T_move is used to indicate that the mouse has moved within the + // T_move is used to indicate that the mouse has moved within the // current region. Button drag mode needs this, others may ignore // this event T_move, + + // T_raw_down is usually sent together with T_down, except that + // this is the original, untransformed scan key sent by the keyboard. + // It is not altered by modifier keys and acts as if the user is + // using the US (qwerty) keyboard layout. + T_raw_down, + T_raw_up, }; INLINE ButtonEvent(); diff --git a/panda/src/tform/buttonThrower.I b/panda/src/tform/buttonThrower.I index 96e7e8434e..b5aa817858 100644 --- a/panda/src/tform/buttonThrower.I +++ b/panda/src/tform/buttonThrower.I @@ -200,6 +200,53 @@ get_move_event() const { return _move_event; } +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_raw_button_down_event +// Access: Published +// Description: Like set_button_down_event, but uses the raw, +// untransformed scan key from the operating system. +// This uses buttons that are independent of the +// user's selected keyboard layout. +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_raw_button_down_event(const string &raw_button_down_event) { + _raw_button_down_event = raw_button_down_event; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_raw_button_down_event +// Access: Published +// Description: Returns the raw_button_down_event that has been set on +// this ButtonThrower. See set_raw_button_down_event(). +//////////////////////////////////////////////////////////////////// +INLINE const string &ButtonThrower:: +get_raw_button_down_event() const { + return _raw_button_down_event; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::set_raw_button_up_event +// Access: Published +// Description: Specifies the generic event that is generated (if +// any) each time a key or button is released. See +// set_raw_button_down_event(). +//////////////////////////////////////////////////////////////////// +INLINE void ButtonThrower:: +set_raw_button_up_event(const string &raw_button_up_event) { + _raw_button_up_event = raw_button_up_event; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonThrower::get_raw_button_up_event +// Access: Published +// Description: Returns the raw_button_up_event that has been set on +// this ButtonThrower. See set_raw_button_up_event(). +//////////////////////////////////////////////////////////////////// +INLINE const string &ButtonThrower:: +get_raw_button_up_event() const { + return _raw_button_up_event; +} + //////////////////////////////////////////////////////////////////// // Function: ButtonThrower::set_prefix // Access: Published diff --git a/panda/src/tform/buttonThrower.cxx b/panda/src/tform/buttonThrower.cxx index b0e1d1452f..4d52caebcd 100644 --- a/panda/src/tform/buttonThrower.cxx +++ b/panda/src/tform/buttonThrower.cxx @@ -268,16 +268,16 @@ void ButtonThrower:: do_specific_event(const string &event_name, double time) { if (_specific_flag) { PT(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); } - + throw_event(event); } } @@ -318,6 +318,14 @@ do_general_event(const ButtonEvent &button_event, const string &button_name) { case ButtonEvent::T_move: event_name = _move_event; break; + + case ButtonEvent::T_raw_down: + event_name = _raw_button_down_event; + break; + + case ButtonEvent::T_raw_up: + event_name = _raw_button_up_event; + break; } if (event_name.empty()) { // This general event is not configured. @@ -336,6 +344,8 @@ do_general_event(const ButtonEvent &button_event, const string &button_name) { case ButtonEvent::T_resume_down: case ButtonEvent::T_up: case ButtonEvent::T_repeat: + case ButtonEvent::T_raw_down: + case ButtonEvent::T_raw_up: event->add_parameter(button_name); break; @@ -405,7 +415,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, do_specific_event(event_name, be._time); } do_general_event(be, event_name); - + } else { // Don't process this button; instead, pass it down to future // generations. @@ -418,7 +428,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, // throw an event now (since we already missed it), but do // make sure our modifiers are up-to-date. _mods.button_down(be._button); - + } else if (be._type == ButtonEvent::T_up) { // Button up. _mods.button_up(be._button); @@ -438,6 +448,34 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, _button_events->add_event(be); } + } else if (be._type == ButtonEvent::T_raw_down) { + // Raw button down. + if (!_throw_buttons_active || has_throw_button(be._button)) { + // Process this button. + do_specific_event("raw-" + event_name, be._time); + do_general_event(be, event_name); + + } else { + // Don't process this button; instead, pass it down to future + // generations. + _button_events->add_event(be); + } + + } else if (be._type == ButtonEvent::T_raw_up) { + // Raw button up. + if (!_throw_buttons_active || has_throw_button(be._button)) { + // Process this button. + do_specific_event("raw-" + event_name + "-up", be._time); + do_general_event(be, event_name); + } + if (_throw_buttons_active) { + // Now pass the event on to future generations. We always + // pass "up" events, even if we are intercepting this + // particular button; unless we're processing all buttons in + // which case it doesn't matter. + _button_events->add_event(be); + } + } else { // Some other kind of button event (e.g. keypress). Don't // throw an event for this, but do pass it down. diff --git a/panda/src/tform/buttonThrower.h b/panda/src/tform/buttonThrower.h index 59b19b7bbf..b779406b05 100644 --- a/panda/src/tform/buttonThrower.h +++ b/panda/src/tform/buttonThrower.h @@ -53,6 +53,10 @@ PUBLISHED: INLINE const string &get_candidate_event() const; INLINE void set_move_event(const string &move_event); INLINE const string &get_move_event() const; + INLINE void set_raw_button_down_event(const string &raw_button_down_event); + INLINE const string &get_raw_button_down_event() const; + INLINE void set_raw_button_up_event(const string &raw_button_up_event); + INLINE const string &get_raw_button_up_event() const; INLINE void set_prefix(const string &prefix); INLINE const string &get_prefix() const; @@ -61,7 +65,6 @@ PUBLISHED: 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; @@ -85,7 +88,7 @@ public: private: void do_specific_event(const string &event_name, double time); - void do_general_event(const ButtonEvent &button_event, + void do_general_event(const ButtonEvent &button_event, const string &event_name); private: @@ -95,6 +98,8 @@ private: string _keystroke_event; string _candidate_event; string _move_event; + string _raw_button_up_event; + string _raw_button_down_event; bool _specific_flag; string _prefix; bool _time_flag; diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index 58de969a8e..f0b5f9d34e 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -1539,6 +1539,12 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, case ButtonEvent::T_move: // This is handled below. break; + + case ButtonEvent::T_raw_down: + case ButtonEvent::T_raw_up: + // These are passed through. + new_button_events.add_event(be); + break; } } } diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 27819dbf84..41d6a145be 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -1404,6 +1404,11 @@ handle_keypress(XKeyEvent &event) { if (button != ButtonHandle::none()) { _input_devices[0].button_down(button); } + + ButtonHandle raw_button = map_raw_button(event.keycode); + if (raw_button != ButtonHandle::none()) { + _input_devices[0].raw_button_down(raw_button); + } } //////////////////////////////////////////////////////////////////// @@ -1432,6 +1437,11 @@ handle_keyrelease(XKeyEvent &event) { if (button != ButtonHandle::none()) { _input_devices[0].button_up(button); } + + ButtonHandle raw_button = map_raw_button(event.keycode); + if (raw_button != ButtonHandle::none()) { + _input_devices[0].raw_button_up(raw_button); + } } //////////////////////////////////////////////////////////////////// @@ -1839,6 +1849,127 @@ map_button(KeySym key) { return ButtonHandle::none(); } +//////////////////////////////////////////////////////////////////// +// Function: x11GraphicsWindow::map_raw_button +// Access: Private +// Description: Maps from a single X keycode to Panda's ButtonHandle. +//////////////////////////////////////////////////////////////////// +ButtonHandle x11GraphicsWindow:: +map_raw_button(KeyCode key) { + switch (key) { + case 9: return KeyboardButton::escape(); + case 10: return KeyboardButton::ascii_key('1'); + case 11: return KeyboardButton::ascii_key('2'); + case 12: return KeyboardButton::ascii_key('3'); + case 13: return KeyboardButton::ascii_key('4'); + case 14: return KeyboardButton::ascii_key('5'); + case 15: return KeyboardButton::ascii_key('6'); + case 16: return KeyboardButton::ascii_key('7'); + case 17: return KeyboardButton::ascii_key('8'); + case 18: return KeyboardButton::ascii_key('9'); + case 19: return KeyboardButton::ascii_key('0'); + case 20: return KeyboardButton::ascii_key('-'); + case 21: return KeyboardButton::ascii_key('='); + case 22: return KeyboardButton::backspace(); + case 23: return KeyboardButton::tab(); + case 24: return KeyboardButton::ascii_key('q'); + case 25: return KeyboardButton::ascii_key('w'); + case 26: return KeyboardButton::ascii_key('e'); + case 27: return KeyboardButton::ascii_key('r'); + case 28: return KeyboardButton::ascii_key('t'); + case 29: return KeyboardButton::ascii_key('y'); + case 30: return KeyboardButton::ascii_key('u'); + case 31: return KeyboardButton::ascii_key('i'); + case 32: return KeyboardButton::ascii_key('o'); + case 33: return KeyboardButton::ascii_key('p'); + case 34: return KeyboardButton::ascii_key('['); + case 35: return KeyboardButton::ascii_key(']'); + case 36: return KeyboardButton::enter(); + case 37: return KeyboardButton::lcontrol(); + case 38: return KeyboardButton::ascii_key('a'); + case 39: return KeyboardButton::ascii_key('s'); + case 40: return KeyboardButton::ascii_key('d'); + case 41: return KeyboardButton::ascii_key('f'); + case 42: return KeyboardButton::ascii_key('g'); + case 43: return KeyboardButton::ascii_key('h'); + case 44: return KeyboardButton::ascii_key('j'); + case 45: return KeyboardButton::ascii_key('k'); + case 46: return KeyboardButton::ascii_key('l'); + case 47: return KeyboardButton::ascii_key(';'); + case 48: return KeyboardButton::ascii_key('\''); + case 49: return KeyboardButton::ascii_key('`'); + case 50: return KeyboardButton::lshift(); + case 51: return KeyboardButton::ascii_key('\\'); + case 52: return KeyboardButton::ascii_key('z'); + case 53: return KeyboardButton::ascii_key('x'); + case 54: return KeyboardButton::ascii_key('c'); + case 55: return KeyboardButton::ascii_key('v'); + case 56: return KeyboardButton::ascii_key('b'); + case 57: return KeyboardButton::ascii_key('n'); + case 58: return KeyboardButton::ascii_key('m'); + case 59: return KeyboardButton::ascii_key(','); + case 60: return KeyboardButton::ascii_key('.'); + case 61: return KeyboardButton::ascii_key('/'); + case 62: return KeyboardButton::rshift(); + case 63: return KeyboardButton::ascii_key('*'); + case 64: return KeyboardButton::lalt(); + case 65: return KeyboardButton::space(); + case 66: return KeyboardButton::caps_lock(); + case 67: return KeyboardButton::f1(); + case 68: return KeyboardButton::f2(); + case 69: return KeyboardButton::f3(); + case 70: return KeyboardButton::f4(); + case 71: return KeyboardButton::f5(); + case 72: return KeyboardButton::f6(); + case 73: return KeyboardButton::f7(); + case 74: return KeyboardButton::f8(); + case 75: return KeyboardButton::f9(); + case 76: return KeyboardButton::f10(); + case 77: return KeyboardButton::num_lock(); + case 78: return KeyboardButton::scroll_lock(); + case 79: return KeyboardButton::ascii_key('7'); + case 80: return KeyboardButton::ascii_key('8'); + case 81: return KeyboardButton::ascii_key('9'); + case 82: return KeyboardButton::ascii_key('-'); + case 83: return KeyboardButton::ascii_key('4'); + case 84: return KeyboardButton::ascii_key('5'); + case 85: return KeyboardButton::ascii_key('6'); + case 86: return KeyboardButton::ascii_key('+'); + case 87: return KeyboardButton::ascii_key('1'); + case 88: return KeyboardButton::ascii_key('2'); + case 89: return KeyboardButton::ascii_key('3'); + case 90: return KeyboardButton::ascii_key('0'); + case 91: return KeyboardButton::ascii_key('.'); + + case 95: return KeyboardButton::f11(); + case 96: return KeyboardButton::f12(); + + case 104: return KeyboardButton::enter(); + case 105: return KeyboardButton::rcontrol(); + case 106: return KeyboardButton::ascii_key('/'); + case 107: return KeyboardButton::print_screen(); + case 108: return KeyboardButton::ralt(); + + case 110: return KeyboardButton::home(); + case 111: return KeyboardButton::up(); + case 112: return KeyboardButton::page_up(); + case 113: return KeyboardButton::left(); + case 114: return KeyboardButton::right(); + case 115: return KeyboardButton::end(); + case 116: return KeyboardButton::down(); + case 117: return KeyboardButton::page_down(); + case 118: return KeyboardButton::insert(); + case 119: return KeyboardButton::del(); + + case 127: return KeyboardButton::pause(); + + //case 133: return KeyboardButton::lmeta(); + //case 134: return KeyboardButton::rmeta(); + //case 135: return KeyboardButton::menu(); + } + return ButtonHandle::none(); +} + //////////////////////////////////////////////////////////////////// // Function: x11GraphicsWindow::get_mouse_button // Access: Private diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index d99d6fe2b1..e5f51d9cf3 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -67,6 +67,7 @@ protected: ButtonHandle get_button(XKeyEvent &key_event, bool allow_shift); ButtonHandle map_button(KeySym key); + ButtonHandle map_raw_button(KeyCode key); ButtonHandle get_mouse_button(XButtonEvent &button_event); static Bool check_event(X11_Display *display, XEvent *event, char *arg);