panda3d/panda/src/device/inputDevice.cxx
2015-12-19 20:09:07 +01:00

539 lines
16 KiB
C++

// 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),
_vendor_id(0),
_product_id(0),
_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 &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: InputDevice::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void InputDevice::
operator = (const InputDevice &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// 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());
}
if (device_cat.is_spam()) {
device_cat.spam()
<< "Changed control " << index;
if (_controls[index]._axis != C_none) {
device_cat.spam(false) << " (" << _controls[index]._axis << ")";
}
device_cat.spam(false) << " to " << state << "\n";
}
_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() << " button";
if (_buttons.size() != 1) {
out.put('s');
}
}
if (_controls.size() > 0) {
out << ", " << _controls.size() << " control";
if (_controls.size() != 1) {
out.put('s');
}
}
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; ++i) {
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_set_vibration
// Access: Private, Virtual
// Description: Sets the vibration strength. The first argument
// controls a low-frequency motor, if present, and
// the latter controls a high-frequency motor. The
// values are within the 0-1 range.
////////////////////////////////////////////////////////////////////
void InputDevice::
do_set_vibration(double strong, double weak) {
}
////////////////////////////////////////////////////////////////////
// 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;
}