diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 8fe92440bc..d11d0825bd 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3641,6 +3641,21 @@ if (not RUNTIME): TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph']) TargetAdd('libp3dgraph_igate.obj', input='libp3dgraph.in', opts=["DEPENDENCYONLY"]) +# +# DIRECTORY: panda/src/device/ +# + +if (not RUNTIME): + OPTS=['DIR:panda/src/device', 'BUILDING:PANDA'] + TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx') + TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx') + + OPTS=['DIR:panda/src/device'] + IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"]) + TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES) + TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device']) + TargetAdd('libp3device_igate.obj', input='libp3device.in', opts=["DEPENDENCYONLY"]) + # # DIRECTORY: panda/src/display/ # @@ -3665,21 +3680,6 @@ if (not RUNTIME): TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx') TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj') -# -# DIRECTORY: panda/src/device/ -# - -if (not RUNTIME): - OPTS=['DIR:panda/src/device', 'BUILDING:PANDA'] - TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx') - TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx') - - OPTS=['DIR:panda/src/device'] - IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device']) - TargetAdd('libp3device_igate.obj', input='libp3device.in', opts=["DEPENDENCYONLY"]) - # # DIRECTORY: panda/src/pnmtext/ # diff --git a/panda/src/device/analogNode.I b/panda/src/device/analogNode.I index 9747587b73..ebc382fce3 100644 --- a/panda/src/device/analogNode.I +++ b/panda/src/device/analogNode.I @@ -44,10 +44,7 @@ is_valid() const { //////////////////////////////////////////////////////////////////// INLINE int AnalogNode:: get_num_controls() const { - _analog->acquire(); - int result = _analog->get_num_controls(); - _analog->unlock(); - return result; + return _analog->get_num_controls(); } //////////////////////////////////////////////////////////////////// @@ -60,10 +57,7 @@ get_num_controls() const { //////////////////////////////////////////////////////////////////// INLINE double AnalogNode:: get_control_state(int index) const { - _analog->acquire(); - double result = _analog->get_control_state(index); - _analog->unlock(); - return result; + return _analog->get_control_state(index); } //////////////////////////////////////////////////////////////////// @@ -75,10 +69,7 @@ get_control_state(int index) const { //////////////////////////////////////////////////////////////////// INLINE bool AnalogNode:: is_control_known(int index) const { - _analog->acquire(); - bool result = _analog->is_control_known(index); - _analog->unlock(); - return result; + return _analog->is_control_known(index); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/device/analogNode.cxx b/panda/src/device/analogNode.cxx index 1bea47ceb2..6d2cef3f67 100644 --- a/panda/src/device/analogNode.cxx +++ b/panda/src/device/analogNode.cxx @@ -30,7 +30,7 @@ AnalogNode(ClientBase *client, const string &device_name) : DataNode(device_name) { _xy_output = define_output("xy", EventStoreVec2::get_class_type()); - _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f)); + _xy = new EventStoreVec2(LPoint2(0)); nassertv(client != (ClientBase *)NULL); PT(ClientDevice) device = @@ -49,7 +49,23 @@ AnalogNode(ClientBase *client, const string &device_name) : return; } - _analog = DCAST(ClientAnalogDevice, device); + _analog = device; +} + +//////////////////////////////////////////////////////////////////// +// Function: AnalogNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +AnalogNode:: +AnalogNode(InputDevice *device) : + DataNode(device->get_name()), + _analog(device) +{ + _xy_output = define_output("xy", EventStoreVec2::get_class_type()); + _xy = new EventStoreVec2(LPoint2(0)); + + nassertv(device != (InputDevice *)NULL); } //////////////////////////////////////////////////////////////////// @@ -74,9 +90,7 @@ write(ostream &out, int indent_level) const { DataNode::write(out, indent_level); if (_analog != (ClientAnalogDevice *)NULL) { - _analog->acquire(); _analog->write_controls(out, indent_level + 2); - _analog->unlock(); } } @@ -100,8 +114,6 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, _analog->poll(); LPoint2 out(0.0f, 0.0f); - - _analog->acquire(); for (int i = 0; i < max_outputs; i++) { if (_outputs[i]._index >= 0 && _analog->is_control_known(_outputs[i]._index)) { @@ -112,7 +124,6 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, } } } - _analog->unlock(); _xy->set_value(out); output.set_data(_xy_output, EventParameter(_xy)); } diff --git a/panda/src/device/analogNode.h b/panda/src/device/analogNode.h index 216c4ae0d4..ea0a6c573e 100644 --- a/panda/src/device/analogNode.h +++ b/panda/src/device/analogNode.h @@ -45,6 +45,7 @@ class EXPCL_PANDA_DEVICE AnalogNode : public DataNode { PUBLISHED: AnalogNode(ClientBase *client, const string &device_name); + AnalogNode(InputDevice *device); virtual ~AnalogNode(); INLINE bool is_valid() const; @@ -73,7 +74,7 @@ private: enum { max_outputs = 2 }; OutputData _outputs[max_outputs]; - PT(ClientAnalogDevice) _analog; + PT(InputDevice) _analog; protected: // Inherited from DataNode diff --git a/panda/src/device/buttonNode.I b/panda/src/device/buttonNode.I index 27faac8325..2eed86eb26 100644 --- a/panda/src/device/buttonNode.I +++ b/panda/src/device/buttonNode.I @@ -21,7 +21,7 @@ //////////////////////////////////////////////////////////////////// INLINE bool ButtonNode:: is_valid() const { - return (_button != (ClientButtonDevice *)NULL) && _button->is_connected(); + return (_device != (ClientButtonDevice *)NULL) && _device->is_connected(); } //////////////////////////////////////////////////////////////////// @@ -36,10 +36,7 @@ is_valid() const { //////////////////////////////////////////////////////////////////// INLINE int ButtonNode:: get_num_buttons() const { - _button->acquire(); - int result = _button->get_num_buttons(); - _button->unlock(); - return result; + return _device->get_num_buttons(); } //////////////////////////////////////////////////////////////////// @@ -58,9 +55,7 @@ get_num_buttons() const { //////////////////////////////////////////////////////////////////// INLINE void ButtonNode:: set_button_map(int index, ButtonHandle button) { - _button->acquire(); - _button->set_button_map(index, button); - _button->unlock(); + _device->set_button_map(index, button); } //////////////////////////////////////////////////////////////////// @@ -73,10 +68,7 @@ set_button_map(int index, ButtonHandle button) { //////////////////////////////////////////////////////////////////// INLINE ButtonHandle ButtonNode:: get_button_map(int index) const { - _button->acquire(); - ButtonHandle result = _button->get_button_map(index); - _button->unlock(); - return result; + return _device->get_button_map(index); } //////////////////////////////////////////////////////////////////// @@ -88,10 +80,7 @@ get_button_map(int index) const { //////////////////////////////////////////////////////////////////// INLINE bool ButtonNode:: get_button_state(int index) const { - _button->acquire(); - bool result = _button->get_button_state(index); - _button->unlock(); - return result; + return _device->get_button_state(index); } //////////////////////////////////////////////////////////////////// @@ -103,8 +92,5 @@ get_button_state(int index) const { //////////////////////////////////////////////////////////////////// INLINE bool ButtonNode:: is_button_known(int index) const { - _button->acquire(); - bool result = _button->is_button_known(index); - _button->unlock(); - return result; + return _device->is_button_known(index); } diff --git a/panda/src/device/buttonNode.cxx b/panda/src/device/buttonNode.cxx index ebae5309a3..d0306b915e 100644 --- a/panda/src/device/buttonNode.cxx +++ b/panda/src/device/buttonNode.cxx @@ -30,7 +30,6 @@ ButtonNode(ClientBase *client, const string &device_name) : DataNode(device_name) { _button_events_output = define_output("button_events", ButtonEventList::get_class_type()); - _button_events = new ButtonEventList; nassertv(client != (ClientBase *)NULL); PT(ClientDevice) device = @@ -49,7 +48,21 @@ ButtonNode(ClientBase *client, const string &device_name) : return; } - _button = DCAST(ClientButtonDevice, device); + _device = device; +} + +//////////////////////////////////////////////////////////////////// +// Function: ButtonNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +ButtonNode:: +ButtonNode(InputDevice *device) : + DataNode(device->get_name()), + _device(device) +{ + _button_events_output = define_output("button_events", ButtonEventList::get_class_type()); + _device = device; } //////////////////////////////////////////////////////////////////// @@ -59,7 +72,7 @@ ButtonNode(ClientBase *client, const string &device_name) : //////////////////////////////////////////////////////////////////// ButtonNode:: ~ButtonNode() { - // When the _button pointer destructs, the ClientButtonDevice + // When the _device pointer destructs, the ClientButtonDevice // disconnects itself from the ClientBase, and everything that needs // to get turned off does. Magic. } @@ -73,11 +86,9 @@ void ButtonNode:: output(ostream &out) const { DataNode::output(out); - if (_button != (ClientButtonDevice *)NULL) { + if (_device != (InputDevice *)NULL) { out << " ("; - _button->acquire(); - _button->output_buttons(out); - _button->unlock(); + _device->output_buttons(out); out << ")"; } } @@ -91,10 +102,8 @@ void ButtonNode:: write(ostream &out, int indent_level) const { DataNode::write(out, indent_level); - if (_button != (ClientButtonDevice *)NULL) { - _button->acquire(); - _button->write_buttons(out, indent_level + 2); - _button->unlock(); + if (_device != (InputDevice *)NULL) { + _device->write_buttons(out, indent_level + 2); } } @@ -115,14 +124,7 @@ void ButtonNode:: do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, DataNodeTransmit &output) { if (is_valid()) { - _button->poll(); - _button->acquire(); - - (*_button_events) = (*_button->get_button_events()); - - _button->get_button_events()->clear(); - _button->unlock(); - - output.set_data(_button_events_output, EventParameter(_button_events)); + PT(ButtonEventList) bel = _device->get_button_events(); + output.set_data(_button_events_output, EventParameter(bel)); } } diff --git a/panda/src/device/buttonNode.h b/panda/src/device/buttonNode.h index 43f04b954e..349e76e708 100644 --- a/panda/src/device/buttonNode.h +++ b/panda/src/device/buttonNode.h @@ -20,8 +20,6 @@ #include "clientBase.h" #include "clientButtonDevice.h" #include "dataNode.h" -#include "buttonEventList.h" - //////////////////////////////////////////////////////////////////// // Class : ButtonNode @@ -41,6 +39,7 @@ class EXPCL_PANDA_DEVICE ButtonNode : public DataNode { PUBLISHED: ButtonNode(ClientBase *client, const string &device_name); + ButtonNode(InputDevice *device); virtual ~ButtonNode(); INLINE bool is_valid() const; @@ -58,7 +57,7 @@ public: virtual void write(ostream &out, int indent_level = 0) const; private: - PT(ClientButtonDevice) _button; + PT(InputDevice) _device; protected: // Inherited from DataNode @@ -69,7 +68,6 @@ protected: private: // outputs int _button_events_output; - PT(ButtonEventList) _button_events; public: static TypeHandle get_class_type() { diff --git a/panda/src/device/clientAnalogDevice.I b/panda/src/device/clientAnalogDevice.I index c36619d4f1..3877364de9 100644 --- a/panda/src/device/clientAnalogDevice.I +++ b/panda/src/device/clientAnalogDevice.I @@ -13,18 +13,6 @@ //////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::AnalogState::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ClientAnalogDevice::AnalogState:: -AnalogState() : - _state(0.0), - _known(false) -{ -} - //////////////////////////////////////////////////////////////////// // Function: ClientAnalogDevice::Constructor // Access: Protected @@ -35,65 +23,3 @@ ClientAnalogDevice(ClientBase *client, const string &device_name): ClientDevice(client, get_class_type(), device_name) { } - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::get_num_controls -// Access: Public -// Description: Returns the number of analog controls known to the -// ClientAnalogDevice. This number may change as -// more controls are discovered. -//////////////////////////////////////////////////////////////////// -INLINE int ClientAnalogDevice:: -get_num_controls() const { - return _controls.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::set_control_state -// Access: Public -// Description: Sets the state of the indicated analog index. The -// caller should ensure that acquire() is in effect while -// this call is made. This should be a number in the -// range -1.0 to 1.0, representing the current position -// of the control within its total range of movement. -//////////////////////////////////////////////////////////////////// -INLINE void ClientAnalogDevice:: -set_control_state(int index, double state) { - ensure_control_index(index); - nassertv(index >= 0 && index < (int)_controls.size()); - _controls[index]._state = state; - _controls[index]._known = true; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::get_control_state -// Access: Public -// Description: Returns the current position of indicated analog -// control (identified by its index number), or 0.0 if -// the control is unknown. The normal range of a single -// control is -1.0 to 1.0. -//////////////////////////////////////////////////////////////////// -INLINE double ClientAnalogDevice:: -get_control_state(int index) const { - if (index >= 0 && index < (int)_controls.size()) { - return _controls[index]._state; - } else { - return 0.0; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::is_control_known -// Access: Public -// Description: Returns true if the state of the indicated analog -// control is known, or false if we have never heard -// anything about this particular control. -//////////////////////////////////////////////////////////////////// -INLINE bool ClientAnalogDevice:: -is_control_known(int index) const { - if (index >= 0 && index < (int)_controls.size()) { - return _controls[index]._known; - } else { - return false; - } -} diff --git a/panda/src/device/clientAnalogDevice.cxx b/panda/src/device/clientAnalogDevice.cxx index 1dbe277c82..6d4a84de23 100644 --- a/panda/src/device/clientAnalogDevice.cxx +++ b/panda/src/device/clientAnalogDevice.cxx @@ -19,25 +19,6 @@ TypeHandle ClientAnalogDevice::_type_handle; - - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::ensure_control_index -// Access: Private -// Description: Guarantees that there is a slot in the array for the -// indicated index number, by filling the array up to -// that index if necessary. -//////////////////////////////////////////////////////////////////// -void ClientAnalogDevice:: -ensure_control_index(int index) { - nassertv(index >= 0); - - _controls.reserve(index + 1); - while ((int)_controls.size() <= index) { - _controls.push_back(AnalogState()); - } -} - //////////////////////////////////////////////////////////////////// // Function: ClientAnalogDevice::write // Access: Public, Virtual @@ -45,32 +26,6 @@ ensure_control_index(int index) { //////////////////////////////////////////////////////////////////// void ClientAnalogDevice:: write(ostream &out, int indent_level) const { - indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n"; + indent(out, indent_level) << get_type() << " " << get_name() << ":\n"; write_controls(out, indent_level + 2); } - -//////////////////////////////////////////////////////////////////// -// Function: ClientAnalogDevice::write_analogs -// Access: Public -// Description: Writes a multi-line description of the current analog -// control states. -//////////////////////////////////////////////////////////////////// -void ClientAnalogDevice:: -write_controls(ostream &out, int indent_level) const { - bool any_controls = false; - Controls::const_iterator ai; - for (ai = _controls.begin(); ai != _controls.end(); ++ai) { - const AnalogState &state = (*ai); - if (state._known) { - any_controls = true; - - indent(out, indent_level) - << (int)(ai - _controls.begin()) << ". " << state._state << "\n"; - } - } - - if (!any_controls) { - indent(out, indent_level) - << "(no known analog controls)\n"; - } -} diff --git a/panda/src/device/clientAnalogDevice.h b/panda/src/device/clientAnalogDevice.h index 4db8fa53c4..c79daa8b16 100644 --- a/panda/src/device/clientAnalogDevice.h +++ b/panda/src/device/clientAnalogDevice.h @@ -36,30 +36,7 @@ protected: INLINE ClientAnalogDevice(ClientBase *client, const string &device_name); public: - INLINE int get_num_controls() const; - - INLINE void set_control_state(int index, double state); - INLINE double get_control_state(int index) const; - INLINE bool is_control_known(int index) const; - virtual void write(ostream &out, int indent_level = 0) const; - void write_controls(ostream &out, int indent_level) const; - -private: - void ensure_control_index(int index); - -protected: - class AnalogState { - public: - INLINE AnalogState(); - - double _state; - bool _known; - }; - - typedef pvector Controls; - Controls _controls; - public: static TypeHandle get_class_type() { diff --git a/panda/src/device/clientBase.cxx b/panda/src/device/clientBase.cxx index e01c35766b..12c570c28c 100644 --- a/panda/src/device/clientBase.cxx +++ b/panda/src/device/clientBase.cxx @@ -144,7 +144,6 @@ get_device(TypeHandle device_type, const string &device_name) { if (device != (ClientDevice *)NULL) { dbn.insert(DevicesByName::value_type(device_name, device)); - device->_is_connected = true; } return device; diff --git a/panda/src/device/clientButtonDevice.I b/panda/src/device/clientButtonDevice.I index 21308006c9..e039e28421 100644 --- a/panda/src/device/clientButtonDevice.I +++ b/panda/src/device/clientButtonDevice.I @@ -12,113 +12,3 @@ // //////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::ButtonState::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ClientButtonDevice::ButtonState:: -ButtonState() : - _handle(ButtonHandle::none()), - _state(S_unknown) -{ -} - - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::get_num_buttons -// Access: Public -// Description: Returns the number of buttons known to the -// ClientButtonDevice. This includes those buttons -// whose state has been seen, as well as buttons that -// have been associated with a ButtonHandle even if -// their state is unknown. This number may change as -// more buttons are discovered. -//////////////////////////////////////////////////////////////////// -INLINE int ClientButtonDevice:: -get_num_buttons() const { - return _buttons.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::set_button_map -// Access: Public -// Description: Associates the indicated ButtonHandle with the button -// of the indicated index number. When the given button -// index changes state, a corresponding ButtonEvent will -// be generated with the given ButtonHandle. Pass -// ButtonHandle::none() to turn off any association. -// -// It is not necessary to call this if you simply want -// to query the state of the various buttons by index -// number; this is only necessary in order to generate -// ButtonEvents when the buttons change state. -//////////////////////////////////////////////////////////////////// -INLINE void ClientButtonDevice:: -set_button_map(int index, ButtonHandle button) { - ensure_button_index(index); - nassertv(index >= 0 && index < (int)_buttons.size()); - _buttons[index]._handle = button; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::get_button_map -// Access: Public -// Description: Returns the ButtonHandle that was previously -// associated with the given index number by -// a call to set_button_map(), or ButtonHandle::none() -// if no button was associated. -//////////////////////////////////////////////////////////////////// -INLINE ButtonHandle ClientButtonDevice:: -get_button_map(int index) const { - if (index >= 0 && index < (int)_buttons.size()) { - return _buttons[index]._handle; - } else { - return ButtonHandle::none(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::get_button_state -// Access: Public -// Description: Returns true if the indicated button (identified by -// its index number) is currently known to be down, or -// false if it is up or unknown. -//////////////////////////////////////////////////////////////////// -INLINE bool ClientButtonDevice:: -get_button_state(int index) const { - if (index >= 0 && index < (int)_buttons.size()) { - return (_buttons[index]._state == S_down); - } else { - return false; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::is_button_known -// Access: Public -// Description: Returns true if the state of the indicated button is -// known, or false if we have never heard anything about -// this particular button. -//////////////////////////////////////////////////////////////////// -INLINE bool ClientButtonDevice:: -is_button_known(int index) const { - if (index >= 0 && index < (int)_buttons.size()) { - return _buttons[index]._state != S_unknown; - } else { - return false; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::get_button_events -// Access: Public -// Description: Returns the list of recently-generated ButtonEvents. -// This must be periodically cleared, or the buttons -// will accumulate. -//////////////////////////////////////////////////////////////////// -INLINE ButtonEventList *ClientButtonDevice:: -get_button_events() const { - return _button_events; -} diff --git a/panda/src/device/clientButtonDevice.cxx b/panda/src/device/clientButtonDevice.cxx index e45561ac5a..02980c55b1 100644 --- a/panda/src/device/clientButtonDevice.cxx +++ b/panda/src/device/clientButtonDevice.cxx @@ -28,47 +28,6 @@ ClientButtonDevice:: ClientButtonDevice(ClientBase *client, const string &device_name): ClientDevice(client, get_class_type(), device_name) { - _button_events = new ButtonEventList(); -} - - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::set_button_state -// Access: Public -// Description: Sets the state of the indicated button index, where -// true indicates down, and false indicates up. This -// may generate a ButtonEvent if the button has an -// associated ButtonHandle. The caller should ensure -// that acquire() is in effect while this call is made. -//////////////////////////////////////////////////////////////////// -void ClientButtonDevice:: -set_button_state(int index, bool down) { - ensure_button_index(index); - nassertv(index >= 0 && index < (int)_buttons.size()); - _buttons[index]._state = down ? S_down : S_up; - - ButtonHandle handle = _buttons[index]._handle; - if (handle != ButtonHandle::none()) { - _button_events->add_event(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up)); - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::ensure_button_index -// Access: Private -// Description: Guarantees that there is a slot in the array for the -// indicated index number, by filling the array up to -// that index if necessary. -//////////////////////////////////////////////////////////////////// -void ClientButtonDevice:: -ensure_button_index(int index) { - nassertv(index >= 0); - - _buttons.reserve(index + 1); - while ((int)_buttons.size() <= index) { - _buttons.push_back(ButtonState()); - } } //////////////////////////////////////////////////////////////////// @@ -78,7 +37,7 @@ ensure_button_index(int index) { //////////////////////////////////////////////////////////////////// void ClientButtonDevice:: output(ostream &out) const { - out << get_type() << " " << get_device_name() << " ("; + out << get_type() << " " << get_name() << " ("; output_buttons(out); out << ")"; } @@ -90,74 +49,6 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// void ClientButtonDevice:: write(ostream &out, int indent_level) const { - indent(out, indent_level) << get_type() << " " << get_device_name() << ":\n"; + indent(out, indent_level) << get_type() << " " << get_name() << ":\n"; write_buttons(out, indent_level + 2); } - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::output_buttons -// Access: Public -// Description: Writes a one-line string of all of the current button -// states. -//////////////////////////////////////////////////////////////////// -void ClientButtonDevice:: -output_buttons(ostream &out) const { - bool any_buttons = false; - Buttons::const_iterator bi; - for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { - const ButtonState &state = (*bi); - if (state._state != S_unknown) { - if (any_buttons) { - out << ", "; - } - any_buttons = true; - out << (int)(bi - _buttons.begin()) << "="; - if (state._state == S_up) { - out << "up"; - } else { - out << "down"; - } - } - } - - if (!any_buttons) { - out << "no known buttons"; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientButtonDevice::write_buttons -// Access: Public -// Description: Writes a multi-line description of the current button -// states. -//////////////////////////////////////////////////////////////////// -void ClientButtonDevice:: -write_buttons(ostream &out, int indent_level) const { - bool any_buttons = false; - Buttons::const_iterator bi; - for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { - const ButtonState &state = (*bi); - if (state._state != S_unknown) { - any_buttons = true; - - indent(out, indent_level) - << (int)(bi - _buttons.begin()) << ". "; - - if (state._handle != ButtonHandle::none()) { - out << "(" << state._handle << ") "; - } - - if (state._state == S_up) { - out << "up"; - } else { - out << "down"; - } - out << "\n"; - } - } - - if (!any_buttons) { - indent(out, indent_level) - << "(no known buttons)\n"; - } -} diff --git a/panda/src/device/clientButtonDevice.h b/panda/src/device/clientButtonDevice.h index b9643d26c2..3deee23cbe 100644 --- a/panda/src/device/clientButtonDevice.h +++ b/panda/src/device/clientButtonDevice.h @@ -39,46 +39,9 @@ protected: ClientButtonDevice(ClientBase *client, const string &device_name); public: - INLINE int get_num_buttons() const; - - INLINE void set_button_map(int index, ButtonHandle button); - INLINE ButtonHandle get_button_map(int index) const; - - void set_button_state(int index, bool down); - INLINE bool get_button_state(int index) const; - INLINE bool is_button_known(int index) const; - - INLINE ButtonEventList *get_button_events() const; - virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; - void output_buttons(ostream &out) const; - void write_buttons(ostream &out, int indent_level) const; - -private: - void ensure_button_index(int index); - -protected: - enum State { - S_unknown, - S_up, - S_down - }; - - class ButtonState { - public: - INLINE ButtonState(); - - ButtonHandle _handle; - State _state; - }; - - typedef pvector Buttons; - Buttons _buttons; - - PT(ButtonEventList) _button_events; - public: static TypeHandle get_class_type() { return _type_handle; @@ -95,7 +58,6 @@ public: private: static TypeHandle _type_handle; - friend class ButtonState; }; #include "clientButtonDevice.I" diff --git a/panda/src/device/clientDevice.I b/panda/src/device/clientDevice.I index efcb92e050..d867978684 100644 --- a/panda/src/device/clientDevice.I +++ b/panda/src/device/clientDevice.I @@ -24,17 +24,6 @@ get_client() const { return _client; } -//////////////////////////////////////////////////////////////////// -// Function: ClientDevice::is_connected -// Access: Public -// Description: Returns true if the device is still connected to its -// ClientBase, false otherwise. -//////////////////////////////////////////////////////////////////// -INLINE bool ClientDevice:: -is_connected() const { - return _is_connected; -} - //////////////////////////////////////////////////////////////////// // Function: ClientDevice::get_device_type // Access: Public @@ -50,45 +39,3 @@ INLINE TypeHandle ClientDevice:: get_device_type() const { return _device_type; } - -//////////////////////////////////////////////////////////////////// -// Function: ClientDevice::get_device_name -// Access: Public -// Description: Returns the device name reported to the ClientBase. -// This has some implementation-defined meaning to -// identify particular devices. -//////////////////////////////////////////////////////////////////// -INLINE const string &ClientDevice:: -get_device_name() const { - return _device_name; -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientDevice::acquire -// Access: Public -// Description: Grabs the mutex associated with this particular -// device. The device will not update asynchronously -// while the mutex is held, allowing the user to copy -// the data out without fear of getting a partial update -// during the copy. -//////////////////////////////////////////////////////////////////// -INLINE void ClientDevice:: -acquire() { -#ifdef OLD_HAVE_IPC - _lock.acquire(); -#endif -} - -//////////////////////////////////////////////////////////////////// -// Function: ClientDevice::unlock -// Access: Public -// Description: Releases the mutex associated with this particular -// device. This should be called after all the data has -// been successfully copied out. See acquire(). -//////////////////////////////////////////////////////////////////// -INLINE void ClientDevice:: -unlock() { -#ifdef OLD_HAVE_IPC - _lock.unlock(); -#endif -} diff --git a/panda/src/device/clientDevice.cxx b/panda/src/device/clientDevice.cxx index d7f7aa90f4..c0ee85d266 100644 --- a/panda/src/device/clientDevice.cxx +++ b/panda/src/device/clientDevice.cxx @@ -27,15 +27,14 @@ TypeHandle ClientDevice::_type_handle; //////////////////////////////////////////////////////////////////// ClientDevice:: ClientDevice(ClientBase *client, TypeHandle device_type, - const string &device_name) : + const string &device_name, int device_flags) : + InputDevice(device_name, DC_unknown, device_flags), _client(client), - _device_type(device_type), - _device_name(device_name) + _device_type(device_type) { // We have to explicitly ref the client pointer, since we can't use // a PT(ClientBase) for circular include reasons. _client->ref(); - _is_connected = false; } //////////////////////////////////////////////////////////////////// @@ -49,7 +48,7 @@ ClientDevice(ClientBase *client, TypeHandle device_type, //////////////////////////////////////////////////////////////////// ClientDevice:: ~ClientDevice() { - nassertv(!_is_connected); + nassertv(!is_connected()); // And now we explicitly unref the client pointer. unref_delete(_client); @@ -72,19 +71,17 @@ ClientDevice:: //////////////////////////////////////////////////////////////////// void ClientDevice:: disconnect() { - if (_is_connected) { - acquire(); + if (is_connected()) { bool disconnected = - _client->disconnect_device(_device_type, _device_name, this); - _is_connected = false; - unlock(); + _client->disconnect_device(_device_type, get_name(), this); + set_connected(false); nassertv(disconnected); } } //////////////////////////////////////////////////////////////////// -// Function: ClientDevice::poll -// Access: Public +// Function: ClientDevice::do_poll +// Access: Public, Virtual, Final // Description: Causes the connected ClientBase to poll all of its // clients, if necessary. This will be a no-op if the // client is running in forked mode, or if it has @@ -94,7 +91,7 @@ disconnect() { // data in this ClientDevice to ensure that it is fresh. //////////////////////////////////////////////////////////////////// void ClientDevice:: -poll() { +do_poll() { _client->poll(); } @@ -105,7 +102,7 @@ poll() { //////////////////////////////////////////////////////////////////// void ClientDevice:: output(ostream &out) const { - out << get_type() << " " << get_device_name(); + out << get_type() << " " << get_name(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/device/clientDevice.h b/panda/src/device/clientDevice.h index b0dbb116e3..3e040bc742 100644 --- a/panda/src/device/clientDevice.h +++ b/panda/src/device/clientDevice.h @@ -16,12 +16,7 @@ #define CLIENTDEVICE_H #include "pandabase.h" - -#include "typedReferenceCount.h" - -#ifdef OLD_HAVE_IPC -#include -#endif +#include "inputDevice.h" class ClientBase; @@ -32,24 +27,20 @@ class ClientBase; // This is an abstract interface; the actual // implementations are in ClientTrackerDevice, etc. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_DEVICE ClientDevice : public TypedReferenceCount { +class EXPCL_PANDA_DEVICE ClientDevice : public InputDevice { protected: ClientDevice(ClientBase *client, TypeHandle device_type, - const string &device_name); + const string &device_name, int device_flags=0); public: virtual ~ClientDevice(); INLINE ClientBase *get_client() const; INLINE TypeHandle get_device_type() const; - INLINE const string &get_device_name() const; - INLINE bool is_connected() const; void disconnect(); - void poll(); - INLINE void acquire(); - INLINE void unlock(); + virtual void do_poll() FINAL; virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; @@ -57,21 +48,15 @@ public: private: ClientBase *_client; TypeHandle _device_type; - string _device_name; - bool _is_connected; - -#ifdef OLD_HAVE_IPC - mutex _lock; -#endif public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - TypedReferenceCount::init_type(); + InputDevice::init_type(); register_type(_type_handle, "ClientDevice", - TypedReferenceCount::get_class_type()); + InputDevice::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/device/clientTrackerDevice.I b/panda/src/device/clientTrackerDevice.I index 938ac26922..1b9047c10f 100644 --- a/panda/src/device/clientTrackerDevice.I +++ b/panda/src/device/clientTrackerDevice.I @@ -20,18 +20,6 @@ //////////////////////////////////////////////////////////////////// INLINE ClientTrackerDevice:: ClientTrackerDevice(ClientBase *client, const string &device_name): - ClientDevice(client, get_class_type(), device_name) + ClientDevice(client, get_class_type(), device_name, IDF_has_tracker) { } - -//////////////////////////////////////////////////////////////////// -// Function: ClientTrackerDevice::get_data -// Access: Public -// Description: Returns the TrackerData that this device is -// reporting. -//////////////////////////////////////////////////////////////////// -INLINE const TrackerData &ClientTrackerDevice:: -get_data() const { - return _data; -} - diff --git a/panda/src/device/clientTrackerDevice.h b/panda/src/device/clientTrackerDevice.h index 8fbfd00c55..04123ca0f4 100644 --- a/panda/src/device/clientTrackerDevice.h +++ b/panda/src/device/clientTrackerDevice.h @@ -30,12 +30,6 @@ class EXPCL_PANDA_DEVICE ClientTrackerDevice : public ClientDevice { protected: INLINE ClientTrackerDevice(ClientBase *client, const string &device_name); -public: - INLINE const TrackerData &get_data() const; - -protected: - TrackerData _data; - public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/device/config_device.cxx b/panda/src/device/config_device.cxx index a86986ed05..84e290be91 100644 --- a/panda/src/device/config_device.cxx +++ b/panda/src/device/config_device.cxx @@ -23,7 +23,9 @@ #include "clientDialDevice.h" #include "clientTrackerDevice.h" #include "dialNode.h" -#include "mouseAndKeyboard.h" +#include "evdevInputDevice.h" +#include "inputDevice.h" +#include "linuxJoystickDevice.h" #include "trackerNode.h" #include "virtualMouse.h" @@ -64,7 +66,12 @@ init_libdevice() { ClientDialDevice::init_type(); ClientTrackerDevice::init_type(); DialNode::init_type(); - MouseAndKeyboard::init_type(); + InputDevice::init_type(); TrackerNode::init_type(); VirtualMouse::init_type(); + +#ifdef PHAVE_LINUX_INPUT_H + EvdevInputDevice::init_type(); + LinuxJoystickDevice::init_type(); +#endif } diff --git a/panda/src/device/dialNode.I b/panda/src/device/dialNode.I index bd04635e46..ab101901b7 100644 --- a/panda/src/device/dialNode.I +++ b/panda/src/device/dialNode.I @@ -33,10 +33,7 @@ is_valid() const { //////////////////////////////////////////////////////////////////// INLINE int DialNode:: get_num_dials() const { - _dial->acquire(); - int result = _dial->get_num_dials(); - _dial->unlock(); - return result; + return _dial->get_num_dials(); } //////////////////////////////////////////////////////////////////// @@ -49,10 +46,7 @@ get_num_dials() const { //////////////////////////////////////////////////////////////////// INLINE double DialNode:: read_dial(int index) { - _dial->acquire(); - double result = _dial->read_dial(index); - _dial->unlock(); - return result; + return _dial->read_dial(index); } //////////////////////////////////////////////////////////////////// @@ -64,8 +58,5 @@ read_dial(int index) { //////////////////////////////////////////////////////////////////// INLINE bool DialNode:: is_dial_known(int index) const { - _dial->acquire(); - bool result = _dial->is_dial_known(index); - _dial->unlock(); - return result; + return _dial->is_dial_known(index); } diff --git a/panda/src/device/evdevInputDevice.I b/panda/src/device/evdevInputDevice.I new file mode 100644 index 0000000000..9e702ad1d8 --- /dev/null +++ b/panda/src/device/evdevInputDevice.I @@ -0,0 +1,14 @@ +// Filename: evdevInputDevice.I +// Created by: rdb (24Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx new file mode 100644 index 0000000000..e03934d658 --- /dev/null +++ b/panda/src/device/evdevInputDevice.cxx @@ -0,0 +1,424 @@ +// Filename: evdevInputDevice.cxx +// Created by: rdb (24Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "evdevInputDevice.h" + +#ifdef PHAVE_LINUX_INPUT_H + +#include "gamepadButton.h" +#include "keyboardButton.h" +#include "mouseButton.h" + +#include +#include + +#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7))) + +TypeHandle EvdevInputDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::Constructor +// Access: Published +// Description: Creates a new device using the Linux joystick +// device using the given file descriptor. It will +// be closed when this object destructs. +//////////////////////////////////////////////////////////////////// +EvdevInputDevice:: +EvdevInputDevice(int fd) : + _fd(fd) { + init_device(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::Constructor +// Access: Published +// Description: Creates a new device using the Linux joystick +// device using the given device filename. +//////////////////////////////////////////////////////////////////// +EvdevInputDevice:: +EvdevInputDevice(const string &fn) { + _fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK); + + if (_fd >= 0) { + init_device(); + } else { + _is_connected = false; + device_cat.error() + << "Opening raw input device: " << strerror(errno) << " " << fn << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +EvdevInputDevice:: +~EvdevInputDevice() { + if (_fd != -1) { + close(_fd); + _fd = -1; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::do_poll +// Access: Private, Virtual +// Description: Polls the input device for new activity, to ensure +// it contains the latest events. This will only have +// any effect for some types of input devices; others +// may be updated automatically, and this method will +// be a no-op. +//////////////////////////////////////////////////////////////////// +void EvdevInputDevice:: +do_poll() { + if (_fd != -1) { + while (process_events()) {} + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::init_device +// Access: Private +// Description: Reads basic properties from the device. +//////////////////////////////////////////////////////////////////// +bool EvdevInputDevice:: +init_device() { + uint8_t evtypes[EV_MAX/8 + 1]; + char name[256]; + char uniq[256]; + if (ioctl(_fd, EVIOCGNAME(sizeof(name)), name) < 0 || + ioctl(_fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0 || + ioctl(_fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0) { + close(_fd); + _fd = -1; + _is_connected = false; + device_cat.error() << "Opening raw input device: ioctl failed\n"; + return false; + } + + for (char *p=name; *p; p++) { + if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { + *p = '_'; + } + } + for (char *p=uniq; *p; p++) { + if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { + *p = '_'; + } + } + + _name = ((string)name) + "." + uniq; + + if (test_bit(EV_REL, evtypes)) { + _flags |= IDF_has_pointer; + } + + if (test_bit(EV_FF, evtypes)) { + _flags |= IDF_has_vibration; + } + + _is_connected = true; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::process_events +// Access: Private +// Description: Reads a number of events from the device. +//////////////////////////////////////////////////////////////////// +bool EvdevInputDevice:: +process_events() { + // Read 8 events at a time. + struct input_event events[8]; + + int n_read = read(_fd, events, sizeof(events)); + if (n_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // No data available for now. + + } else if (errno == ENODEV || errno == EINVAL) { + // The device ceased to exist, so we better close it. + close(_fd); + _fd = -1; + _is_connected = false; + errno = 0; + + } else { + device_cat.error() << "read: " << strerror(errno) << "\n"; + } + return false; + } + + if (n_read == 0) { + return false; + } + + n_read /= sizeof(struct input_event); + + int x = _pointer_data.get_x(); + int y = _pointer_data.get_y(); + double time = ClockObject::get_global_clock()->get_frame_time(); + ButtonHandle button; + + for (int i = 0; i < n_read; ++i) { + switch (events[i].type) { + case EV_SYN: + break; + + case EV_REL: + if (events[i].code == REL_X) x += events[i].value; + if (events[i].code == REL_Y) y += events[i].value; + break; + + case EV_ABS: + if (events[i].code == ABS_X) x = events[i].value; + if (events[i].code == ABS_Y) y = events[i].value; + break; + + case EV_KEY: + button = map_button(events[i].code); + _button_events->add_event(ButtonEvent(button, events[i].value ? ButtonEvent::T_down : ButtonEvent::T_up, time)); + break; + + default: + //cerr << "event " << events[i].type << " - " << events[i].code << " - " << events[i].value << "\n"; + break; + } + } + + set_pointer(true, x, y, time); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: EvdevInputDevice::map_button +// Access: Public, Static +// Description: Maps an evdev code to a ButtonHandle. +//////////////////////////////////////////////////////////////////// +ButtonHandle EvdevInputDevice:: +map_button(int code) { + if (code >= 0 && code < 0x80) { + // See linux/input.h for the source of this mapping. + static const ButtonHandle keyboard_map[] = { + ButtonHandle::none(), + KeyboardButton::escape(), + KeyboardButton::ascii_key('1'), + KeyboardButton::ascii_key('2'), + KeyboardButton::ascii_key('3'), + KeyboardButton::ascii_key('4'), + KeyboardButton::ascii_key('5'), + KeyboardButton::ascii_key('6'), + KeyboardButton::ascii_key('7'), + KeyboardButton::ascii_key('8'), + KeyboardButton::ascii_key('9'), + KeyboardButton::ascii_key('0'), + KeyboardButton::ascii_key('-'), + KeyboardButton::ascii_key('='), + KeyboardButton::backspace(), + KeyboardButton::tab(), + KeyboardButton::ascii_key('q'), + KeyboardButton::ascii_key('w'), + KeyboardButton::ascii_key('e'), + KeyboardButton::ascii_key('r'), + KeyboardButton::ascii_key('t'), + KeyboardButton::ascii_key('y'), + KeyboardButton::ascii_key('u'), + KeyboardButton::ascii_key('i'), + KeyboardButton::ascii_key('o'), + KeyboardButton::ascii_key('p'), + KeyboardButton::ascii_key('['), + KeyboardButton::ascii_key(']'), + KeyboardButton::enter(), + KeyboardButton::lcontrol(), + KeyboardButton::ascii_key('a'), + KeyboardButton::ascii_key('s'), + KeyboardButton::ascii_key('d'), + KeyboardButton::ascii_key('f'), + KeyboardButton::ascii_key('g'), + KeyboardButton::ascii_key('h'), + KeyboardButton::ascii_key('j'), + KeyboardButton::ascii_key('k'), + KeyboardButton::ascii_key('l'), + KeyboardButton::ascii_key(';'), + KeyboardButton::ascii_key('\''), + KeyboardButton::ascii_key('`'), + KeyboardButton::lshift(), + KeyboardButton::ascii_key('\\'), + KeyboardButton::ascii_key('z'), + KeyboardButton::ascii_key('x'), + KeyboardButton::ascii_key('c'), + KeyboardButton::ascii_key('v'), + KeyboardButton::ascii_key('b'), + KeyboardButton::ascii_key('n'), + KeyboardButton::ascii_key('m'), + KeyboardButton::ascii_key(','), + KeyboardButton::ascii_key('.'), + KeyboardButton::ascii_key('/'), + KeyboardButton::rshift(), + KeyboardButton::ascii_key('*'), + KeyboardButton::lalt(), + KeyboardButton::space(), + KeyboardButton::caps_lock(), + KeyboardButton::f1(), + KeyboardButton::f2(), + KeyboardButton::f3(), + KeyboardButton::f4(), + KeyboardButton::f5(), + KeyboardButton::f6(), + KeyboardButton::f7(), + KeyboardButton::f8(), + KeyboardButton::f9(), + KeyboardButton::f10(), + KeyboardButton::num_lock(), + KeyboardButton::scroll_lock(), + KeyboardButton::ascii_key('7'), + KeyboardButton::ascii_key('8'), + KeyboardButton::ascii_key('9'), + KeyboardButton::ascii_key('-'), + KeyboardButton::ascii_key('4'), + KeyboardButton::ascii_key('5'), + KeyboardButton::ascii_key('6'), + KeyboardButton::ascii_key('+'), + KeyboardButton::ascii_key('1'), + KeyboardButton::ascii_key('2'), + KeyboardButton::ascii_key('3'), + KeyboardButton::ascii_key('0'), + KeyboardButton::ascii_key('.'), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + KeyboardButton::f11(), + KeyboardButton::f12(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + KeyboardButton::enter(), + KeyboardButton::rcontrol(), + KeyboardButton::ascii_key('/'), + KeyboardButton::print_screen(), + KeyboardButton::ralt(), + ButtonHandle::none(), + KeyboardButton::home(), + KeyboardButton::up(), + KeyboardButton::page_up(), + KeyboardButton::left(), + KeyboardButton::right(), + KeyboardButton::end(), + KeyboardButton::down(), + KeyboardButton::page_down(), + KeyboardButton::insert(), + KeyboardButton::del(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + KeyboardButton::pause(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + ButtonHandle::none(), + KeyboardButton::lmeta(), + KeyboardButton::rmeta(), + KeyboardButton::menu(), + }; + return keyboard_map[code]; + + } else if (code < 0x100) { + return ButtonHandle::none(); + + } else if ((code & 0xfff0) == BTN_MOUSE) { + // The number for these is reversed in Panda. + if (code == BTN_RIGHT) { + return MouseButton::three(); + } else if (code == BTN_MIDDLE) { + return MouseButton::two(); + } else { + return MouseButton::button(code - BTN_MOUSE); + } + } + + switch (code) { + case BTN_A: + return GamepadButton::action_a(); + + case BTN_B: + return GamepadButton::action_b(); + + case BTN_C: + return GamepadButton::action_c(); + + case BTN_X: + return GamepadButton::action_x(); + + case BTN_Y: + return GamepadButton::action_y(); + + case BTN_Z: + return GamepadButton::action_z(); + + case BTN_TL: + return GamepadButton::lshoulder(); + + case BTN_TR: + return GamepadButton::rshoulder(); + + case BTN_TL2: + return GamepadButton::ltrigger(); + + case BTN_TR2: + return GamepadButton::rtrigger(); + + case BTN_SELECT: + return GamepadButton::back(); + + case BTN_START: + return GamepadButton::start(); + + case BTN_MODE: + return GamepadButton::guide(); + + case BTN_THUMBL: + return GamepadButton::lstick(); + + case BTN_THUMBR: + return GamepadButton::rstick(); + + case BTN_TRIGGER_HAPPY1: + return GamepadButton::dpad_left(); + + case BTN_TRIGGER_HAPPY2: + return GamepadButton::dpad_right(); + + case BTN_TRIGGER_HAPPY3: + return GamepadButton::dpad_up(); + + case BTN_TRIGGER_HAPPY4: + return GamepadButton::dpad_down(); + + default: + return ButtonHandle::none(); + } +} + +#endif diff --git a/panda/src/device/evdevInputDevice.h b/panda/src/device/evdevInputDevice.h new file mode 100644 index 0000000000..d3d4203625 --- /dev/null +++ b/panda/src/device/evdevInputDevice.h @@ -0,0 +1,63 @@ +// Filename: evdevInputDevice.h +// Created by: rdb (24Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef EVDEVINPUTDEVICE_H +#define EVDEVINPUTDEVICE_H + +#include "inputDevice.h" + +#ifdef PHAVE_LINUX_INPUT_H + +//////////////////////////////////////////////////////////////////// +// Class : EvdevInputDevice +// Description : This is a type of device that uses the Linux +// /dev/input/event# API to read data from a raw mouse. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_DEVICE EvdevInputDevice : public InputDevice { +PUBLISHED: + EvdevInputDevice(int fd); + EvdevInputDevice(const string &device); + virtual ~EvdevInputDevice(); + +private: + virtual void do_poll(); + + bool init_device(); + bool process_events(); + +private: + int _fd; + +public: + static ButtonHandle map_button(int code); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + InputDevice::init_type(); + register_type(_type_handle, "EvdevInputDevice", + InputDevice::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "evdevInputDevice.I" + +#endif // PHAVE_LINUX_INPUT_H + +#endif // EVDEVINPUTDEVICE_H diff --git a/panda/src/device/inputDevice.I b/panda/src/device/inputDevice.I new file mode 100644 index 0000000000..99962b7750 --- /dev/null +++ b/panda/src/device/inputDevice.I @@ -0,0 +1,445 @@ +// Filename: inputDevice.I +// Created by: drose (24May00) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::Default Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE InputDevice:: +InputDevice() : + _flags(0), + _device_class(DC_unknown), + _is_connected(false), + _event_sequence(0), + _enable_pointer_events(false), + _battery_level(-1), + _max_battery_level(-1) +{ + _button_events = new ButtonEventList; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_name +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE string InputDevice:: +get_name() const { + LightMutexHolder holder(_lock); + return _name; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::is_connected +// Access: Public +// Description: Returns true if the device is still connected and +// able to receive data, false otherwise. May return +// false positives. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +is_connected() const { + LightMutexHolder holder(_lock); + return _is_connected; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_device_class +// Access: Public +// Description: Returns an identification of the general type of +// device. If this could not be determined, returns +// DC_unknown. +//////////////////////////////////////////////////////////////////// +INLINE InputDevice::DeviceClass InputDevice:: +get_device_class() const { + LightMutexHolder holder(_lock); + return _device_class; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_pointer +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +has_pointer() const { + LightMutexHolder holder(_lock); + return ((_flags & IDF_has_pointer) != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_keyboard +// Access: Public +// Description: Returns true if the device has a physical keyboard +// designed for text entry. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +has_keyboard() const { + LightMutexHolder holder(_lock); + return ((_flags & IDF_has_keyboard) != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_tracker +// Access: Public +// Description: Returns true if the device features a tracker that +// can track position and/or orientation in 3D space. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +has_tracker() const { + LightMutexHolder holder(_lock); + return ((_flags & IDF_has_tracker) != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_battery +// Access: Public +// Description: Returns true if the device may be able to provide +// information about its battery life. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +has_battery() const { + LightMutexHolder holder(_lock); + return ((_flags & IDF_has_battery) != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_axis +// Access: Public +// Description: Returns true if the device has the given axis. +//////////////////////////////////////////////////////////////////// +/* +INLINE bool InputDevice:: +has_axis(Axis axis) const { + LightMutexHolder holder(_lock); + return ((_has_axes & (1 << axis)) != 0); +}*/ + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_pointer +// Access: Public +// Description: Returns the PointerData associated with the input +// device's pointer. This only makes sense if +// has_pointer() also returns true. +//////////////////////////////////////////////////////////////////// +INLINE PointerData InputDevice:: +get_pointer() const { + LightMutexHolder holder(_lock); + return _pointer_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_tracker +// Access: Public +// Description: Returns the TrackerData associated with the input +// device's tracker. This only makes sense if +// has_tracker() also returns true. +//////////////////////////////////////////////////////////////////// +INLINE TrackerData InputDevice:: +get_tracker() const { + LightMutexHolder holder(_lock); + return _tracker_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_battery_level +// Access: Public +// Description: Returns a rough indication of the battery level, +// ranging from 0 (completely empty battery) to the +// number reported by get_max_battery_level(), which +// represents a full battery. +// If this information is not known, returns -1. +//////////////////////////////////////////////////////////////////// +INLINE short InputDevice:: +get_battery_level() const { + LightMutexHolder holder(_lock); + return _battery_level; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_max_battery_level +// Access: Public +// Description: Returns the maximum value that may be reported by +// get_battery_level(), representing a full battery. +// Returns -1 if no battery information is known. +//////////////////////////////////////////////////////////////////// +INLINE short InputDevice:: +get_max_battery_level() const { + LightMutexHolder holder(_lock); + return _max_battery_level; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_num_buttons +// Access: Public +// Description: Returns the number of buttons known to the +// ClientButtonDevice. This includes those buttons +// whose state has been seen, as well as buttons that +// have been associated with a ButtonHandle even if +// their state is unknown. This number may change as +// more buttons are discovered. +//////////////////////////////////////////////////////////////////// +INLINE int InputDevice:: +get_num_buttons() const { + LightMutexHolder holder(_lock); + return _buttons.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_button_map +// Access: Public +// Description: Associates the indicated ButtonHandle with the button +// of the indicated index number. When the given button +// index changes state, a corresponding ButtonEvent will +// be generated with the given ButtonHandle. Pass +// ButtonHandle::none() to turn off any association. +// +// It is not necessary to call this if you simply want +// to query the state of the various buttons by index +// number; this is only necessary in order to generate +// ButtonEvents when the buttons change state. +//////////////////////////////////////////////////////////////////// +INLINE void InputDevice:: +set_button_map(int index, ButtonHandle button) { + LightMutexHolder holder(_lock); + nassertv(index >= 0); + if (index >= (int)_buttons.size()) { + _buttons.resize(index + 1, ButtonState()); + } + + _buttons[index]._handle = button; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_button_map +// Access: Public +// Description: Returns the ButtonHandle that was previously +// associated with the given index number by +// a call to set_button_map(), or ButtonHandle::none() +// if no button was associated. +//////////////////////////////////////////////////////////////////// +INLINE ButtonHandle InputDevice:: +get_button_map(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return _buttons[index]._handle; + } else { + return ButtonHandle::none(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_button_state +// Access: Public +// Description: Returns true if the indicated button (identified by +// its index number) is currently known to be down, or +// false if it is up or unknown. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +get_button_state(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return (_buttons[index]._state == S_down); + } else { + return false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::is_button_known +// Access: Public +// Description: Returns true if the state of the indicated button is +// known, or false if we have never heard anything about +// this particular button. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +is_button_known(int index) const { + if (index >= 0 && index < (int)_buttons.size()) { + return _buttons[index]._state != S_unknown; + } else { + return false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_num_controls +// Access: Public +// Description: Returns the number of analog controls known to the +// InputDevice. This number may change as +// more controls are discovered. +//////////////////////////////////////////////////////////////////// +INLINE int InputDevice:: +get_num_controls() const { + return _controls.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_control_map +// Access: Public +// Description: Associates the indicated ControlAxis with the +// control of the indicated index number. Pass +// C_none to turn off any association. +// +// It is not necessary to call this if you simply want +// to query the state of the various controls by index +// number. +//////////////////////////////////////////////////////////////////// +INLINE void InputDevice:: +set_control_map(int index, ControlAxis axis) { + LightMutexHolder holder(_lock); + nassertv(index >= 0); + if (index >= (int)_controls.size()) { + _controls.resize(index + 1, AnalogState()); + } + + _controls[index]._axis = axis; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_control_map +// Access: Public +// Description: Returns the ControlAxis that was previously +// associated with the given index number by +// a call to set_control_map(), or C_none +// if no control was associated. +//////////////////////////////////////////////////////////////////// +INLINE InputDevice::ControlAxis InputDevice:: +get_control_map(int index) const { + if (index >= 0 && index < (int)_controls.size()) { + return _controls[index]._axis; + } else { + return C_none; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_control_state +// Access: Public +// Description: Returns the current position of indicated analog +// control (identified by its index number), or 0.0 if +// the control is unknown. The normal range of a single +// control is -1.0 to 1.0. +//////////////////////////////////////////////////////////////////// +INLINE double InputDevice:: +get_control_state(int index) const { + if (index >= 0 && index < (int)_controls.size()) { + return _controls[index]._state; + } else { + return 0.0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::is_control_known +// Access: Public +// Description: Returns true if the state of the indicated analog +// control is known, or false if we have never heard +// anything about this particular control. +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +is_control_known(int index) const { + if (index >= 0 && index < (int)_controls.size()) { + return _controls[index]._known; + } else { + return false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::enable_pointer_events +// Access: Public +// Description: Enables the generation of mouse-movement events. +//////////////////////////////////////////////////////////////////// +INLINE void InputDevice:: +enable_pointer_events() { + LightMutexHolder holder(_lock); + _enable_pointer_events = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::disable_pointer_events +// Access: Public +// Description: Disables the generation of mouse-movement events. +//////////////////////////////////////////////////////////////////// +INLINE void InputDevice:: +disable_pointer_events() { + LightMutexHolder holder(_lock); + _enable_pointer_events = false; + _pointer_events.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_connected +// Access: Protected +// Description: Called to indicate that the device has been +// disconnected or connected from its host. +//////////////////////////////////////////////////////////////////// +INLINE void InputDevice:: +set_connected(bool connected) { + LightMutexHolder holder(_lock); + _is_connected = connected; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::operator == +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +operator == (const InputDevice &) const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::operator != +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +operator != (const InputDevice &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::operator < +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool InputDevice:: +operator < (const InputDevice &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::ButtonState::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE InputDevice::ButtonState:: +ButtonState() : + _handle(ButtonHandle::none()), + _state(S_unknown) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::AnalogState::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE InputDevice::AnalogState:: +AnalogState() : + _axis(C_none), + _state(0.0), + _known(false) +{ +} diff --git a/panda/src/device/inputDevice.cxx b/panda/src/device/inputDevice.cxx new file mode 100644 index 0000000000..25477ca913 --- /dev/null +++ b/panda/src/device/inputDevice.cxx @@ -0,0 +1,517 @@ +// Filename: inputDevice.cxx +// Created by: drose (24May00) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "inputDevice.h" + +TypeHandle InputDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::Constructor +// Access: Private +// Description: Defines a new InputDevice for the window. Most +// windows will have exactly one InputDevice: a +// keyboard/mouse pair. Some may also add joystick +// data, or additional mice or something. +// +// This private constructor is only used internally by +// the named constructors, below. +//////////////////////////////////////////////////////////////////// +InputDevice:: +InputDevice(const string &name, DeviceClass dev_class, int flags) : + _name(name), + _flags(flags), + _device_class(dev_class), + _is_connected(true), + _event_sequence(0), + _enable_pointer_events(false), + _battery_level(-1), + _max_battery_level(-1) +{ + _button_events = new ButtonEventList; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +InputDevice:: +InputDevice(const InputDevice ©) { + *this = copy; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void InputDevice:: +operator = (const InputDevice ©) { + LightMutexHolder holder(_lock); + LightMutexHolder holder1(copy._lock); + _name = copy._name; + _flags = copy._flags; + _is_connected = copy._is_connected; + _event_sequence = copy._event_sequence; + _enable_pointer_events = copy._enable_pointer_events; + _pointer_data = copy._pointer_data; + _button_events = copy._button_events; + _pointer_events = copy._pointer_events; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +InputDevice:: +~InputDevice() { +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::poll +// Access: Public, Virtual +// Description: Polls the input device for new activity, to ensure +// it contains the latest events. This will only have +// any effect for some types of input devices; others +// may be updated automatically, and this method will +// be a no-op. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +poll() { + LightMutexHolder holder(_lock); + do_poll(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_button_event +// Access: Public +// Description: Returns true if this device has a pending button +// event (a mouse button or keyboard button down/up), +// false otherwise. If this returns true, the +// particular event may be extracted via +// get_button_event(). +//////////////////////////////////////////////////////////////////// +bool InputDevice:: +has_button_event() const { + LightMutexHolder holder(_lock); + return !_button_events.is_null() && _button_events->get_num_events() > 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_button_events +// Access: Public +// Description: Returns the list of recently-generated ButtonEvents. +// The list is also cleared. +//////////////////////////////////////////////////////////////////// +PT(ButtonEventList) InputDevice:: +get_button_events() { + LightMutexHolder holder(_lock); + PT(ButtonEventList) result = new ButtonEventList; + swap(_button_events, result); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::has_pointer_event +// Access: Public +// Description: Returns true if this device has a pending pointer +// event (a mouse movement), or false otherwise. If +// this returns true, the particular event may be +// extracted via get_pointer_event(). +//////////////////////////////////////////////////////////////////// +bool InputDevice:: +has_pointer_event() const { + LightMutexHolder holder(_lock); + return (_pointer_events != 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::get_pointer_events +// Access: Public +// Description: Returns a PointerEventList containing all the recent +// pointer events. Clears the list. +//////////////////////////////////////////////////////////////////// +PT(PointerEventList) InputDevice:: +get_pointer_events() { + LightMutexHolder holder(_lock); + PT(PointerEventList) result = _pointer_events; + _pointer_events.clear(); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_pointer +// Access: Protected +// Description: Records that a mouse movement has taken place. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +set_pointer(bool inwin, double x, double y, double time) { + nassertv(_lock.debug_is_locked()); + _pointer_data._in_window = inwin; + _pointer_data._xpos = x; + _pointer_data._ypos = y; + + if (_enable_pointer_events) { + int seq = _event_sequence++; + if (_pointer_events.is_null()) { + _pointer_events = new PointerEventList(); + } + _pointer_events->add_event(_pointer_data._in_window, + _pointer_data._xpos, + _pointer_data._ypos, + seq, time); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_pointer_out_of_window +// Access: Protected +// Description: Records that the mouse pointer has left the window. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +set_pointer_out_of_window(double time) { + nassertv(_lock.debug_is_locked()); + _pointer_data._in_window = false; + + if (_enable_pointer_events) { + int seq = _event_sequence++; + if (_pointer_events.is_null()) { + _pointer_events = new PointerEventList(); + } + _pointer_events->add_event(_pointer_data._in_window, + _pointer_data._xpos, + _pointer_data._ypos, + seq, time); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_button_state +// Access: Protected +// Description: Sets the state of the indicated button index, where +// true indicates down, and false indicates up. This +// may generate a ButtonEvent if the button has an +// associated ButtonHandle. The caller should ensure +// that acquire() is in effect while this call is made. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +set_button_state(int index, bool down) { + nassertv(_lock.debug_is_locked()); + nassertv(index >= 0); + if (index >= (int)_buttons.size()) { + _buttons.resize(index + 1, ButtonState()); + } + + _buttons[index]._state = down ? S_down : S_up; + + ButtonHandle handle = _buttons[index]._handle; + if (handle != ButtonHandle::none()) { + _button_events->add_event(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_control_state +// Access: Protected +// Description: Sets the state of the indicated analog index. The +// caller should ensure that acquire() is in effect while +// this call is made. This should be a number in the +// range -1.0 to 1.0, representing the current position +// of the control within its total range of movement. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +set_control_state(int index, double state) { + nassertv(_lock.debug_is_locked()); + nassertv(index >= 0); + if (index >= (int)_controls.size()) { + _controls.resize(index + 1, AnalogState()); + } + + _controls[index]._state = state; + _controls[index]._known = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::set_tracker +// Access: Protected +// Description: Records that a tracker movement has taken place. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +set_tracker(const LPoint3 &pos, const LOrientation &orient, double time) { + nassertv(_lock.debug_is_locked()); + + _tracker_data.set_pos(pos); + _tracker_data.set_orient(orient); + _tracker_data.set_time(time); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::output +// Access: Public +// Description: Writes a one-line string describing the device. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +output(ostream &out) const { + LightMutexHolder holder(_lock); + + out << _name << " ("; + + if (!_is_connected) { + out << "dis"; + } + + out << "connected)"; + + if (_device_class != DC_unknown) { + out << ", " << _device_class; + } + + if (_buttons.size() > 0) { + out << ", " << _buttons.size() << " buttons"; + } + + if (_controls.size() > 0) { + out << ", " << _controls.size() << " controls"; + } + + if (_flags & IDF_has_pointer) { + out << ", pointer"; + } + if (_flags & IDF_has_keyboard) { + out << ", keyboard"; + } + if (_flags & IDF_has_tracker) { + out << ", tracker"; + } + if (_flags & IDF_has_vibration) { + out << ", vibration"; + } + if (_flags & IDF_has_battery) { + out << ", battery"; + + if (_battery_level > 0 && _max_battery_level > 0) { + out << " ["; + short i = 0; + for (; i < _battery_level - 1; ++i) { + out << '='; + } + out << '/'; + for (; i < _max_battery_level; ++i) { + out << ' '; + } + out << ']'; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::output_buttons +// Access: Public +// Description: Writes a one-line string of all of the current button +// states. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +output_buttons(ostream &out) const { + LightMutexHolder holder(_lock); + + bool any_buttons = false; + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + const ButtonState &state = (*bi); + if (state._state != S_unknown) { + if (any_buttons) { + out << ", "; + } + any_buttons = true; + out << (int)(bi - _buttons.begin()) << "="; + if (state._state == S_up) { + out << "up"; + } else { + out << "down"; + } + } + } + + if (!any_buttons) { + out << "no known buttons"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::write_buttons +// Access: Public +// Description: Writes a multi-line description of the current button +// states. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +write_buttons(ostream &out, int indent_level) const { + bool any_buttons = false; + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + const ButtonState &state = (*bi); + if (state._state != S_unknown) { + any_buttons = true; + + indent(out, indent_level) + << (int)(bi - _buttons.begin()) << ". "; + + if (state._handle != ButtonHandle::none()) { + out << "(" << state._handle << ") "; + } + + if (state._state == S_up) { + out << "up"; + } else { + out << "down"; + } + out << "\n"; + } + } + + if (!any_buttons) { + indent(out, indent_level) + << "(no known buttons)\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::write_controls +// Access: Public +// Description: Writes a multi-line description of the current analog +// control states. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +write_controls(ostream &out, int indent_level) const { + LightMutexHolder holder(_lock); + + bool any_controls = false; + Controls::const_iterator ai; + for (ai = _controls.begin(); ai != _controls.end(); ++ai) { + const AnalogState &state = (*ai); + if (state._known) { + any_controls = true; + + indent(out, indent_level) + << (int)(ai - _controls.begin()) << ". " << state._state << "\n"; + } + } + + if (!any_controls) { + indent(out, indent_level) + << "(no known analog controls)\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDevice::do_poll +// Access: Protected, Virtual +// Description: Polls the input device for new activity, to ensure +// it contains the latest events. This will only have +// any effect for some types of input devices; others +// may be updated automatically, and this method will +// be a no-op. +//////////////////////////////////////////////////////////////////// +void InputDevice:: +do_poll() { +} + +ostream & +operator << (ostream &out, InputDevice::DeviceClass dc) { + switch (dc) { + case InputDevice::DC_unknown: + out << "unknown"; + break; + + case InputDevice::DC_virtual: + out << "virtual"; + break; + + case InputDevice::DC_keyboard: + out << "keyboard"; + break; + + case InputDevice::DC_mouse: + out << "mouse"; + break; + + case InputDevice::DC_touch: + out << "touch"; + break; + + case InputDevice::DC_gamepad: + out << "gamepad"; + break; + + case InputDevice::DC_flight_stick: + out << "flight_stick"; + break; + + case InputDevice::DC_steering_wheel: + out << "steering_wheel"; + break; + } + return out; +} + +ostream & +operator << (ostream &out, InputDevice::ControlAxis axis) { + switch (axis) { + case InputDevice::C_none: + out << "none"; + break; + + case InputDevice::C_left_x: + out << "left_x"; + break; + + case InputDevice::C_left_y: + out << "left_y"; + break; + + case InputDevice::C_left_trigger: + out << "left_trigger"; + break; + + case InputDevice::C_right_x: + out << "right_x"; + break; + + case InputDevice::C_right_y: + out << "right_y"; + break; + + case InputDevice::C_right_trigger: + out << "right_trigger"; + break; + + case InputDevice::C_x: + out << "x"; + break; + + case InputDevice::C_y: + out << "y"; + break; + + case InputDevice::C_trigger: + out << "trigger"; + break; + + case InputDevice::C_throttle: + out << "throttle"; + break; + } + + return out; +} diff --git a/panda/src/device/inputDevice.h b/panda/src/device/inputDevice.h new file mode 100644 index 0000000000..407e6cdb77 --- /dev/null +++ b/panda/src/device/inputDevice.h @@ -0,0 +1,279 @@ +// Filename: inputDevice.h +// Created by: drose (24May00) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef INPUTDEVICE_H +#define INPUTDEVICE_H + +#include "pandabase.h" + +#include "buttonEvent.h" +#include "buttonEventList.h" +#include "pointerEvent.h" +#include "pointerEventList.h" +#include "mouseData.h" +#include "trackerData.h" +#include "clockObject.h" + +#include "pdeque.h" +#include "pvector.h" +#include "lightMutex.h" +#include "lightMutexHolder.h" + +typedef MouseData PointerData; + +//////////////////////////////////////////////////////////////////// +// Class : InputDevice +// Description : This is a structure representing a single input +// device. Input devices may have zero or more +// buttons, pointers, or controls associated with them, +// and optionally a tracker. +// +// These devices are brought under a common interface +// because there is such a large range of devices out +// there that may support any number of these types of +// controls, we couldn't even begin to cover them with +// type-specific subclasses. +// +// Use the various has_() and get_num_() methods to +// determine information about the device capabilities. +// For instance, has_keyboard() will give an indication +// that you can receive keystroke events from this +// device, and get_num_buttons() will tell you that +// the device may send button events. +// +// There is the DeviceType enumeration, however, which +// will (if known) contain identification about the +// general category of devices this fits in, such as +// keyboard, mouse, gamepad, or flight stick. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount { +PUBLISHED: + // This enum contains information that can be used to identify the + // type of input device. + enum DeviceClass { + DC_unknown, + + // This means that the device doesn't correspond to a physical + // device, but rather to a dynamic source of input events. + DC_virtual, + + // A physical, alphabetical keyboard. + DC_keyboard, + + DC_mouse, + DC_touch, + + // A gamepad with action buttons, a D-pad, and thumbsticks. + DC_gamepad, + + DC_flight_stick, + DC_steering_wheel, + }; + +protected: + InputDevice(const string &name, DeviceClass dev_class, int flags); + +public: + InputDevice(); + InputDevice(const InputDevice ©); + void operator = (const InputDevice ©); + ~InputDevice(); + +PUBLISHED: + enum ControlAxis { + C_none, + + // Gamepad + C_left_x, + C_left_y, + C_left_trigger, + C_right_x, + C_right_y, + C_right_trigger, + + // Flight stick + C_x, + C_y, + C_trigger, + C_throttle, + }; + + INLINE string get_name() const; + INLINE bool is_connected() const; + INLINE DeviceClass get_device_class() const; + + // The human-readable name of this input device. + MAKE_PROPERTY(name, get_name); + + // This is false if we know that the device is not currently connected. + // May report false positives if we can't know this with certainty. + MAKE_PROPERTY(connected, is_connected); + + // This contains an identification of the general type of device. If + // this could not be determined, it is set to DC_unknown. + MAKE_PROPERTY(device_class, get_device_class); + + INLINE bool has_pointer() const; + INLINE bool has_keyboard() const; + INLINE bool has_tracker() const; + INLINE bool has_battery() const; + + INLINE PointerData get_pointer() const; + INLINE TrackerData get_tracker() const; + + INLINE short get_battery_level() const; + INLINE short get_max_battery_level() const; + + INLINE int get_num_buttons() const; + INLINE void set_button_map(int index, ButtonHandle button); + INLINE ButtonHandle get_button_map(int index) const; + INLINE bool get_button_state(int index) const; + INLINE bool is_button_known(int index) const; + + INLINE int get_num_controls() const; + INLINE void set_control_map(int index, ControlAxis axis); + INLINE ControlAxis get_control_map(int index) const; + INLINE double get_control_state(int index) const; + INLINE bool is_control_known(int index) const; + + INLINE void enable_pointer_events(); + INLINE void disable_pointer_events(); + + void poll(); + + bool has_button_event() const; + PT(ButtonEventList) get_button_events(); + bool has_pointer_event() const; + PT(PointerEventList) get_pointer_events(); + + virtual void output(ostream &out) const; + +protected: + void set_pointer(bool inwin, double x, double y, double time); + void set_pointer_out_of_window(double time); + void set_button_state(int index, bool down); + void set_control_state(int index, double state); + void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time); + + virtual void do_poll(); + +public: + INLINE void set_connected(bool connected); + + // We need these methods to make VC++ happy when we try to + // instantiate a pvector. They don't do + // anything useful. + INLINE bool operator == (const InputDevice &other) const; + INLINE bool operator != (const InputDevice &other) const; + INLINE bool operator < (const InputDevice &other) const; + + void output_buttons(ostream &out) const; + void write_buttons(ostream &out, int indent_level) const; + void write_controls(ostream &out, int indent_level) const; + +protected: + enum InputDeviceFlags { + // The device provides absolute screen coordinates. + IDF_has_pointer = 0x01, + + // The device has an interface for providing text input. + IDF_has_keyboard = 0x02, + + // The device has a motion tracker, such as an HMD. + IDF_has_tracker = 0x04, + + // The device can produce force feedback. + IDF_has_vibration = 0x08, + + // The device provides information about battery life. + IDF_has_battery = 0x10, + }; + +protected: + typedef pdeque ButtonEvents; + + LightMutex _lock; + + string _name; + DeviceClass _device_class; + int _flags; + int _event_sequence; + bool _is_connected; + bool _enable_pointer_events; + PointerData _pointer_data; + PT(ButtonEventList) _button_events; + PT(PointerEventList) _pointer_events; + +public: + enum State { + S_unknown, + S_up, + S_down + }; + + class ButtonState { + public: + INLINE ButtonState(); + + ButtonHandle _handle; + State _state; + }; + typedef pvector Buttons; + Buttons _buttons; + + class AnalogState { + public: + INLINE AnalogState(); + + ControlAxis _axis; + double _state; + bool _known; + }; + typedef pvector Controls; + Controls _controls; + + short _battery_level; + short _max_battery_level; + + TrackerData _tracker_data; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "InputDevice", + TypedReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +INLINE ostream &operator << (ostream &out, const InputDevice &device) { + device.output(out); + return out; +} + +ostream &operator << (ostream &out, InputDevice::DeviceClass dc); +ostream &operator << (ostream &out, InputDevice::ControlAxis axis); + +#include "inputDevice.I" + +#endif diff --git a/panda/src/device/inputDeviceManager.I b/panda/src/device/inputDeviceManager.I new file mode 100644 index 0000000000..21f687f621 --- /dev/null +++ b/panda/src/device/inputDeviceManager.I @@ -0,0 +1,27 @@ +// Filename: inputDeviceManager.I +// Created by: rdb (09Dec15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::get_global_ptr +// Access: Published, Static +// Description: Returns the singleton instance. +//////////////////////////////////////////////////////////////////// +INLINE InputDeviceManager *InputDeviceManager:: +get_global_ptr() { + if (_global_ptr == (InputDeviceManager *)NULL) { + _global_ptr = new InputDeviceManager; + } + return _global_ptr; +} diff --git a/panda/src/device/inputDeviceManager.cxx b/panda/src/device/inputDeviceManager.cxx new file mode 100644 index 0000000000..d67e21208f --- /dev/null +++ b/panda/src/device/inputDeviceManager.cxx @@ -0,0 +1,240 @@ +// Filename: inputDeviceManager.cxx +// Created by: rdb (09Dec15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "inputDeviceManager.h" +#include "linuxJoystickDevice.h" +#include "throw_event.h" + +#ifdef PHAVE_LINUX_INPUT_H +#include +#include +#include +#include +#endif + +InputDeviceManager *InputDeviceManager::_global_ptr = NULL; + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::Constructor +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +InputDeviceManager:: +InputDeviceManager() : _inotify_fd(-1) { +#ifdef PHAVE_LINUX_INPUT_H + // Scan /dev/input for a list of input devices. + DIR *dir = opendir("/dev/input"); + if (dir) { + dirent *entry = readdir(dir); + while (entry != NULL) { + if (entry->d_type == DT_CHR) { + string name(entry->d_name); + if (!consider_add_linux_device(name)) { + // We can't access it. That's pretty normal for most devices. + if (device_cat.is_debug()) { + device_cat.debug() + << "Ignoring input device /dev/input/" << name << ": " + << strerror(errno) << "\n"; + } + errno = 0; + } + } + entry = readdir(dir); + } + closedir(dir); + } else { + device_cat.error() + << "Error opening directory /dev/input: " << strerror(errno) << "\n"; + return; + } + + // Use inotify to watch /dev/input for hotplugging of devices. + _inotify_fd = inotify_init1(O_NONBLOCK); + + if (_inotify_fd < 0) { + device_cat.error() + << "Error initializing inotify: " << strerror(errno) << "\n"; + + } else if (inotify_add_watch(_inotify_fd, "/dev/input", IN_CREATE | IN_ATTRIB | IN_DELETE) < 0) { + device_cat.error() + << "Error adding inotify watch on /dev/input: " << strerror(errno) << "\n"; + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::Destructor +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +InputDeviceManager:: +~InputDeviceManager() { +#ifdef PHAVE_LINUX_INPUT_H + if (_inotify_fd >= 0) { + close(_inotify_fd); + _inotify_fd = -1; + } +#endif +} + +#ifdef PHAVE_LINUX_INPUT_H +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::consider_add_linux_device +// Access: Private +// Description: Checks whether the given device is accessible, and +// if so, adds it. Returns false on error. +//////////////////////////////////////////////////////////////////// +bool InputDeviceManager:: +consider_add_linux_device(const string &name) { + // Get the full path name first. + string path = "/dev/input/"; + path += name; + + if (access(path.c_str(), R_OK) < 0) { + return false; + } + + if (_devices_by_path.count(name)) { + // We already have this device. + return true; + } + + // Check if it's a joystick or game controller device. + if (name.size() > 2 && name[0] == 'j' && name[1] == 's' && isdigit(name[2])) { + PT(InputDevice) device = new LinuxJoystickDevice(path); + if (device_cat.is_info()) { + device_cat.info() + << "Discovered input device " << *device << "\n"; + } + + _devices_by_path[name] = device; + _all_devices.push_back(MOVE(device)); + return true; + } + + return true; +} +#endif + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::add_device +// Access: Public +// Description: Called when a new device has been discovered. +//////////////////////////////////////////////////////////////////// +void InputDeviceManager:: +add_device(InputDevice *device) { + { + LightMutexHolder holder(_lock); + _all_devices.push_back(device); + } + throw_event("device-added", device); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::remove_device +// Access: Public +// Description: Called when a device has been removed. +//////////////////////////////////////////////////////////////////// +void InputDeviceManager:: +remove_device(InputDevice *device) { + { + LightMutexHolder holder(_lock); + + InputDevices::iterator it; + it = std::find(_all_devices.begin(), _all_devices.end(), device); + nassertv_always(it != _all_devices.end()); + + _all_devices.erase(it); + } + + throw_event("device-removed", device); +} + +//////////////////////////////////////////////////////////////////// +// Function: InputDeviceManager::poll +// Access: Public +// Description: Polls the system to see if there are any new devices. +//////////////////////////////////////////////////////////////////// +void InputDeviceManager:: +poll() { +#ifdef PHAVE_LINUX_INPUT_H + // We use inotify to tell us whether a device was added, removed, + // or has changed permissions to allow us to access it. + unsigned int avail; + ioctl(_inotify_fd, FIONREAD, &avail); + if (avail == 0) { + return; + } + + char buffer[avail]; + int n_read = read(_inotify_fd, buffer, avail); + if (n_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // No data available for now. + + } else { + device_cat.error() << "read: " << strerror(errno) << "\n"; + } + return; + } + + LightMutexHolder holder(_lock); + + // Iterate over the events in the buffer. + char *ptr = buffer; + char *end = buffer + avail; + while (ptr < end) { + inotify_event *event = (inotify_event *)ptr; + + string name(event->name); + + if (event->mask & IN_DELETE) { + // The device was deleted. If we have it, remove it. + DevicesByPath::iterator it = _devices_by_path.find(name); + if (it != _devices_by_path.end()) { + PT(InputDevice) device = it->second; + device->set_connected(false); + + InputDevices::iterator it2; + _devices_by_path.erase(it); + it2 = std::find(_all_devices.begin(), _all_devices.end(), device); + _all_devices.erase(it2); + + if (device_cat.is_info()) { + device_cat.info() + << "Removed input device " << *device << "\n"; + } + throw_event("device-removed", device.p()); + } + + } else if (event->mask & (IN_CREATE | IN_ATTRIB)) { + // The device was created, or it was chmodded to be accessible. + DevicesByPath::iterator it = _devices_by_path.find(name); + if (it == _devices_by_path.end()) { + // We don't know about this device yet. + if (!consider_add_linux_device(name) && (event->mask & IN_CREATE) != 0) { + if (device_cat.is_debug()) { + device_cat.debug() + << "Ignoring input device /dev/input/" << name << ": " + << strerror(errno) << "\n"; + } + } + errno = 0; + } + } + + ptr += sizeof(inotify_event) + event->len; + } +#endif +} diff --git a/panda/src/device/inputDeviceManager.h b/panda/src/device/inputDeviceManager.h new file mode 100644 index 0000000000..3c05cf96fd --- /dev/null +++ b/panda/src/device/inputDeviceManager.h @@ -0,0 +1,64 @@ +// Filename: inputDeviceManager.h +// Created by: rdb (09Dec15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef INPUTDEVICEMANAGER_H +#define INPUTDEVICEMANAGER_H + +#include "pandabase.h" +#include "lightMutex.h" +#include "inputDevice.h" + +//////////////////////////////////////////////////////////////////// +// Class : InputDeviceManager +// Description : This class keeps track of all the devices on a +// system, and sends out events when a device has been +// hot-plugged. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_DEVICE InputDeviceManager { +private: + InputDeviceManager(); + ~InputDeviceManager(); + +#ifdef PHAVE_LINUX_INPUT_H + bool consider_add_linux_device(const string &name); +#endif + +public: + void add_device(InputDevice *device); + void remove_device(InputDevice *device); + +PUBLISHED: + void poll(); + + INLINE static InputDeviceManager *get_global_ptr(); + +private: + LightMutex _lock; + +#ifdef PHAVE_LINUX_INPUT_H + int _inotify_fd; + + typedef pmap DevicesByPath; + DevicesByPath _devices_by_path; +#endif + + typedef pvector InputDevices; + InputDevices _all_devices; + + static InputDeviceManager *_global_ptr; +}; + +#include "inputDeviceManager.I" + +#endif diff --git a/panda/src/device/linuxJoystickDevice.I b/panda/src/device/linuxJoystickDevice.I new file mode 100644 index 0000000000..b1150e12a5 --- /dev/null +++ b/panda/src/device/linuxJoystickDevice.I @@ -0,0 +1,14 @@ +// Filename: linuxJoystickDevice.I +// Created by: rdb (21Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/device/linuxJoystickDevice.cxx b/panda/src/device/linuxJoystickDevice.cxx new file mode 100644 index 0000000000..b3566554e6 --- /dev/null +++ b/panda/src/device/linuxJoystickDevice.cxx @@ -0,0 +1,313 @@ +// Filename: linuxJoystickDevice.cxx +// Created by: rdb (21Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "linuxJoystickDevice.h" + +#ifdef PHAVE_LINUX_INPUT_H + +#include "gamepadButton.h" + +#include +#include + +TypeHandle LinuxJoystickDevice::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: LinuxJoystickDevice::Constructor +// Access: Private +// Description: Creates a new device using the Linux joystick +// device using the given device filename. +//////////////////////////////////////////////////////////////////// +LinuxJoystickDevice:: +LinuxJoystickDevice(const string &device) : + _fd(-1), + _device(device) +{ + LightMutexHolder holder(_lock); + if (!open_device()) { + device_cat.error() + << "Could not open joystick device " << _device + << ": " << strerror(errno) << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LinuxJoystickDevice::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +LinuxJoystickDevice:: +~LinuxJoystickDevice() { + if (_fd != -1) { + close(_fd); + _fd = -1; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LinuxJoystickDevice::do_poll +// Access: Private, Virtual +// Description: Polls the input device for new activity, to ensure +// it contains the latest events. This will only have +// any effect for some types of input devices; others +// may be updated automatically, and this method will +// be a no-op. +//////////////////////////////////////////////////////////////////// +void LinuxJoystickDevice:: +do_poll() { + if (_fd != -1) { + while (process_events()) {} + } else { + open_device(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LinuxJoystickDevice::open_device +// Access: Private +// Description: Opens or reopens the joystick device, and reads out +// the button and axis mappings. +// Assumes the lock has been held. +//////////////////////////////////////////////////////////////////// +bool LinuxJoystickDevice:: +open_device() { + nassertr(_lock.debug_is_locked(), false); + + _fd = open(_device.c_str(), O_RDONLY | O_NONBLOCK); + + if (_fd == -1) { + _is_connected = false; + return false; + } + + // Read the name from the device. + char name[128]; + name[0] = 0; + ioctl(_fd, JSIOCGNAME(sizeof(name)), name); + _name = name; + + // Get the number of axes. + PN_uint8 num_axes = 0, num_buttons = 0; + ioctl(_fd, JSIOCGAXES, &num_axes); + ioctl(_fd, JSIOCGBUTTONS, &num_buttons); + + _buttons.resize(num_buttons); + _controls.resize(num_axes); + + if (num_buttons > 0) { + PN_uint16 btnmap[512]; + ioctl(_fd, JSIOCGBTNMAP, btnmap); + + for (char i = 0; i < num_buttons; ++i) { + ButtonHandle handle = ButtonHandle::none(); + switch (btnmap[i]) { + case BTN_A: + handle = GamepadButton::action_a(); + _device_class = DC_gamepad; + break; + + case BTN_B: + handle = GamepadButton::action_b(); + break; + + case BTN_C: + handle = GamepadButton::action_c(); + break; + + case BTN_X: + handle = GamepadButton::action_x(); + break; + + case BTN_Y: + handle = GamepadButton::action_y(); + break; + + case BTN_Z: + handle = GamepadButton::action_z(); + break; + + case BTN_TL: + handle = GamepadButton::lshoulder(); + break; + + case BTN_TR: + handle = GamepadButton::rshoulder(); + break; + + case BTN_TL2: + handle = GamepadButton::ltrigger(); + break; + + case BTN_TR2: + handle = GamepadButton::rtrigger(); + break; + + case BTN_SELECT: + handle = GamepadButton::back(); + break; + + case BTN_START: + handle = GamepadButton::start(); + break; + + case BTN_MODE: + handle = GamepadButton::guide(); + break; + + case BTN_THUMBL: + handle = GamepadButton::lstick(); + break; + + case BTN_THUMBR: + handle = GamepadButton::rstick(); + break; + + case BTN_TRIGGER_HAPPY1: + handle = GamepadButton::dpad_left(); + break; + + case BTN_TRIGGER_HAPPY2: + handle = GamepadButton::dpad_right(); + break; + + case BTN_TRIGGER_HAPPY3: + handle = GamepadButton::dpad_up(); + break; + + case BTN_TRIGGER_HAPPY4: + handle = GamepadButton::dpad_down(); + break; + + default: + handle = ButtonHandle::none(); + break; + } + _buttons[i]._handle = handle; + } + } + + if (num_axes > 0) { + PN_uint8 axmap[512]; + ioctl(_fd, JSIOCGAXMAP, axmap); + + for (char i = 0; i < num_axes; ++i) { + ControlAxis axis = C_none; + + switch (axmap[i]) { + case ABS_X: + if (_device_class == DC_gamepad) { + axis = C_left_x; + } else { + axis = C_x; + } + break; + + case ABS_Y: + if (_device_class == DC_gamepad) { + axis = C_left_y; + } else { + axis = C_y; + } + break; + + case ABS_Z: + if (_device_class == DC_gamepad) { + axis = C_left_trigger; + } else { + axis = C_trigger; + } + break; + + case ABS_RX: + axis = C_right_x; + break; + + case ABS_RY: + axis = C_right_y; + break; + + case ABS_RZ: + axis = C_right_trigger; + break; + + default: + axis = C_none; + break; + } + _controls[i]._axis = axis; + } + } + + // Read the init events. + _is_connected = true; + while (process_events()) {}; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: LinuxJoystickDevice::process_events +// Access: Private +// Description: Reads a number of events from the joystick. +//////////////////////////////////////////////////////////////////// +bool LinuxJoystickDevice:: +process_events() { + // Read 8 events at a time. + struct js_event events[8]; + + int n_read = read(_fd, events, sizeof(events)); + if (n_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // No data available for now. + + } else if (errno == ENODEV) { + // The device ceased to exist, so we better close it. + close(_fd); + _fd = -1; + _is_connected = false; + errno = 0; + + } else { + device_cat.error() << "read: " << strerror(errno) << "\n"; + } + return false; + } + + if (n_read == 0) { + return false; + } + + n_read /= sizeof(struct js_event); + + for (int i = 0; i < n_read; ++i) { + int index = events[i].number; + + if (events[i].type & JS_EVENT_BUTTON) { + set_button_state(index, (events[i].value != 0)); + + } else if (events[i].type & JS_EVENT_AXIS) { + ControlAxis axis = _controls[index]._axis; + + if (axis == C_left_trigger || axis == C_right_trigger || axis == C_trigger) { + // We'd like to use 0.0 to indicate the resting position. + set_control_state(index, (events[i].value + 32767) / 65534.0); + } else { + set_control_state(index, events[i].value / 32767.0); + } + } + } + + return true; +} + +#endif diff --git a/panda/src/device/linuxJoystickDevice.h b/panda/src/device/linuxJoystickDevice.h new file mode 100644 index 0000000000..d71ad45c17 --- /dev/null +++ b/panda/src/device/linuxJoystickDevice.h @@ -0,0 +1,60 @@ +// Filename: linuxJoystickDevice.h +// Created by: rdb (21Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef LINUXJOYSTICKDEVICE_H +#define LINUXJOYSTICKDEVICE_H + +#include "inputDevice.h" + +#ifdef PHAVE_LINUX_INPUT_H + +//////////////////////////////////////////////////////////////////// +// Class : LinuxJoystickDevice +// Description : This is a type of device that uses the Linux +// /dev/input/js# API to read data from a game controller. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_DEVICE LinuxJoystickDevice : public InputDevice { +PUBLISHED: + LinuxJoystickDevice(const string &device); + virtual ~LinuxJoystickDevice(); + +private: + virtual void do_poll(); + + bool open_device(); + bool process_events(); + +private: + int _fd; + string _device; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + InputDevice::init_type(); + register_type(_type_handle, "LinuxJoystickDevice", + InputDevice::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "linuxJoystickDevice.I" + +#endif // PHAVE_LINUX_INPUT_H + +#endif // LINUXJOYSTICKDEVICE_H diff --git a/panda/src/device/p3device_composite1.cxx b/panda/src/device/p3device_composite1.cxx index b48fae48ec..80fa832775 100644 --- a/panda/src/device/p3device_composite1.cxx +++ b/panda/src/device/p3device_composite1.cxx @@ -5,4 +5,7 @@ #include "clientDevice.cxx" #include "clientDialDevice.cxx" #include "clientTrackerDevice.cxx" - +#include "evdevInputDevice.cxx" +#include "inputDevice.cxx" +#include "inputDeviceManager.cxx" +#include "linuxJoystickDevice.cxx" diff --git a/panda/src/device/p3device_composite2.cxx b/panda/src/device/p3device_composite2.cxx index 9457fca14c..294e5d69ae 100644 --- a/panda/src/device/p3device_composite2.cxx +++ b/panda/src/device/p3device_composite2.cxx @@ -3,7 +3,6 @@ #include "analogNode.cxx" #include "buttonNode.cxx" #include "dialNode.cxx" -#include "mouseAndKeyboard.cxx" #include "trackerData.cxx" #include "trackerNode.cxx" #include "virtualMouse.cxx" diff --git a/panda/src/device/trackerNode.I b/panda/src/device/trackerNode.I index 5f872c7ea3..5aa067e730 100644 --- a/panda/src/device/trackerNode.I +++ b/panda/src/device/trackerNode.I @@ -20,10 +20,9 @@ //////////////////////////////////////////////////////////////////// INLINE bool TrackerNode:: is_valid() const { - return (_tracker != (ClientTrackerDevice *)NULL) && _tracker->is_connected(); + return (!_tracker.is_null()/* && _tracker->is_connected()*/); } - //////////////////////////////////////////////////////////////////// // Function: TrackerNode::get_pos // Access: Public diff --git a/panda/src/device/trackerNode.cxx b/panda/src/device/trackerNode.cxx index edc20ca07d..095fbfc141 100644 --- a/panda/src/device/trackerNode.cxx +++ b/panda/src/device/trackerNode.cxx @@ -51,7 +51,7 @@ TrackerNode(ClientBase *client, const string &device_name) : return; } - _tracker = DCAST(ClientTrackerDevice, device); + _tracker = device; } //////////////////////////////////////////////////////////////////// @@ -60,18 +60,19 @@ TrackerNode(ClientBase *client, const string &device_name) : // Description: //////////////////////////////////////////////////////////////////// TrackerNode:: -TrackerNode(ClientTrackerDevice *device) : - DataNode(device->get_device_name()), +TrackerNode(InputDevice *device) : + DataNode(device->get_name()), _tracker(device) { _transform_output = define_output("transform", TransformState::get_class_type()); _transform = TransformState::make_identity(); - nassertv(device != (ClientTrackerDevice *)NULL); - ClientBase *client = device->get_client(); - nassertv(client != (ClientBase *)NULL); - set_tracker_coordinate_system(client->get_coordinate_system()); + nassertv(device != (InputDevice *)NULL); + nassertv(device->has_tracker()); + + //TODO: get coordinate system from tracker object? + set_tracker_coordinate_system(CS_default); set_graph_coordinate_system(CS_default); } @@ -105,9 +106,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, DataNodeTransmit &output) { if (is_valid()) { _tracker->poll(); - _tracker->acquire(); - _data = _tracker->get_data(); - _tracker->unlock(); + _data = _tracker->get_tracker(); _data.get_orient().extract_to_matrix(_mat); if (_tracker_cs != _graph_cs) { diff --git a/panda/src/device/trackerNode.h b/panda/src/device/trackerNode.h index 8010c9da7b..9cef1c2d7f 100644 --- a/panda/src/device/trackerNode.h +++ b/panda/src/device/trackerNode.h @@ -19,7 +19,7 @@ #include "clientBase.h" #include "trackerData.h" -#include "clientTrackerDevice.h" +#include "inputDevice.h" #include "dataNode.h" #include "luse.h" #include "linmath_events.h" @@ -27,16 +27,16 @@ //////////////////////////////////////////////////////////////////// // Class : TrackerNode -// Description : This is the primary interface to a Tracker object -// associated with a ClientBase. It reads the position -// and orientation information from the tracker and -// makes it available as a transformation on the data -// graph. +// Description : This class reads the position and orientation +// information from a tracker device and makes it +// available as a transformation on the data graph. +// It is also the primary interface to a Tracker object +// associated with a ClientBase. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_DEVICE TrackerNode : public DataNode { PUBLISHED: TrackerNode(ClientBase *client, const string &device_name); - TrackerNode(ClientTrackerDevice *device); + TrackerNode(InputDevice *device); virtual ~TrackerNode(); INLINE bool is_valid() const; @@ -66,7 +66,7 @@ private: CPT(TransformState) _transform; private: - PT(ClientTrackerDevice) _tracker; + PT(InputDevice) _tracker; TrackerData _data; LMatrix4 _mat; CoordinateSystem _tracker_cs, _graph_cs; diff --git a/panda/src/display/callbackGraphicsWindow.cxx b/panda/src/display/callbackGraphicsWindow.cxx index 6de33cc9d6..af1d4169e7 100644 --- a/panda/src/display/callbackGraphicsWindow.cxx +++ b/panda/src/display/callbackGraphicsWindow.cxx @@ -54,22 +54,6 @@ CallbackGraphicsWindow:: ~CallbackGraphicsWindow() { } - -//////////////////////////////////////////////////////////////////// -// Function: CallbackGraphicsWindow::get_input_device -// Access: Published -// Description: Returns a writable reference to the nth input device -// (mouse). This is intended to be used for the window -// implementation to record mouse and keyboard input -// information for the Panda system. -//////////////////////////////////////////////////////////////////// -GraphicsWindowInputDevice &CallbackGraphicsWindow:: -get_input_device(int device) { - LightMutexHolder holder(_input_lock); - nassertr(device >= 0 && device < (int)_input_devices.size(), _input_devices[0]); - return _input_devices[device]; -} - //////////////////////////////////////////////////////////////////// // Function: CallbackGraphicsWindow::create_input_device // Access: Published @@ -79,9 +63,7 @@ get_input_device(int device) { //////////////////////////////////////////////////////////////////// int CallbackGraphicsWindow:: create_input_device(const string &name) { - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, name); - return add_input_device(device); + return add_input_device(GraphicsWindowInputDevice::pointer_and_keyboard(this, name)); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/callbackGraphicsWindow.h b/panda/src/display/callbackGraphicsWindow.h index c34d324126..e1633959db 100644 --- a/panda/src/display/callbackGraphicsWindow.h +++ b/panda/src/display/callbackGraphicsWindow.h @@ -182,7 +182,6 @@ PUBLISHED: INLINE void clear_render_callback(); INLINE CallbackObject *get_render_callback() const; - GraphicsWindowInputDevice &get_input_device(int device); int create_input_device(const string &name); public: diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index a62e6a4fb0..f98508894b 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -22,9 +22,11 @@ #include "graphicsPipe.h" #include "graphicsOutput.h" #include "graphicsBuffer.h" -#include "graphicsWindow.h" #include "graphicsDevice.h" +#include "graphicsWindow.h" +#include "graphicsWindowInputDevice.h" #include "graphicsWindowProcCallbackData.h" +#include "mouseAndKeyboard.h" #include "nativeWindowHandle.h" #include "parasiteBuffer.h" #include "pandaSystem.h" @@ -501,7 +503,9 @@ init_libdisplay() { GraphicsPipe::init_type(); GraphicsStateGuardian::init_type(); GraphicsWindow::init_type(); + GraphicsWindowInputDevice::init_type(); GraphicsWindowProcCallbackData::init_type(); + MouseAndKeyboard::init_type(); NativeWindowHandle::init_type(); ParasiteBuffer::init_type(); StandardMunger::init_type(); diff --git a/panda/src/display/graphicsWindow.cxx b/panda/src/display/graphicsWindow.cxx index 6166f9cbac..b6d4976181 100644 --- a/panda/src/display/graphicsWindow.cxx +++ b/panda/src/display/graphicsWindow.cxx @@ -288,6 +288,20 @@ get_num_input_devices() const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindow::get_input_device +// Access: Published +// Description: Returns the nth input device associated with the +// window. Typically, a window will have exactly one +// input device: the keyboard/mouse pair. +//////////////////////////////////////////////////////////////////// +InputDevice *GraphicsWindow:: +get_input_device(int device) const { + LightMutexHolder holder(_input_lock); + nassertr(device >= 0 && device < (int)_input_devices.size(), NULL); + return _input_devices[device]; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsWindow::get_input_device_name // Access: Published @@ -299,7 +313,7 @@ get_input_device_name(int device) const { { LightMutexHolder holder(_input_lock); nassertr(device >= 0 && device < (int)_input_devices.size(), ""); - result = _input_devices[device].get_name(); + result = _input_devices[device]->get_name(); } return result; } @@ -317,7 +331,7 @@ has_pointer(int device) const { { LightMutexHolder holder(_input_lock); nassertr(device >= 0 && device < (int)_input_devices.size(), false); - result = _input_devices[device].has_pointer(); + result = _input_devices[device]->has_pointer(); } return result; } @@ -334,7 +348,7 @@ has_keyboard(int device) const { { LightMutexHolder holder(_input_lock); nassertr(device >= 0 && device < (int)_input_devices.size(), false); - result = _input_devices[device].has_keyboard(); + result = _input_devices[device]->has_keyboard(); } return result; } @@ -359,7 +373,7 @@ void GraphicsWindow:: enable_pointer_events(int device) { LightMutexHolder holder(_input_lock); nassertv(device >= 0 && device < (int)_input_devices.size()); - _input_devices[device].enable_pointer_events(); + _input_devices[device]->enable_pointer_events(); } //////////////////////////////////////////////////////////////////// @@ -371,7 +385,7 @@ void GraphicsWindow:: disable_pointer_events(int device) { LightMutexHolder holder(_input_lock); nassertv(device >= 0 && device < (int)_input_devices.size()); - _input_devices[device].disable_pointer_events(); + _input_devices[device]->disable_pointer_events(); } //////////////////////////////////////////////////////////////////// @@ -379,11 +393,11 @@ disable_pointer_events(int device) { // Access: Published // Description: See GraphicsWindowInputDevice::enable_pointer_mode //////////////////////////////////////////////////////////////////// -void GraphicsWindow:: +/*void GraphicsWindow:: enable_pointer_mode(int device, double speed) { LightMutexHolder holder(_input_lock); nassertv(device >= 0 && device < (int)_input_devices.size()); - _input_devices[device].enable_pointer_mode(speed); + _input_devices[device]->enable_pointer_mode(speed); } //////////////////////////////////////////////////////////////////// @@ -395,8 +409,8 @@ void GraphicsWindow:: disable_pointer_mode(int device) { LightMutexHolder holder(_input_lock); nassertv(device >= 0 && device < (int)_input_devices.size()); - _input_devices[device].disable_pointer_mode(); -} + _input_devices[device]->disable_pointer_mode(); +}*/ //////////////////////////////////////////////////////////////////// // Function: GraphicsWindow::get_pointer @@ -412,7 +426,7 @@ get_pointer(int device) const { { LightMutexHolder holder(_input_lock); nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData()); - result = _input_devices[device].get_pointer(); + result = _input_devices[device]->get_pointer(); } return result; } @@ -443,81 +457,6 @@ close_ime() { return; } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::has_button_event -// Access: Public -// Description: Returns true if the indicated device has a pending -// button event (a mouse button or keyboard button -// down/up), false otherwise. If this returns true, the -// particular event may be extracted via -// get_button_event(). -//////////////////////////////////////////////////////////////////// -bool GraphicsWindow:: -has_button_event(int device) const { - bool result; - { - LightMutexHolder holder(_input_lock); - nassertr(device >= 0 && device < (int)_input_devices.size(), false); - result = _input_devices[device].has_button_event(); - } - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::get_button_event -// Access: Public -// Description: Assuming a previous call to has_button_event() -// returned true, this returns the pending button event. -//////////////////////////////////////////////////////////////////// -ButtonEvent GraphicsWindow:: -get_button_event(int device) { - ButtonEvent result; - { - LightMutexHolder holder(_input_lock); - nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent()); - nassertr(_input_devices[device].has_button_event(), ButtonEvent()); - result = _input_devices[device].get_button_event(); - } - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::has_pointer_event -// Access: Public -// Description: Returns true if the indicated device has a pending -// pointer event (a mouse movement). If this returns -// true, the particular event may be extracted via -// get_pointer_events(). -//////////////////////////////////////////////////////////////////// -bool GraphicsWindow:: -has_pointer_event(int device) const { - bool result; - { - LightMutexHolder holder(_input_lock); - nassertr(device >= 0 && device < (int)_input_devices.size(), false); - result = _input_devices[device].has_pointer_event(); - } - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::get_pointer_events -// Access: Public -// Description: Assuming a previous call to has_pointer_event() -// returned true, this returns the pending pointer event list. -//////////////////////////////////////////////////////////////////// -PT(PointerEventList) GraphicsWindow:: -get_pointer_events(int device) { - PT(PointerEventList) result; - { - LightMutexHolder holder(_input_lock); - nassertr(device >= 0 && device < (int)_input_devices.size(), NULL); - nassertr(_input_devices[device].has_pointer_event(), NULL); - result = _input_devices[device].get_pointer_events(); - } - return result; -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsWindow::verify_window_sizes // Access: Public, Virtual @@ -860,11 +799,15 @@ system_changed_size(int x_size, int y_size) { // Returns the index of the new device. //////////////////////////////////////////////////////////////////// int GraphicsWindow:: -add_input_device(const GraphicsWindowInputDevice &device) { +add_input_device(InputDevice *device) { LightMutexHolder holder(_input_lock); int index = (int)_input_devices.size(); _input_devices.push_back(device); - _input_devices.back().set_device_index(index); + + if (device->is_of_type(GraphicsWindowInputDevice::get_class_type())) { + ((GraphicsWindowInputDevice *)device)->set_device_index(index); + } + return index; } diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index e7ebab8c80..dbeae1e1da 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -82,10 +82,12 @@ PUBLISHED: INLINE WindowHandle *get_window_handle() const; MAKE_PROPERTY(window_handle, get_window_handle); - + // Mouse and keyboard routines int get_num_input_devices() const; + InputDevice *get_input_device(int i) const; string get_input_device_name(int device) const; + MAKE_SEQ(get_input_devices, get_num_input_devices, get_input_device); MAKE_SEQ(get_input_device_names, get_num_input_devices, get_input_device_name); bool has_pointer(int device) const; bool has_keyboard(int device) const; @@ -93,20 +95,14 @@ PUBLISHED: void enable_pointer_events(int device); void disable_pointer_events(int device); - void enable_pointer_mode(int device, double speed); - void disable_pointer_mode(int device); + /*void enable_pointer_mode(int device, double speed); + void disable_pointer_mode(int device);*/ MouseData get_pointer(int device) const; virtual bool move_pointer(int device, int x, int y); virtual void close_ime(); public: - // No need to publish these. - bool has_button_event(int device) const; - ButtonEvent get_button_event(int device); - bool has_pointer_event(int device) const; - PT(PointerEventList) get_pointer_events(int device); - virtual void add_window_proc( const GraphicsWindowProc* wnd_proc_object ){}; virtual void remove_window_proc( const GraphicsWindowProc* wnd_proc_object ){}; virtual void clear_window_procs(){}; @@ -146,8 +142,8 @@ protected: void system_changed_size(int x_size, int y_size); protected: - int add_input_device(const GraphicsWindowInputDevice &device); - typedef vector_GraphicsWindowInputDevice InputDevices; + int add_input_device(InputDevice *device); + typedef pvector InputDevices; InputDevices _input_devices; LightMutex _input_lock; diff --git a/panda/src/display/graphicsWindowInputDevice.I b/panda/src/display/graphicsWindowInputDevice.I index 3763d7baa4..ea26364be7 100644 --- a/panda/src/display/graphicsWindowInputDevice.I +++ b/panda/src/display/graphicsWindowInputDevice.I @@ -12,73 +12,14 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// // Function: GraphicsWindowInputDevice::Default Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GraphicsWindowInputDevice:: -GraphicsWindowInputDevice() { - LightMutexHolder holder(_lock); - _flags = 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_name -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE string GraphicsWindowInputDevice:: -get_name() const { - LightMutexHolder holder(_lock); - return _name; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::has_pointer -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool GraphicsWindowInputDevice:: -has_pointer() const { - LightMutexHolder holder(_lock); - return ((_flags & IDF_has_pointer) != 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::has_keyboard -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool GraphicsWindowInputDevice:: -has_keyboard() const { - LightMutexHolder holder(_lock); - return ((_flags & IDF_has_keyboard) != 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_pointer -// Access: Public -// Description: Returns the MouseData associated with the input -// device's pointer. -//////////////////////////////////////////////////////////////////// -INLINE MouseData GraphicsWindowInputDevice:: -get_pointer() const { - LightMutexHolder holder(_lock); - return _mouse_data; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_raw_pointer -// Access: Public -// Description: Returns the MouseData associated with the input -// device's pointer, in raw form (ie, prior to any -// pointer_mode interpretation). -//////////////////////////////////////////////////////////////////// -INLINE MouseData GraphicsWindowInputDevice:: -get_raw_pointer() const { - LightMutexHolder holder(_lock); - return _true_mouse_data; +GraphicsWindowInputDevice() : _host(NULL) { } //////////////////////////////////////////////////////////////////// @@ -90,140 +31,9 @@ get_raw_pointer() const { //////////////////////////////////////////////////////////////////// INLINE void GraphicsWindowInputDevice:: set_device_index(int index) { - LightMutexHolder holder(_lock); _device_index = index; } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::enable_pointer_events -// Access: Public -// Description: Enables the generation of mouse-movement events. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -enable_pointer_events() { - LightMutexHolder holder(_lock); - _enable_pointer_events = true; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::disable_pointer_events -// Access: Public -// Description: Disables the generation of mouse-movement events. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -disable_pointer_events() { - LightMutexHolder holder(_lock); - _enable_pointer_events = false; - _pointer_events.clear(); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::button_down -// Access: Published -// Description: Records that the indicated button has been depressed. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -button_down(ButtonHandle button) { - button_down(button, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::button_resume_down -// Access: Published -// Description: Records that the indicated button was depressed -// earlier, and we only just detected the event after -// the fact. This is mainly useful for tracking the -// state of modifier keys. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -button_resume_down(ButtonHandle button) { - button_resume_down(button, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::button_up -// Access: Published -// Description: Records that the indicated button has been released. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -button_up(ButtonHandle button) { - button_up(button, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::keystroke -// Access: Published -// Description: Records that the indicated keystroke has been -// generated. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -keystroke(int keycode) { - keystroke(keycode, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::focus_lost -// Access: Published -// Description: This should be called when the window focus is lost, -// so that we may miss upcoming button events -// (especially "up" events) for the next period of time. -// It generates keyboard and mouse "up" events for those -// buttons that we previously sent unpaired "down" -// events, so that the Panda application will believe -// all buttons are now released. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -focus_lost() { - focus_lost(ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::raw_button_down -// Access: Published -// Description: Records that the indicated button has been depressed. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -raw_button_down(ButtonHandle button) { - raw_button_down(button, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::raw_button_up -// Access: Published -// Description: Records that the indicated button has been released. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -raw_button_up(ButtonHandle button) { - raw_button_up(button, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::set_pointer_in_window -// Access: Published -// Description: To be called by a particular kind of GraphicsWindow -// to indicate that the pointer is within the window, at -// the given pixel coordinates. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -set_pointer_in_window(double x, double y) { - // mutex is handled in set pointer .. convience function - set_pointer(true, x, y, ClockObject::get_global_clock()->get_frame_time()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::set_pointer_out_of_window -// Access: Published -// Description: To be called by a particular kind of GraphicsWindow -// to indicate that the pointer is no longer within the -// window. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -set_pointer_out_of_window() { - // mutex is handled in set pointer .. convience function - set_pointer(false, _mouse_data._xpos, _mouse_data._ypos, - ClockObject::get_global_clock()->get_frame_time()); -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsWindowInputDevice::set_pointer_in_window // Access: Published @@ -233,8 +43,8 @@ set_pointer_out_of_window() { //////////////////////////////////////////////////////////////////// INLINE void GraphicsWindowInputDevice:: set_pointer_in_window(double x, double y, double time) { - // mutex is handled in set pointer .. convience function - set_pointer(true, x, y, time); + LightMutexHolder holder(_lock); + InputDevice::set_pointer(true, x, y, time); } //////////////////////////////////////////////////////////////////// @@ -246,36 +56,6 @@ set_pointer_in_window(double x, double y, double time) { //////////////////////////////////////////////////////////////////// INLINE void GraphicsWindowInputDevice:: set_pointer_out_of_window(double time) { - // mutex is handled in set pointer .. convience function - set_pointer(false, _mouse_data._xpos, _mouse_data._ypos, time); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::operator == -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool GraphicsWindowInputDevice:: -operator == (const GraphicsWindowInputDevice &) const { - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::operator != -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool GraphicsWindowInputDevice:: -operator != (const GraphicsWindowInputDevice &) const { - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::operator < -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE bool GraphicsWindowInputDevice:: -operator < (const GraphicsWindowInputDevice &) const { - return false; + LightMutexHolder holder(_lock); + InputDevice::set_pointer_out_of_window(time); } diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index a1d4950205..e7a3c360b4 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -18,17 +18,7 @@ #include "mouseButton.h" #include "keyboardButton.h" -#define EXPCL EXPCL_PANDA_DISPLAY -#define EXPTP EXPTP_PANDA_DISPLAY -#define TYPE GraphicsWindowInputDevice -#define NAME vector_GraphicsWindowInputDevice - -#include "vector_src.cxx" - -// Tell GCC that we'll take care of the instantiation explicitly here. -#ifdef __GNUC__ -#pragma implementation -#endif +TypeHandle GraphicsWindowInputDevice::_type_handle; //////////////////////////////////////////////////////////////////// // Function: GraphicsWindowInputDevice::Constructor @@ -43,14 +33,8 @@ //////////////////////////////////////////////////////////////////// GraphicsWindowInputDevice:: GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags) : - _host(host), - _name(name), - _flags(flags), - _device_index(0), - _event_sequence(0), - _pointer_mode_enable(false), - _pointer_speed(1.0), - _enable_pointer_events(false) + InputDevice(name, DC_virtual, flags), + _host(host) { } @@ -60,9 +44,9 @@ GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags) : // Description: This named constructor returns an input device that // only has a pointing device, no keyboard. //////////////////////////////////////////////////////////////////// -GraphicsWindowInputDevice GraphicsWindowInputDevice:: +PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice:: pointer_only(GraphicsWindow *host, const string &name) { - return GraphicsWindowInputDevice(host, name, IDF_has_pointer); + return new GraphicsWindowInputDevice(host, name, IDF_has_pointer); } //////////////////////////////////////////////////////////////////// @@ -71,9 +55,9 @@ pointer_only(GraphicsWindow *host, const string &name) { // Description: This named constructor returns an input device that // only has a keyboard, no pointing device. //////////////////////////////////////////////////////////////////// -GraphicsWindowInputDevice GraphicsWindowInputDevice:: +PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice:: keyboard_only(GraphicsWindow *host, const string &name) { - return GraphicsWindowInputDevice(host, name, IDF_has_keyboard); + return new GraphicsWindowInputDevice(host, name, IDF_has_keyboard); } //////////////////////////////////////////////////////////////////// @@ -82,9 +66,9 @@ keyboard_only(GraphicsWindow *host, const string &name) { // Description: This named constructor returns an input device that // has both a keyboard and pointer. //////////////////////////////////////////////////////////////////// -GraphicsWindowInputDevice GraphicsWindowInputDevice:: +PT(GraphicsWindowInputDevice) GraphicsWindowInputDevice:: pointer_and_keyboard(GraphicsWindow *host, const string &name) { - return + return new GraphicsWindowInputDevice(host, name, IDF_has_pointer | IDF_has_keyboard); } @@ -94,9 +78,8 @@ pointer_and_keyboard(GraphicsWindow *host, const string &name) { // Description: //////////////////////////////////////////////////////////////////// GraphicsWindowInputDevice:: -GraphicsWindowInputDevice(const GraphicsWindowInputDevice ©) -{ - *this = copy; +GraphicsWindowInputDevice(const GraphicsWindowInputDevice ©) { + *this = copy; } //////////////////////////////////////////////////////////////////// @@ -105,22 +88,9 @@ GraphicsWindowInputDevice(const GraphicsWindowInputDevice ©) // Description: //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: -operator = (const GraphicsWindowInputDevice ©) -{ - LightMutexHolder holder(_lock); - LightMutexHolder holder1(copy._lock); +operator = (const GraphicsWindowInputDevice ©) { _host = copy._host; - _name = copy._name; - _flags = copy._flags; - _device_index = copy._device_index; - _event_sequence = copy._event_sequence; - _pointer_mode_enable = copy._pointer_mode_enable; - _pointer_speed = copy._pointer_speed; - _enable_pointer_events = copy._enable_pointer_events; - _mouse_data = copy._mouse_data; - _true_mouse_data = copy._true_mouse_data; - _button_events = copy._button_events; - _pointer_events = copy._pointer_events; + InputDevice::operator = (copy); } //////////////////////////////////////////////////////////////////// @@ -132,151 +102,6 @@ GraphicsWindowInputDevice:: ~GraphicsWindowInputDevice() { } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::has_button_event -// Access: Public -// Description: Returns true if this device has a pending button -// event (a mouse button or keyboard button down/up), -// false otherwise. If this returns true, the -// particular event may be extracted via -// get_button_event(). -//////////////////////////////////////////////////////////////////// -bool GraphicsWindowInputDevice:: -has_button_event() const { - LightMutexHolder holder(_lock); - return !_button_events.empty(); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_button_event -// Access: Public -// Description: Assuming a previous call to has_button_event() -// returned true, this returns the pending button event. -//////////////////////////////////////////////////////////////////// -ButtonEvent GraphicsWindowInputDevice:: -get_button_event() { - LightMutexHolder holder(_lock); - ButtonEvent be = _button_events.front(); - _button_events.pop_front(); - return be; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::has_pointer_event -// Access: Public -// Description: Returns true if this device has a pending pointer -// event (a mouse movement), or false otherwise. If -// this returns true, the particular event may be -// extracted via get_pointer_event(). -//////////////////////////////////////////////////////////////////// -bool GraphicsWindowInputDevice:: -has_pointer_event() const { - LightMutexHolder holder(_lock); - return (_pointer_events != 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_pointer_events -// Access: Public -// Description: Returns a PointerEventList containing all the recent -// pointer events. -//////////////////////////////////////////////////////////////////// -PT(PointerEventList) GraphicsWindowInputDevice:: -get_pointer_events() { - LightMutexHolder holder(_lock); - PT(PointerEventList) result = _pointer_events; - _pointer_events = 0; - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::enable_pointer_mode -// Access: Public -// Description: There are two modes: raw mode, and pointer mode. -// In pointer mode, the mouse stops when it reaches the -// edges of the window. In raw mode, the mouse ignores -// the screen boundaries and can continue indefinitely, -// even into negative coordinates. In raw mode, each -// "blip" from the mouse hardware corresponds to a -// change of 1 unit in the mouse's (x,y) coordinate. -// In pointer mode, a variety of speed adjustment factors -// and concepts like "mouse acceleration" may be applied. -// -// Mouse zero represents the system mouse pointer. This -// is by definition a pointer, not a raw mouse. It is -// an error to try to enable or disable pointer mode on -// mouse zero. -//////////////////////////////////////////////////////////////////// -void GraphicsWindowInputDevice:: -enable_pointer_mode(double speed) { - LightMutexHolder holder(_lock); - nassertv(_device_index != 0); - _pointer_mode_enable = true; - _pointer_speed = speed; - _mouse_data._xpos = _host->get_x_size() * 0.5; - _mouse_data._ypos = _host->get_y_size() * 0.5; - _mouse_data._in_window = true; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::disable_pointer_mode -// Access: Public -// Description: see enable_pointer_mode. -//////////////////////////////////////////////////////////////////// -void GraphicsWindowInputDevice:: -disable_pointer_mode() { - LightMutexHolder holder(_lock); - nassertv(_device_index != 0); - _pointer_mode_enable = false; - _pointer_speed = 1.0; - _mouse_data = _true_mouse_data; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::set_pointer -// Access: Published -// Description: Records that a mouse movement has taken place. -//////////////////////////////////////////////////////////////////// -void GraphicsWindowInputDevice:: -set_pointer(bool inwin, double x, double y, double time) { - LightMutexHolder holder(_lock); - - double delta_x = x - _true_mouse_data._xpos; - double delta_y = y - _true_mouse_data._ypos; - _true_mouse_data._in_window = inwin; - _true_mouse_data._xpos = x; - _true_mouse_data._ypos = y; - - if (_pointer_mode_enable) { - double pointer_x = _mouse_data._xpos; - double pointer_y = _mouse_data._ypos; - pointer_x += (delta_x * _pointer_speed); - pointer_y += (delta_y * _pointer_speed); - double xhi = _host->get_x_size(); - double yhi = _host->get_y_size(); - if (pointer_x < 0.0) pointer_x = 0.0; - if (pointer_y < 0.0) pointer_y = 0.0; - if (pointer_x > xhi) pointer_x = xhi; - if (pointer_y > yhi) pointer_y = yhi; - _mouse_data._in_window = true; - _mouse_data._xpos = pointer_x; - _mouse_data._ypos = pointer_y; - } else { - _mouse_data = _true_mouse_data; - } - - if (_enable_pointer_events) { - int seq = _event_sequence++; - if (_pointer_events == 0) { - _pointer_events = new PointerEventList(); - } - _pointer_events->add_event(_mouse_data._in_window, - _mouse_data._xpos, - _mouse_data._ypos, - seq, time); - } -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsWindowInputDevice::button_down // Access: Published @@ -285,7 +110,7 @@ set_pointer(bool inwin, double x, double y, double time) { void GraphicsWindowInputDevice:: button_down(ButtonHandle button, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_down, time)); + _button_events->add_event(ButtonEvent(button, ButtonEvent::T_down, time)); _buttons_held.insert(button); } @@ -300,7 +125,7 @@ button_down(ButtonHandle button, double time) { void GraphicsWindowInputDevice:: button_resume_down(ButtonHandle button, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time)); + _button_events->add_event(ButtonEvent(button, ButtonEvent::T_resume_down, time)); _buttons_held.insert(button); } @@ -312,7 +137,7 @@ button_resume_down(ButtonHandle button, double time) { void GraphicsWindowInputDevice:: button_up(ButtonHandle button, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_up, time)); + _button_events->add_event(ButtonEvent(button, ButtonEvent::T_up, time)); _buttons_held.erase(button); } @@ -325,7 +150,7 @@ button_up(ButtonHandle button, double time) { void GraphicsWindowInputDevice:: keystroke(int keycode, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(keycode, time)); + _button_events->add_event(ButtonEvent(keycode, time)); } //////////////////////////////////////////////////////////////////// @@ -340,7 +165,7 @@ void GraphicsWindowInputDevice:: candidate(const wstring &candidate_string, size_t highlight_start, size_t highlight_end, size_t cursor_pos) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(candidate_string, + _button_events->add_event(ButtonEvent(candidate_string, highlight_start, highlight_end, cursor_pos)); } @@ -361,7 +186,7 @@ focus_lost(double time) { LightMutexHolder holder(_lock); ButtonsHeld::iterator bi; for (bi = _buttons_held.begin(); bi != _buttons_held.end(); ++bi) { - _button_events.push_back(ButtonEvent(*bi, ButtonEvent::T_up, time)); + _button_events->add_event(ButtonEvent(*bi, ButtonEvent::T_up, time)); } _buttons_held.clear(); } @@ -374,7 +199,7 @@ focus_lost(double time) { void GraphicsWindowInputDevice:: raw_button_down(ButtonHandle button, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_down, time)); + _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_down, time)); } //////////////////////////////////////////////////////////////////// @@ -385,5 +210,5 @@ raw_button_down(ButtonHandle button, double time) { void GraphicsWindowInputDevice:: raw_button_up(ButtonHandle button, double time) { LightMutexHolder holder(_lock); - _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_up, time)); + _button_events->add_event(ButtonEvent(button, ButtonEvent::T_raw_up, time)); } diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index e76d48c5bc..56e62ffab0 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -16,139 +16,79 @@ #define GRAPHICSWINDOWINPUTDEVICE_H #include "pandabase.h" - -#include "buttonEvent.h" -#include "pointerEvent.h" -#include "pointerEventList.h" -#include "mouseData.h" -#include "clockObject.h" - -#include "pdeque.h" -#include "pvector.h" -#include "lightMutex.h" -#include "lightMutexHolder.h" +#include "inputDevice.h" // Forward declarations class GraphicsWindow; //////////////////////////////////////////////////////////////////// // Class : GraphicsWindowInputDevice -// Description : This is a structure representing a single input -// device that may be associated with a window. -// Typically this will be a keyboard/mouse pair, and -// there will be exactly one of these associated with -// each window, but other variants are possible. +// Description : This is a virtual input device that represents +// the keyboard and mouse pair that is associated with +// a particular window. It collects mouse and keyboard +// events from the windowing system while the window is +// in focus. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_DISPLAY GraphicsWindowInputDevice { +class EXPCL_PANDA_DISPLAY GraphicsWindowInputDevice : public InputDevice { private: GraphicsWindowInputDevice(GraphicsWindow *host, const string &name, int flags); 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); + static PT(GraphicsWindowInputDevice) pointer_only(GraphicsWindow *host, const string &name); + static PT(GraphicsWindowInputDevice) keyboard_only(GraphicsWindow *host, const string &name); + static PT(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; - PT(PointerEventList) get_pointer_events(); - PUBLISHED: // The following interface is for the various kinds of // GraphicsWindows to record the data incoming on the device. - INLINE void button_down(ButtonHandle button); - INLINE void button_resume_down(ButtonHandle button); - INLINE void button_up(ButtonHandle button); - INLINE void keystroke(int keycode); - INLINE void focus_lost(); - INLINE void raw_button_down(ButtonHandle button); - INLINE void raw_button_up(ButtonHandle button); - INLINE void set_pointer_in_window(double x, double y); - INLINE void set_pointer_out_of_window(); + 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 button_down(ButtonHandle button, double time); - void button_resume_down(ButtonHandle button, double time); - void button_up(ButtonHandle button, double time); - void keystroke(int keycode, double 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 highlight_end, size_t cursor_pos); - void focus_lost(double time); - void raw_button_down(ButtonHandle button, double time); - void raw_button_up(ButtonHandle button, double time); - INLINE void set_pointer_in_window(double x, double y, double time); - INLINE void set_pointer_out_of_window(double time); - void set_pointer(bool inwin, double x, double y, double time); + void focus_lost(double time = ClockObject::get_global_clock()->get_frame_time()); -public: - // We need these methods to make VC++ happy when we try to - // instantiate a pvector. They don't do - // anything useful. - INLINE bool operator == (const GraphicsWindowInputDevice &other) const; - INLINE bool operator != (const GraphicsWindowInputDevice &other) const; - INLINE bool operator < (const GraphicsWindowInputDevice &other) const; + 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()); private: - enum InputDeviceFlags { - IDF_has_pointer = 0x01, - IDF_has_keyboard = 0x02 - }; - 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; - ButtonEvents _button_events; - PT(PointerEventList) _pointer_events; typedef pset ButtonsHeld; ButtonsHeld _buttons_held; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + InputDevice::init_type(); + register_type(_type_handle, "GraphicsWindowInputDevice", + InputDevice::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; }; #include "graphicsWindowInputDevice.I" -#define EXPCL EXPCL_PANDA_DISPLAY -#define EXPTP EXPTP_PANDA_DISPLAY -#define TYPE GraphicsWindowInputDevice -#define NAME vector_GraphicsWindowInputDevice - -#include "vector_src.h" - -// Tell GCC that we'll take care of the instantiation explicitly here. -#ifdef __GNUC__ -#pragma interface -#endif - #endif diff --git a/panda/src/device/mouseAndKeyboard.cxx b/panda/src/display/mouseAndKeyboard.cxx similarity index 88% rename from panda/src/device/mouseAndKeyboard.cxx rename to panda/src/display/mouseAndKeyboard.cxx index e8c102746e..7666b63404 100644 --- a/panda/src/device/mouseAndKeyboard.cxx +++ b/panda/src/display/mouseAndKeyboard.cxx @@ -41,7 +41,6 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const string &name) : _pixel_xy = new EventStoreVec2(LPoint2(0.0f, 0.0f)); _pixel_size = new EventStoreVec2(LPoint2(0.0f, 0.0f)); _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f)); - _button_events = new ButtonEventList; } //////////////////////////////////////////////////////////////////// @@ -93,20 +92,18 @@ get_source_device() const { void MouseAndKeyboard:: do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, DataNodeTransmit &output) { - if (_window->has_button_event(_device)) { - // Fill up the button events. - _button_events->clear(); - while (_window->has_button_event(_device)) { - ButtonEvent be = _window->get_button_event(_device); - _button_events->add_event(be); - } - output.set_data(_button_events_output, EventParameter(_button_events)); + + PT(InputDevice) device = _window->get_input_device(_device); + + if (device->has_button_event()) { + PT(ButtonEventList) bel = device->get_button_events(); + output.set_data(_button_events_output, EventParameter(bel)); } - if (_window->has_pointer_event(_device)) { - PT(PointerEventList) pel = _window->get_pointer_events(_device); + if (device->has_pointer_event()) { + PT(PointerEventList) pel = device->get_pointer_events(); output.set_data(_pointer_events_output, EventParameter(pel)); } - + // Get the window size. WindowProperties properties = _window->get_properties(); if (properties.has_size()) { @@ -116,18 +113,18 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &, _pixel_size->set_value(LPoint2(w, h)); output.set_data(_pixel_size_output, EventParameter(_pixel_size)); - if (_window->has_pointer(_device)) { - const MouseData &mdata = _window->get_pointer(_device); + if (device->has_pointer()) { + const MouseData &mdata = device->get_pointer(); if (mdata._in_window) { // Get mouse motion in pixels. _pixel_xy->set_value(LPoint2(mdata._xpos, mdata._ypos)); output.set_data(_pixel_xy_output, EventParameter(_pixel_xy)); - + // Normalize pixel motion to range [-1,1]. PN_stdfloat xf = (PN_stdfloat)(2 * mdata._xpos) / (PN_stdfloat)w - 1.0f; PN_stdfloat yf = 1.0f - (PN_stdfloat)(2 * mdata._ypos) / (PN_stdfloat)h; - + _xy->set_value(LPoint2(xf, yf)); output.set_data(_xy_output, EventParameter(_xy)); } diff --git a/panda/src/device/mouseAndKeyboard.h b/panda/src/display/mouseAndKeyboard.h similarity index 98% rename from panda/src/device/mouseAndKeyboard.h rename to panda/src/display/mouseAndKeyboard.h index 939a04aa8a..f39674900a 100644 --- a/panda/src/device/mouseAndKeyboard.h +++ b/panda/src/display/mouseAndKeyboard.h @@ -51,7 +51,7 @@ PUBLISHED: PT(GraphicsWindow) get_source_window() const; int get_source_device() const; - + protected: // Inherited from DataNode virtual void do_transmit_data(DataGraphTraverser *trav, @@ -69,7 +69,6 @@ private: PT(EventStoreVec2) _pixel_xy; PT(EventStoreVec2) _pixel_size; PT(EventStoreVec2) _xy; - PT(ButtonEventList) _button_events; PT(GraphicsWindow) _window; int _device; diff --git a/panda/src/display/p3display_composite2.cxx b/panda/src/display/p3display_composite2.cxx index b3ba58995b..c2d47f7aad 100644 --- a/panda/src/display/p3display_composite2.cxx +++ b/panda/src/display/p3display_composite2.cxx @@ -5,6 +5,7 @@ #include "graphicsWindowProc.cxx" #include "graphicsWindowProcCallbackData.cxx" #include "graphicsWindowInputDevice.cxx" +#include "mouseAndKeyboard.cxx" #include "nativeWindowHandle.cxx" #include "parasiteBuffer.cxx" #include "standardMunger.cxx" diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 44ac7bd6a4..8610341402 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -32,6 +32,7 @@ #include "datagram.h" #include "doubleBitMask.h" #include "factoryParam.h" +#include "gamepadButton.h" #include "namable.h" #include "nodeCachedReferenceCount.h" #include "paramValue.h" @@ -225,6 +226,7 @@ init_libputil() { WritableConfigurable::init_type(); WritableParam::init_type(); + GamepadButton::init_gamepad_buttons(); KeyboardButton::init_keyboard_buttons(); MouseButton::init_mouse_buttons(); diff --git a/panda/src/putil/gamepadButton.cxx b/panda/src/putil/gamepadButton.cxx new file mode 100644 index 0000000000..ed8d41a435 --- /dev/null +++ b/panda/src/putil/gamepadButton.cxx @@ -0,0 +1,75 @@ +// Filename: gamepadButton.cxx +// Created by: rdb (21Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "gamepadButton.h" +#include "buttonRegistry.h" + +#define DEFINE_GAMEPAD_BUTTON_HANDLE(KeyName) \ + static ButtonHandle _##KeyName; \ + ButtonHandle GamepadButton::KeyName() { return _##KeyName; } + +DEFINE_GAMEPAD_BUTTON_HANDLE(lstick) +DEFINE_GAMEPAD_BUTTON_HANDLE(rstick) +DEFINE_GAMEPAD_BUTTON_HANDLE(lshoulder) +DEFINE_GAMEPAD_BUTTON_HANDLE(rshoulder) +DEFINE_GAMEPAD_BUTTON_HANDLE(ltrigger) +DEFINE_GAMEPAD_BUTTON_HANDLE(rtrigger) + +DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_left) +DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_right) +DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_up) +DEFINE_GAMEPAD_BUTTON_HANDLE(dpad_down) + +DEFINE_GAMEPAD_BUTTON_HANDLE(back) +DEFINE_GAMEPAD_BUTTON_HANDLE(guide) +DEFINE_GAMEPAD_BUTTON_HANDLE(start) + +DEFINE_GAMEPAD_BUTTON_HANDLE(action_a) +DEFINE_GAMEPAD_BUTTON_HANDLE(action_b) +DEFINE_GAMEPAD_BUTTON_HANDLE(action_c) +DEFINE_GAMEPAD_BUTTON_HANDLE(action_x) +DEFINE_GAMEPAD_BUTTON_HANDLE(action_y) +DEFINE_GAMEPAD_BUTTON_HANDLE(action_z) + +//////////////////////////////////////////////////////////////////// +// Function: GamepadButton::init_gamepad_buttons +// Access: Public, Static +// Description: This is intended to be called only once, by the +// static initialization performed in config_util.cxx. +//////////////////////////////////////////////////////////////////// +void GamepadButton:: +init_gamepad_buttons() { + ButtonRegistry::ptr()->register_button(_lstick, "lstick"); + ButtonRegistry::ptr()->register_button(_rstick, "rstick"); + ButtonRegistry::ptr()->register_button(_lshoulder, "lshoulder"); + ButtonRegistry::ptr()->register_button(_rshoulder, "rshoulder"); + ButtonRegistry::ptr()->register_button(_ltrigger, "ltrigger"); + ButtonRegistry::ptr()->register_button(_rtrigger, "rtrigger"); + + ButtonRegistry::ptr()->register_button(_dpad_left, "dpad_left"); + ButtonRegistry::ptr()->register_button(_dpad_right, "dpad_right"); + ButtonRegistry::ptr()->register_button(_dpad_up, "dpad_up"); + ButtonRegistry::ptr()->register_button(_dpad_down, "dpad_down"); + + ButtonRegistry::ptr()->register_button(_back, "back"); + ButtonRegistry::ptr()->register_button(_guide, "guide"); + ButtonRegistry::ptr()->register_button(_start, "start"); + + ButtonRegistry::ptr()->register_button(_action_a, "action_a"); + ButtonRegistry::ptr()->register_button(_action_b, "action_b"); + ButtonRegistry::ptr()->register_button(_action_c, "action_c"); + ButtonRegistry::ptr()->register_button(_action_x, "action_x"); + ButtonRegistry::ptr()->register_button(_action_y, "action_y"); + ButtonRegistry::ptr()->register_button(_action_z, "action_z"); +} diff --git a/panda/src/putil/gamepadButton.h b/panda/src/putil/gamepadButton.h new file mode 100644 index 0000000000..4d6b7afa88 --- /dev/null +++ b/panda/src/putil/gamepadButton.h @@ -0,0 +1,57 @@ +// Filename: gamepadButton.h +// Created by: rdb (21Aug15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef GAMEPADBUTTON_H +#define GAMEPADBUTTON_H + +#include "pandabase.h" + +#include "buttonHandle.h" + +//////////////////////////////////////////////////////////////////// +// Class : GamepadButton +// Description : This class is just used as a convenient namespace for +// grouping all of these handy functions that return +// buttons which map to gamepad buttons. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_PUTIL GamepadButton { +PUBLISHED: + static ButtonHandle lstick(); + static ButtonHandle rstick(); + static ButtonHandle lshoulder(); + static ButtonHandle rshoulder(); + static ButtonHandle ltrigger(); + static ButtonHandle rtrigger(); + + static ButtonHandle dpad_left(); + static ButtonHandle dpad_right(); + static ButtonHandle dpad_up(); + static ButtonHandle dpad_down(); + + static ButtonHandle back(); + static ButtonHandle guide(); + static ButtonHandle start(); + + static ButtonHandle action_a(); + static ButtonHandle action_b(); + static ButtonHandle action_c(); + static ButtonHandle action_x(); + static ButtonHandle action_y(); + static ButtonHandle action_z(); + +public: + static void init_gamepad_buttons(); +}; + +#endif diff --git a/panda/src/putil/p3putil_composite1.cxx b/panda/src/putil/p3putil_composite1.cxx index 3fd7673773..294f465629 100644 --- a/panda/src/putil/p3putil_composite1.cxx +++ b/panda/src/putil/p3putil_composite1.cxx @@ -28,4 +28,3 @@ #include "factoryBase.cxx" #include "factoryParam.cxx" #include "factoryParams.cxx" -#include "globalPointerRegistry.cxx" diff --git a/panda/src/putil/p3putil_composite2.cxx b/panda/src/putil/p3putil_composite2.cxx index a4ce5c9cfc..9b0f01d851 100644 --- a/panda/src/putil/p3putil_composite2.cxx +++ b/panda/src/putil/p3putil_composite2.cxx @@ -1,3 +1,5 @@ +#include "gamepadButton.cxx" +#include "globalPointerRegistry.cxx" #include "ioPtaDatagramFloat.cxx" #include "ioPtaDatagramInt.cxx" #include "ioPtaDatagramShort.cxx" diff --git a/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm b/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm index 876de6450d..f14641becf 100644 --- a/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm +++ b/panda/src/tinydisplay/tinyOsxGraphicsWindow.mm @@ -419,7 +419,7 @@ OSStatus TinyOsxGraphicsWindow::handleTextInput (EventHandlerCallRef myHandler, } for (unsigned int x = 0; x < actualSize/sizeof(UniChar); ++x) { - _input_devices[0].keystroke(text[x]); + _input_devices[0]->keystroke(text[x]); } DisposePtr((char *)text); } @@ -492,10 +492,10 @@ TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(GraphicsEngine *engine, GraphicsPip _current_icon(NULL), _ID(id_seed++), _originalMode(NULL) { - GraphicsWindowInputDevice device = + PT(InputDevice) device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse"); _input_devices.push_back(device); - _input_devices[0].set_pointer_in_window(0, 0); + device->set_pointer_in_window(0, 0); _last_key_modifiers = 0; _last_buttons = 0; @@ -579,7 +579,7 @@ bool TinyOsxGraphicsWindow::set_icon_filename(const Filename &icon_filename) { //////////////////////////////////////////////////////////////////// void TinyOsxGraphicsWindow:: set_pointer_in_window(int x, int y) { - _input_devices[0].set_pointer_in_window(x, y); + _input_devices[0]->set_pointer_in_window(x, y); if (_cursor_hidden != _display_hide_cursor) { if (_cursor_hidden) { @@ -600,7 +600,7 @@ set_pointer_in_window(int x, int y) { //////////////////////////////////////////////////////////////////// void TinyOsxGraphicsWindow:: set_pointer_out_of_window() { - _input_devices[0].set_pointer_out_of_window(); + _input_devices[0]->set_pointer_out_of_window(); if (_display_hide_cursor) { CGDisplayShowCursor(kCGDirectMainDisplay); @@ -1333,13 +1333,13 @@ void TinyOsxGraphicsWindow::SystemPointToLocalPoint(Point &qdGlobalPoint) { _wheel_delta += this_wheel_delta; SInt32 wheel_scale = osx_mouse_wheel_scale; while (_wheel_delta > wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_up()); - _input_devices[0].button_up(MouseButton::wheel_up()); + _input_devices[0]->button_down(MouseButton::wheel_up()); + _input_devices[0]->button_up(MouseButton::wheel_up()); _wheel_delta -= wheel_scale; } while (_wheel_delta < -wheel_scale) { - _input_devices[0].button_down(MouseButton::wheel_down()); - _input_devices[0].button_up(MouseButton::wheel_down()); + _input_devices[0]->button_down(MouseButton::wheel_down()); + _input_devices[0]->button_up(MouseButton::wheel_down()); _wheel_delta += wheel_scale; } } @@ -1519,25 +1519,25 @@ HandleButtonDelta(UInt32 new_buttons) { if (changed & 0x01) { if (new_buttons & 0x01) { - _input_devices[0].button_down(MouseButton::one()); + _input_devices[0]->button_down(MouseButton::one()); } else { - _input_devices[0].button_up(MouseButton::one()); + _input_devices[0]->button_up(MouseButton::one()); } } if (changed & 0x04) { if (new_buttons & 0x04) { - _input_devices[0].button_down(MouseButton::two()); + _input_devices[0]->button_down(MouseButton::two()); } else { - _input_devices[0].button_up(MouseButton::two()); + _input_devices[0]->button_up(MouseButton::two()); } } if (changed & 0x02) { if (new_buttons & 0x02) { - _input_devices[0].button_down(MouseButton::three()); + _input_devices[0]->button_down(MouseButton::three()); } else { - _input_devices[0].button_up(MouseButton::three()); + _input_devices[0]->button_up(MouseButton::three()); } } @@ -1745,7 +1745,7 @@ void TinyOsxGraphicsWindow::set_properties_now(WindowProperties &properties) { if (properties.has_cursor_hidden()) { _properties.set_cursor_hidden(properties.get_cursor_hidden()); _cursor_hidden = properties.get_cursor_hidden(); - if (_cursor_hidden && _input_devices[0].has_pointer()) { + if (_cursor_hidden && _input_devices[0]->has_pointer()) { if (!_display_hide_cursor) { CGDisplayHideCursor(kCGDirectMainDisplay); _display_hide_cursor = true; diff --git a/panda/src/tinydisplay/tinySDLGraphicsWindow.cxx b/panda/src/tinydisplay/tinySDLGraphicsWindow.cxx index 47631c6321..2da9337c1f 100644 --- a/panda/src/tinydisplay/tinySDLGraphicsWindow.cxx +++ b/panda/src/tinydisplay/tinySDLGraphicsWindow.cxx @@ -46,9 +46,7 @@ TinySDLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _pitch = 0; update_pixel_factor(); - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"); - add_input_device(device); + add_input_device(GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse")); } //////////////////////////////////////////////////////////////////// @@ -184,35 +182,35 @@ process_events() { switch(evt.type) { case SDL_KEYDOWN: if (evt.key.keysym.unicode) { - _input_devices[0].keystroke(evt.key.keysym.unicode); + _input_devices[0]->keystroke(evt.key.keysym.unicode); } button = get_keyboard_button(evt.key.keysym.sym); if (button != ButtonHandle::none()) { - _input_devices[0].button_down(button); + _input_devices[0]->button_down(button); } break; case SDL_KEYUP: button = get_keyboard_button(evt.key.keysym.sym); if (button != ButtonHandle::none()) { - _input_devices[0].button_up(button); + _input_devices[0]->button_up(button); } break; case SDL_MOUSEBUTTONDOWN: button = get_mouse_button(evt.button.button); - _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y); - _input_devices[0].button_down(button); + _input_devices[0]->set_pointer_in_window(evt.button.x, evt.button.y); + _input_devices[0]->button_down(button); break; case SDL_MOUSEBUTTONUP: button = get_mouse_button(evt.button.button); - _input_devices[0].set_pointer_in_window(evt.button.x, evt.button.y); - _input_devices[0].button_up(button); + _input_devices[0]->set_pointer_in_window(evt.button.x, evt.button.y); + _input_devices[0]->button_up(button); break; case SDL_MOUSEMOTION: - _input_devices[0].set_pointer_in_window(evt.motion.x, evt.motion.y); + _input_devices[0]->set_pointer_in_window(evt.motion.x, evt.motion.y); break; case SDL_VIDEORESIZE: diff --git a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx index 924ababedb..0b6cf0b48e 100644 --- a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx +++ b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx @@ -215,9 +215,7 @@ process_events() { if (_xwindow == (X11_Window)0) { return; } - - poll_raw_mice(); - + XEvent event; XKeyEvent keyrelease_event; bool got_keyrelease_event = false; @@ -294,18 +292,18 @@ process_events() { case ButtonPress: // This refers to the mouse buttons. button = get_mouse_button(event.xbutton); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); - _input_devices[0].button_down(button); + _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y); + _input->button_down(button); break; case ButtonRelease: button = get_mouse_button(event.xbutton); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); - _input_devices[0].button_up(button); + _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y); + _input->button_up(button); break; case MotionNotify: - _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y); + _input->set_pointer_in_window(event.xmotion.x, event.xmotion.y); break; case KeyPress: @@ -322,11 +320,11 @@ process_events() { break; case EnterNotify: - _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y); + _input->set_pointer_in_window(event.xcrossing.x, event.xcrossing.y); break; case LeaveNotify: - _input_devices[0].set_pointer_out_of_window(); + _input->set_pointer_out_of_window(); break; case FocusIn: @@ -335,7 +333,7 @@ process_events() { break; case FocusOut: - _input_devices[0].focus_lost(); + _input->focus_lost(); properties.set_foreground(false); system_changed_properties(properties); break; diff --git a/panda/src/vrpn/vrpnAnalog.cxx b/panda/src/vrpn/vrpnAnalog.cxx index 40e55796a4..377574b6fe 100644 --- a/panda/src/vrpn/vrpnAnalog.cxx +++ b/panda/src/vrpn/vrpnAnalog.cxx @@ -115,7 +115,6 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) { Devices::iterator di; for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { VrpnAnalogDevice *device = (*di); - device->acquire(); for (int i = 0; i < info.num_channel; i++) { if (vrpn_cat.is_debug()) { if (device->get_control_state(i) != info.channel[i]) { @@ -125,6 +124,5 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) { } device->set_control_state(i, info.channel[i]); } - device->unlock(); } } diff --git a/panda/src/vrpn/vrpnButton.cxx b/panda/src/vrpn/vrpnButton.cxx index 444fea8708..d6bca1cf4b 100644 --- a/panda/src/vrpn/vrpnButton.cxx +++ b/panda/src/vrpn/vrpnButton.cxx @@ -119,8 +119,6 @@ vrpn_button_callback(void *userdata, const vrpn_BUTTONCB info) { Devices::iterator di; for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { VrpnButtonDevice *device = (*di); - device->acquire(); device->set_button_state(info.button, info.state != 0); - device->unlock(); } } diff --git a/panda/src/vrpn/vrpnDial.cxx b/panda/src/vrpn/vrpnDial.cxx index 34d4ae549a..0c958d98ab 100644 --- a/panda/src/vrpn/vrpnDial.cxx +++ b/panda/src/vrpn/vrpnDial.cxx @@ -120,8 +120,6 @@ vrpn_dial_callback(void *userdata, const vrpn_DIALCB info) { Devices::iterator di; for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { VrpnDialDevice *device = (*di); - device->acquire(); device->push_dial(info.dial, info.change); - device->unlock(); } } diff --git a/panda/src/vrpn/vrpnTracker.cxx b/panda/src/vrpn/vrpnTracker.cxx index c99e95b513..37cc8c03b8 100644 --- a/panda/src/vrpn/vrpnTracker.cxx +++ b/panda/src/vrpn/vrpnTracker.cxx @@ -123,11 +123,10 @@ vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info) { VrpnTrackerDevice *device = (*di); if (device->get_sensor() == info.sensor && device->get_data_type() == VrpnTrackerDevice::DT_position) { - device->acquire(); - device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); - device->_data.set_pos(LPoint3(info.pos[0], info.pos[1], info.pos[2])); - device->_data.set_orient(LOrientation(info.quat[3], info.quat[0], info.quat[1], info.quat[2])); - device->unlock(); + device->set_tracker(LPoint3(info.pos[0], info.pos[1], info.pos[2]), + LOrientation(info.quat[3], info.quat[0], + info.quat[1], info.quat[2]), + VrpnClient::convert_to_secs(info.msg_time)); } } } @@ -152,13 +151,10 @@ vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info) { VrpnTrackerDevice *device = (*di); if (device->get_sensor() == info.sensor && device->get_data_type() == VrpnTrackerDevice::DT_velocity) { - device->acquire(); - device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); - device->_data.set_pos(LPoint3(info.vel[0], info.vel[1], info.vel[2])); - device->_data.set_orient(LOrientation(info.vel_quat[3], info.vel_quat[0], - info.vel_quat[1], info.vel_quat[2])); - device->_data.set_dt(info.vel_quat_dt); - device->unlock(); + device->set_tracker(LPoint3(info.vel[0], info.vel[1], info.vel[2]), + LOrientation(info.vel_quat[3], info.vel_quat[0], + info.vel_quat[1], info.vel_quat[2]), + VrpnClient::convert_to_secs(info.msg_time)); } } } @@ -183,13 +179,10 @@ vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info) { VrpnTrackerDevice *device = (*di); if (device->get_sensor() == info.sensor && device->get_data_type() == VrpnTrackerDevice::DT_acceleration) { - device->acquire(); - device->_data.set_time(VrpnClient::convert_to_secs(info.msg_time)); - device->_data.set_pos(LPoint3(info.acc[0], info.acc[1], info.acc[2])); - device->_data.set_orient(LOrientation(info.acc_quat[3], info.acc_quat[0], - info.acc_quat[1], info.acc_quat[2])); - device->_data.set_dt(info.acc_quat_dt); - device->unlock(); + device->set_tracker(LPoint3(info.acc[0], info.acc[1], info.acc[2]), + LOrientation(info.acc_quat[3], info.acc_quat[0], + info.acc_quat[1], info.acc_quat[2]), + VrpnClient::convert_to_secs(info.msg_time)); } } } diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index f270a70f61..4e04206426 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -2786,9 +2786,9 @@ handle_raw_input(HRAWINPUT hraw) { if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { _input_devices[i].set_pointer_in_window(adjx, adjy); } else { - int oldx = _input_devices[i].get_raw_pointer().get_x(); - int oldy = _input_devices[i].get_raw_pointer().get_y(); - _input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy); + //int oldx = _input_devices[i].get_raw_pointer().get_x(); + //int oldy = _input_devices[i].get_raw_pointer().get_y(); + //_input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy); } if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) { diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 326953d0c4..8e9f6252bb 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -28,14 +28,10 @@ #include "nativeWindowHandle.h" #include "virtualFileSystem.h" #include "get_x11.h" +#include "evdevInputDevice.h" -#include -#include #include - -#ifdef PHAVE_LINUX_INPUT_H -#include -#endif +#include #ifdef HAVE_XCURSOR static int xcursor_read(XcursorFile *file, unsigned char *buf, int len) { @@ -69,8 +65,6 @@ static int xcursor_seek(XcursorFile *file, long offset, int whence) { TypeHandle x11GraphicsWindow::_type_handle; -#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7))) - //////////////////////////////////////////////////////////////////// // Function: x11GraphicsWindow::Constructor // Access: Public @@ -107,9 +101,9 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _override_redirect = False; _wm_delete_window = x11_pipe->_wm_delete_window; - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"); + PT(GraphicsWindowInputDevice) device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"); add_input_device(device); + _input = device; } //////////////////////////////////////////////////////////////////// @@ -143,26 +137,26 @@ move_pointer(int device, int x, int y) { if (device == 0) { // Move the system mouse pointer. if (!_properties.get_foreground() || - !_input_devices[0].get_pointer().get_in_window()) { + !_input->get_pointer().get_in_window()) { // If the window doesn't have input focus, or the mouse isn't // currently within the window, forget it. return false; } - const MouseData &md = _input_devices[0].get_pointer(); + const MouseData &md = _input->get_pointer(); if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) { if (!_dga_mouse_enabled) { XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y); } - _input_devices[0].set_pointer_in_window(x, y); + _input->set_pointer_in_window(x, y); } return true; } else { // Move a raw mouse. - if ((device < 1)||(device >= _input_devices.size())) { + if (device < 1 || device >= _input_devices.size()) { return false; } - _input_devices[device].set_pointer_in_window(x, y); + //_input_devices[device]->set_pointer_in_window(x, y); return true; } } @@ -249,8 +243,6 @@ process_events() { return; } - poll_raw_mice(); - XEvent event; XKeyEvent keyrelease_event; bool got_keyrelease_event = false; @@ -311,25 +303,25 @@ process_events() { // This refers to the mouse buttons. button = get_mouse_button(event.xbutton); if (!_dga_mouse_enabled) { - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); + _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y); } - _input_devices[0].button_down(button); + _input->button_down(button); break; case ButtonRelease: button = get_mouse_button(event.xbutton); if (!_dga_mouse_enabled) { - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); + _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y); } - _input_devices[0].button_up(button); + _input->button_up(button); break; case MotionNotify: if (_dga_mouse_enabled) { - const MouseData &md = _input_devices[0].get_raw_pointer(); - _input_devices[0].set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root); + const MouseData &md = _input->get_pointer(); + _input->set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root); } else { - _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y); + _input->set_pointer_in_window(event.xmotion.x, event.xmotion.y); } break; @@ -348,15 +340,15 @@ process_events() { case EnterNotify: if (_dga_mouse_enabled) { - const MouseData &md = _input_devices[0].get_raw_pointer(); - _input_devices[0].set_pointer_in_window(md.get_x(), md.get_y()); + const MouseData &md = _input->get_pointer(); + _input->set_pointer_in_window(md.get_x(), md.get_y()); } else { - _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y); + _input->set_pointer_in_window(event.xcrossing.x, event.xcrossing.y); } break; case LeaveNotify: - _input_devices[0].set_pointer_out_of_window(); + _input->set_pointer_out_of_window(); break; case FocusIn: @@ -365,7 +357,7 @@ process_events() { break; case FocusOut: - _input_devices[0].focus_lost(); + _input->focus_lost(); properties.set_foreground(false); changed_properties = true; break; @@ -751,7 +743,7 @@ set_properties_now(WindowProperties &properties) { XQueryPointer(_display, _xwindow, &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); + _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y); } } else { x11display_cat.info() << "XF86DGA extension not available\n"; @@ -1295,66 +1287,43 @@ open_raw_mice() { bool any_mice = false; for (int i=0; i<64; i++) { - uint8_t evtypes[EV_MAX/8 + 1]; ostringstream fnb; fnb << "/dev/input/event" << i; string fn = fnb.str(); int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0); if (fd >= 0) { - any_present = true; - char name[256]; - char phys[256]; - char uniq[256]; - if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)|| - (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)|| - (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)|| - (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) { - close(fd); - x11display_cat.error() << - "Opening raw mice: ioctl failed on " << fn << "\n"; - } else { - if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) { - for (char *p=name; *p; p++) { - if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { - *p = '_'; - } - } - for (char *p=uniq; *p; p++) { - if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) { - *p = '_'; - } - } - string full_id = ((string)name) + "." + uniq; - MouseDeviceInfo inf; - inf._fd = fd; - inf._input_device_index = _input_devices.size(); - inf._io_buffer = ""; - _mouse_device_info.push_back(inf); - GraphicsWindowInputDevice device = - GraphicsWindowInputDevice::pointer_only(this, full_id); - add_input_device(device); - x11display_cat.info() << "Raw mouse " << - inf._input_device_index << " detected: " << full_id << "\n"; - any_mice = true; - } else { - close(fd); - } + EvdevInputDevice *device = new EvdevInputDevice(fd); + nassertd(device != NULL) continue; + + if (device->has_pointer()) { + add_input_device(device); + + x11display_cat.info() + << "Raw mouse " << _input_devices.size() + << " detected: " << device->get_name() << "\n"; + + any_mice = true; + any_present = true; } } else { - if ((errno == ENOENT)||(errno == ENOTDIR)) { + if (errno == ENOENT || errno == ENOTDIR) { break; } else { any_present = true; - x11display_cat.error() << - "Opening raw mice: " << strerror(errno) << " " << fn << "\n"; + x11display_cat.error() + << "Opening raw mice: " << strerror(errno) << " " << fn << "\n"; } } } - if (!any_present) { + if (any_mice) { + _properties.set_raw_mice(true); + + } else if (!any_present) { x11display_cat.error() << "Opening raw mice: files not found: /dev/input/event*\n"; - } else if (!any_mice) { + + } else { x11display_cat.error() << "Opening raw mice: no mouse devices detected in /dev/input/event*\n"; } @@ -1364,69 +1333,6 @@ open_raw_mice() { #endif } -//////////////////////////////////////////////////////////////////// -// Function: x11GraphicsWindow::poll_raw_mice -// Access: Private -// Description: Reads events from the raw mouse device files. -//////////////////////////////////////////////////////////////////// -void x11GraphicsWindow:: -poll_raw_mice() { -#ifdef PHAVE_LINUX_INPUT_H - for (int di = 0; di < _mouse_device_info.size(); ++di) { - MouseDeviceInfo &inf = _mouse_device_info[di]; - - // Read all bytes into buffer. - if (inf._fd >= 0) { - while (1) { - char tbuf[1024]; - int nread = read(inf._fd, tbuf, sizeof(tbuf)); - if (nread > 0) { - inf._io_buffer += string(tbuf, nread); - } else { - if ((nread < 0) && ((errno == EWOULDBLOCK) || (errno==EAGAIN))) { - break; - } - close(inf._fd); - inf._fd = -1; - break; - } - } - } - - // Process events. - int nevents = inf._io_buffer.size() / sizeof(struct input_event); - if (nevents == 0) { - continue; - } - const input_event *events = (const input_event *)(inf._io_buffer.c_str()); - GraphicsWindowInputDevice &dev = _input_devices[inf._input_device_index]; - int x = dev.get_raw_pointer().get_x(); - int y = dev.get_raw_pointer().get_y(); - for (int i = 0; i < nevents; i++) { - if (events[i].type == EV_REL) { - if (events[i].code == REL_X) x += events[i].value; - if (events[i].code == REL_Y) y += events[i].value; - } else if (events[i].type == EV_ABS) { - if (events[i].code == ABS_X) x = events[i].value; - if (events[i].code == ABS_Y) y = events[i].value; - } else if (events[i].type == EV_KEY) { - if ((events[i].code >= BTN_MOUSE) && (events[i].code < BTN_MOUSE + 8)) { - int btn = events[i].code - BTN_MOUSE; - dev.set_pointer_in_window(x, y); - if (events[i].value) { - dev.button_down(MouseButton::button(btn)); - } else { - dev.button_up(MouseButton::button(btn)); - } - } - } - } - inf._io_buffer.erase(0, nevents * sizeof(struct input_event)); - dev.set_pointer_in_window(x, y); - } -#endif -} - //////////////////////////////////////////////////////////////////// // Function: x11GraphicsWindow::handle_keystroke // Access: Private @@ -1436,7 +1342,7 @@ poll_raw_mice() { void x11GraphicsWindow:: handle_keystroke(XKeyEvent &event) { if (!_dga_mouse_enabled) { - _input_devices[0].set_pointer_in_window(event.x, event.y); + _input->set_pointer_in_window(event.x, event.y); } if (_ic) { @@ -1454,14 +1360,14 @@ handle_keystroke(XKeyEvent &event) { // Now each of the returned wide characters represents a // keystroke. for (int i = 0; i < len; i++) { - _input_devices[0].keystroke(buffer[i]); + _input->keystroke(buffer[i]); } } else { // Without an input context, just get the ascii keypress. ButtonHandle button = get_button(event, true); if (button.has_ascii_equivalent()) { - _input_devices[0].keystroke(button.get_ascii_equivalent()); + _input->keystroke(button.get_ascii_equivalent()); } } } @@ -1475,30 +1381,32 @@ handle_keystroke(XKeyEvent &event) { void x11GraphicsWindow:: handle_keypress(XKeyEvent &event) { if (!_dga_mouse_enabled) { - _input_devices[0].set_pointer_in_window(event.x, event.y); + _input->set_pointer_in_window(event.x, event.y); } // Now get the raw unshifted button. ButtonHandle button = get_button(event, false); if (button != ButtonHandle::none()) { if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) { - _input_devices[0].button_down(KeyboardButton::control()); + _input->button_down(KeyboardButton::control()); } if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) { - _input_devices[0].button_down(KeyboardButton::shift()); + _input->button_down(KeyboardButton::shift()); } if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) { - _input_devices[0].button_down(KeyboardButton::alt()); + _input->button_down(KeyboardButton::alt()); } if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) { - _input_devices[0].button_down(KeyboardButton::meta()); + _input->button_down(KeyboardButton::meta()); } - _input_devices[0].button_down(button); + _input->button_down(button); } - ButtonHandle raw_button = map_raw_button(event.keycode); - if (raw_button != ButtonHandle::none()) { - _input_devices[0].raw_button_down(raw_button); + if (event.keycode >= 9 && event.keycode <= 135) { + ButtonHandle raw_button = map_raw_button(event.keycode); + if (raw_button != ButtonHandle::none()) { + _input->raw_button_down(raw_button); + } } } @@ -1511,30 +1419,32 @@ handle_keypress(XKeyEvent &event) { void x11GraphicsWindow:: handle_keyrelease(XKeyEvent &event) { if (!_dga_mouse_enabled) { - _input_devices[0].set_pointer_in_window(event.x, event.y); + _input->set_pointer_in_window(event.x, event.y); } // Now get the raw unshifted button. ButtonHandle button = get_button(event, false); if (button != ButtonHandle::none()) { if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) { - _input_devices[0].button_up(KeyboardButton::control()); + _input->button_up(KeyboardButton::control()); } if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) { - _input_devices[0].button_up(KeyboardButton::shift()); + _input->button_up(KeyboardButton::shift()); } if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) { - _input_devices[0].button_up(KeyboardButton::alt()); + _input->button_up(KeyboardButton::alt()); } if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) { - _input_devices[0].button_up(KeyboardButton::meta()); + _input->button_up(KeyboardButton::meta()); } - _input_devices[0].button_up(button); + _input->button_up(button); } - ButtonHandle raw_button = map_raw_button(event.keycode); - if (raw_button != ButtonHandle::none()) { - _input_devices[0].raw_button_up(raw_button); + if (event.keycode >= 9 && event.keycode <= 135) { + ButtonHandle raw_button = map_raw_button(event.keycode); + if (raw_button != ButtonHandle::none()) { + _input->raw_button_up(raw_button); + } } } @@ -1617,7 +1527,7 @@ get_button(XKeyEvent &key_event, bool allow_shift) { // can do this in just the ASCII set, because we handle // international keyboards elsewhere (via an input context). if ((key_event.state & (ShiftMask | LockMask)) != 0) { - if (key >= XK_a and key <= XK_z) { + if (key >= XK_a && key <= XK_z) { key += (XK_A - XK_a); } } @@ -1962,117 +1872,16 @@ map_button(KeySym key) const { //////////////////////////////////////////////////////////////////// ButtonHandle x11GraphicsWindow:: map_raw_button(KeyCode key) const { - 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(); +#ifdef PHAVE_LINUX_INPUT_H + // Most X11 servers are configured to use the evdev driver, which + // adds 8 to the underlying evdev keycodes (not sure why). + // In any case, this means we can use the same mapping as our raw + // input code, which uses evdev directly. + int index = key - 8; + if (index >= 0) { + return EvdevInputDevice::map_button(index); } +#endif return ButtonHandle::none(); } diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index 5bcb8de0db..d279ecd443 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -74,7 +74,6 @@ protected: static Bool check_event(X11_Display *display, XEvent *event, char *arg); void open_raw_mice(); - void poll_raw_mice(); private: X11_Cursor get_cursor(const Filename &filename); @@ -89,6 +88,7 @@ protected: Colormap _colormap; XIC _ic; XVisualInfo *_visual_info; + GraphicsWindowInputDevice *_input; bool _have_xrandr; #ifdef HAVE_XRANDR