/** * 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." * * @file inputDevice.h * @author rdb * @date 2015-12-11 */ #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; /** * 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 motion 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 of 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 { // It is not known what type of device this is. 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, DC_dance_pad, // Head-mounted display. DC_hmd, // Count of this enum, used for loops DC_COUNT, }; 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, C_rudder, C_hat_x, C_hat_y, // Steering wheel / pedals C_wheel, C_accelerator, C_brake, }; INLINE string get_name() const; INLINE string get_manufacturer() const; INLINE unsigned short get_vendor_id() const; INLINE unsigned short get_product_id() 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); // The device's manufacturer, or the empty string if not known. MAKE_PROPERTY(manufacturer, get_manufacturer); // USB vendor ID of the device, or 0 if not known. MAKE_PROPERTY(vendor_id, get_vendor_id); // USB product ID of the device, or 0 if not known. MAKE_PROPERTY(product_id, get_product_id); // 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 size_t get_num_buttons() const; INLINE void set_button_map(size_t index, ButtonHandle button); INLINE ButtonHandle get_button_map(size_t index) const; INLINE bool get_button_state(size_t index) const; INLINE bool is_button_known(size_t index) const; INLINE size_t get_num_controls() const; INLINE void set_control_map(size_t index, ControlAxis axis); INLINE ControlAxis get_control_map(size_t index) const; INLINE double get_control_state(size_t index) const; INLINE bool is_control_known(size_t index) const; INLINE void set_vibration(double strong, double weak); 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_set_vibration(double low, double high); 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; string _serial_number; string _manufacturer; DeviceClass _device_class; int _flags; int _event_sequence; unsigned short _vendor_id; unsigned short _product_id; bool _is_connected; bool _enable_pointer_events; PointerData _pointer_data; PT(ButtonEventList) _button_events; PT(PointerEventList) _pointer_events; PUBLISHED: enum State { S_unknown, S_up, S_down }; class ButtonState { public: INLINE ButtonState(); INLINE ButtonState(ButtonHandle handle); PUBLISHED: ButtonHandle handle; State state; }; typedef pvector Buttons; Buttons _buttons; class AnalogState { public: INLINE AnalogState(); PUBLISHED: ControlAxis axis; double state; bool known; }; typedef pvector Controls; Controls _controls; short _battery_level; short _max_battery_level; TrackerData _tracker_data; INLINE ButtonState get_button(size_t index) const; INLINE ButtonState find_button(ButtonHandle handle) const; INLINE AnalogState get_control(size_t index) const; INLINE AnalogState find_control(ControlAxis axis) const; // Make device buttons and controls iterable MAKE_SEQ_PROPERTY(buttons, get_num_buttons, get_button); MAKE_SEQ_PROPERTY(controls, get_num_controls, get_control); 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; } EXPCL_PANDA_DEVICE ostream &operator << (ostream &out, InputDevice::DeviceClass dc); EXPCL_PANDA_DEVICE ostream &operator << (ostream &out, InputDevice::ControlAxis axis); #include "inputDevice.I" #endif