778 lines
24 KiB
C++
778 lines
24 KiB
C++
/**
|
|
* 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 ioKitInputDevice.cxx
|
|
* @author rdb
|
|
* @date 2017-12-21
|
|
*/
|
|
|
|
#include "ioKitInputDevice.h"
|
|
|
|
#if defined(__APPLE__) && !defined(CPPPARSER)
|
|
|
|
#include <IOKit/hid/IOHIDLib.h>
|
|
#include <IOKit/hid/IOHIDElement.h>
|
|
|
|
#include "inputDeviceManager.h"
|
|
#include "keyboardButton.h"
|
|
#include "gamepadButton.h"
|
|
#include "mouseButton.h"
|
|
|
|
/**
|
|
* Protected constructor.
|
|
*/
|
|
IOKitInputDevice::
|
|
IOKitInputDevice(IOHIDDeviceRef device) :
|
|
_device(device),
|
|
_hat_element(nullptr),
|
|
_pointer_x(nullptr),
|
|
_pointer_y(nullptr),
|
|
_scroll_wheel(nullptr),
|
|
_pointer_x_timestamp(0),
|
|
_pointer_y_timestamp(0),
|
|
_scroll_wheel_timestamp(0) {
|
|
nassertv(device);
|
|
|
|
char buffer[4096];
|
|
|
|
CFStringRef name = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
|
if (name) {
|
|
buffer[0] = 0;
|
|
CFStringGetCString(name, buffer, sizeof(buffer), kCFStringEncodingUTF8);
|
|
|
|
// Strip trailing spaces.
|
|
size_t len = strlen(buffer);
|
|
while (isspace(buffer[len - 1])) {
|
|
--len;
|
|
}
|
|
_name.assign(buffer, len);
|
|
}
|
|
|
|
CFStringRef mfg = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
|
|
if (mfg) {
|
|
CFStringGetCString(mfg, buffer, sizeof(buffer), kCFStringEncodingUTF8);
|
|
_manufacturer = buffer;
|
|
}
|
|
|
|
CFStringRef serial = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDSerialNumberKey));
|
|
if (serial) {
|
|
CFStringGetCString(serial, buffer, sizeof(buffer), kCFStringEncodingUTF8);
|
|
_serial_number = buffer;
|
|
}
|
|
|
|
CFNumberRef vendor = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
|
|
if (vendor) {
|
|
int32_t value = 0;
|
|
CFNumberGetValue(vendor, kCFNumberSInt32Type, &value);
|
|
_vendor_id = (unsigned short)value;
|
|
}
|
|
|
|
CFNumberRef product = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
|
|
if (product) {
|
|
int32_t value = 0;
|
|
CFNumberGetValue(product, kCFNumberSInt32Type, &value);
|
|
_product_id = (unsigned short)value;
|
|
}
|
|
|
|
if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse)) {
|
|
_device_class = DeviceClass::MOUSE;
|
|
}
|
|
else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard)) {
|
|
_device_class = DeviceClass::KEYBOARD;
|
|
}
|
|
else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad)) {
|
|
_device_class = DeviceClass::GAMEPAD;
|
|
}
|
|
else if (IOHIDDeviceConformsTo(device, kHIDPage_Simulation, kHIDUsage_Sim_FlightStick)) {
|
|
_device_class = DeviceClass::FLIGHT_STICK;
|
|
}
|
|
else if (IOHIDDeviceConformsTo(device, kHIDPage_Simulation, kHIDUsage_GD_Joystick)) {
|
|
_device_class = DeviceClass::FLIGHT_STICK;
|
|
}
|
|
else if (_vendor_id == 0x044f && _product_id == 0xb108) {
|
|
// T.Flight Hotas X
|
|
_device_class = DeviceClass::FLIGHT_STICK;
|
|
}
|
|
else if (_vendor_id == 0x046d &&
|
|
(_product_id == 0xc623 ||
|
|
_product_id == 0xc625 ||
|
|
_product_id == 0xc626 ||
|
|
_product_id == 0xc627 ||
|
|
_product_id == 0xc628 ||
|
|
_product_id == 0xc629 ||
|
|
_product_id == 0xc62b)) {
|
|
// 3Dconnexion SpaceNavigator and friends.
|
|
_device_class = DeviceClass::SPATIAL_MOUSE;
|
|
}
|
|
else if (_name == "usb gamepad") {
|
|
_device_class = DeviceClass::GAMEPAD;
|
|
}
|
|
|
|
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, nullptr, 0);
|
|
if (elements) {
|
|
CFIndex count = CFArrayGetCount(elements);
|
|
for (CFIndex i = 0; i < count; ++i) {
|
|
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
parse_element(element);
|
|
}
|
|
CFRelease(elements);
|
|
}
|
|
|
|
if (_hat_element != nullptr) {
|
|
_hat_left_button = (int)_buttons.size();
|
|
_buttons.push_back(ButtonState(GamepadButton::hat_left()));
|
|
_buttons.push_back(ButtonState(GamepadButton::hat_right()));
|
|
_buttons.push_back(ButtonState(GamepadButton::hat_down()));
|
|
_buttons.push_back(ButtonState(GamepadButton::hat_up()));
|
|
}
|
|
|
|
if (_pointer_x != nullptr && _pointer_y != nullptr) {
|
|
enable_feature(Feature::POINTER);
|
|
add_pointer(PointerType::UNKNOWN, 0);
|
|
}
|
|
|
|
_is_connected = true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
IOKitInputDevice::
|
|
~IOKitInputDevice() {
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
void IOKitInputDevice::
|
|
parse_element(IOHIDElementRef element) {
|
|
ButtonHandle handle = ButtonHandle::none();
|
|
Axis axis = Axis::NONE;
|
|
uint32_t page = IOHIDElementGetUsagePage(element);
|
|
uint32_t usage = IOHIDElementGetUsage(element);
|
|
|
|
switch (IOHIDElementGetType(element)) {
|
|
case kIOHIDElementTypeInput_Misc:
|
|
switch (page) {
|
|
case kHIDPage_GenericDesktop:
|
|
switch (usage) {
|
|
case kHIDUsage_GD_X:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::LEFT_X;
|
|
} else if (_device_class == DeviceClass::FLIGHT_STICK) {
|
|
axis = Axis::ROLL;
|
|
} else if (_device_class == DeviceClass::MOUSE) {
|
|
_pointer_x = element;
|
|
return;
|
|
} else {
|
|
axis = Axis::X;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Y:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::LEFT_Y;
|
|
} else if (_device_class == DeviceClass::FLIGHT_STICK) {
|
|
axis = Axis::PITCH;
|
|
} else if (_device_class == DeviceClass::MOUSE) {
|
|
_pointer_y = element;
|
|
return;
|
|
} else {
|
|
axis = Axis::Y;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Z:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::LEFT_TRIGGER;
|
|
} else if (_device_class == DeviceClass::FLIGHT_STICK) {
|
|
axis = Axis::THROTTLE;
|
|
} else {
|
|
axis = Axis::Z;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Rx:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::RIGHT_X;
|
|
} else {
|
|
axis = Axis::PITCH;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Ry:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::RIGHT_Y;
|
|
} else {
|
|
axis = Axis::ROLL;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Rz:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
axis = Axis::RIGHT_TRIGGER;
|
|
} else {
|
|
axis = Axis::YAW;
|
|
}
|
|
break;
|
|
case kHIDUsage_GD_Slider:
|
|
axis = Axis::RUDDER;
|
|
break;
|
|
case kHIDUsage_GD_Dial:
|
|
break;
|
|
case kHIDUsage_GD_Wheel:
|
|
_scroll_wheel = element;
|
|
return;
|
|
case kHIDUsage_GD_Hatswitch:
|
|
_hat_element = element;
|
|
return;
|
|
case kHIDUsage_GD_DPadUp:
|
|
handle = GamepadButton::dpad_up();
|
|
break;
|
|
case kHIDUsage_GD_DPadDown:
|
|
handle = GamepadButton::dpad_down();
|
|
break;
|
|
case kHIDUsage_GD_DPadRight:
|
|
handle = GamepadButton::dpad_right();
|
|
break;
|
|
case kHIDUsage_GD_DPadLeft:
|
|
handle = GamepadButton::dpad_left();
|
|
break;
|
|
case 0xffffffffu:
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kHIDPage_Simulation:
|
|
switch (usage) {
|
|
case kHIDUsage_Sim_Rudder:
|
|
axis = Axis::RUDDER;
|
|
break;
|
|
case kHIDUsage_Sim_Throttle:
|
|
axis = Axis::THROTTLE;
|
|
break;
|
|
case kHIDUsage_Sim_Accelerator:
|
|
axis = Axis::ACCELERATOR;
|
|
break;
|
|
case kHIDUsage_Sim_Brake:
|
|
axis = Axis::BRAKE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (axis != Axis::NONE) {
|
|
int min = IOHIDElementGetLogicalMin(element);
|
|
int max = IOHIDElementGetLogicalMax(element);
|
|
if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::THROTTLE) {
|
|
// T.Flight Hotas X throttle is reversed and can go backwards.
|
|
add_axis(axis, max, min, true);
|
|
} else if (axis == Axis::YAW || axis == Axis::RUDDER || axis == Axis::LEFT_Y || axis == Axis::RIGHT_Y ||
|
|
(_device_class == DeviceClass::SPATIAL_MOUSE && (axis == Axis::Y || axis == Axis::Z || axis == Axis::ROLL))) {
|
|
// We'd like to reverse the Y axis to match the XInput behavior.
|
|
// We also reverse yaw to obey the right-hand rule.
|
|
add_axis(axis, max, min);
|
|
} else {
|
|
add_axis(axis, min, max);
|
|
}
|
|
|
|
_analog_elements.push_back(element);
|
|
}
|
|
break;
|
|
|
|
case kIOHIDElementTypeInput_Button:
|
|
switch (page) {
|
|
case kHIDPage_GenericDesktop:
|
|
switch (usage) {
|
|
case kHIDUsage_GD_DPadUp:
|
|
handle = GamepadButton::dpad_up();
|
|
break;
|
|
case kHIDUsage_GD_DPadDown:
|
|
handle = GamepadButton::dpad_down();
|
|
break;
|
|
case kHIDUsage_GD_DPadRight:
|
|
handle = GamepadButton::dpad_right();
|
|
break;
|
|
case kHIDUsage_GD_DPadLeft:
|
|
handle = GamepadButton::dpad_left();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kHIDPage_KeyboardOrKeypad:
|
|
switch (usage) {
|
|
case kHIDUsage_KeyboardA:
|
|
case kHIDUsage_KeyboardB:
|
|
case kHIDUsage_KeyboardC:
|
|
case kHIDUsage_KeyboardD:
|
|
case kHIDUsage_KeyboardE:
|
|
case kHIDUsage_KeyboardF:
|
|
case kHIDUsage_KeyboardG:
|
|
case kHIDUsage_KeyboardH:
|
|
case kHIDUsage_KeyboardI:
|
|
case kHIDUsage_KeyboardJ:
|
|
case kHIDUsage_KeyboardK:
|
|
case kHIDUsage_KeyboardL:
|
|
case kHIDUsage_KeyboardM:
|
|
case kHIDUsage_KeyboardN:
|
|
case kHIDUsage_KeyboardO:
|
|
case kHIDUsage_KeyboardP:
|
|
case kHIDUsage_KeyboardQ:
|
|
case kHIDUsage_KeyboardR:
|
|
case kHIDUsage_KeyboardS:
|
|
case kHIDUsage_KeyboardT:
|
|
case kHIDUsage_KeyboardU:
|
|
case kHIDUsage_KeyboardV:
|
|
case kHIDUsage_KeyboardW:
|
|
case kHIDUsage_KeyboardX:
|
|
case kHIDUsage_KeyboardY:
|
|
case kHIDUsage_KeyboardZ:
|
|
handle = KeyboardButton::ascii_key('a' + (usage - kHIDUsage_KeyboardA));
|
|
break;
|
|
case kHIDUsage_Keyboard1:
|
|
handle = KeyboardButton::ascii_key('1');
|
|
break;
|
|
case kHIDUsage_Keyboard2:
|
|
handle = KeyboardButton::ascii_key('2');
|
|
break;
|
|
case kHIDUsage_Keyboard3:
|
|
handle = KeyboardButton::ascii_key('3');
|
|
break;
|
|
case kHIDUsage_Keyboard4:
|
|
handle = KeyboardButton::ascii_key('4');
|
|
break;
|
|
case kHIDUsage_Keyboard5:
|
|
handle = KeyboardButton::ascii_key('5');
|
|
break;
|
|
case kHIDUsage_Keyboard6:
|
|
handle = KeyboardButton::ascii_key('6');
|
|
break;
|
|
case kHIDUsage_Keyboard7:
|
|
handle = KeyboardButton::ascii_key('7');
|
|
break;
|
|
case kHIDUsage_Keyboard8:
|
|
handle = KeyboardButton::ascii_key('8');
|
|
break;
|
|
case kHIDUsage_Keyboard9:
|
|
handle = KeyboardButton::ascii_key('9');
|
|
break;
|
|
case kHIDUsage_Keyboard0:
|
|
handle = KeyboardButton::ascii_key('0');
|
|
break;
|
|
case kHIDUsage_KeyboardReturnOrEnter:
|
|
handle = KeyboardButton::enter();
|
|
break;
|
|
case kHIDUsage_KeyboardEscape:
|
|
handle = KeyboardButton::escape();
|
|
break;
|
|
case kHIDUsage_KeyboardDeleteOrBackspace:
|
|
handle = KeyboardButton::backspace();
|
|
break;
|
|
case kHIDUsage_KeyboardTab:
|
|
handle = KeyboardButton::tab();
|
|
break;
|
|
case kHIDUsage_KeyboardSpacebar:
|
|
handle = KeyboardButton::ascii_key(' ');
|
|
break;
|
|
case kHIDUsage_KeyboardHyphen:
|
|
handle = KeyboardButton::ascii_key('-');
|
|
break;
|
|
case kHIDUsage_KeyboardEqualSign:
|
|
handle = KeyboardButton::ascii_key('=');
|
|
break;
|
|
case kHIDUsage_KeyboardOpenBracket:
|
|
handle = KeyboardButton::ascii_key('[');
|
|
break;
|
|
case kHIDUsage_KeyboardCloseBracket:
|
|
handle = KeyboardButton::ascii_key(']');
|
|
break;
|
|
case kHIDUsage_KeyboardBackslash:
|
|
handle = KeyboardButton::ascii_key('\\');
|
|
break;
|
|
case kHIDUsage_KeyboardNonUSPound:
|
|
handle = KeyboardButton::ascii_key('$');
|
|
break;
|
|
case kHIDUsage_KeyboardSemicolon:
|
|
handle = KeyboardButton::ascii_key(';');
|
|
break;
|
|
case kHIDUsage_KeyboardQuote:
|
|
handle = KeyboardButton::ascii_key('\'');
|
|
break;
|
|
case kHIDUsage_KeyboardGraveAccentAndTilde:
|
|
handle = KeyboardButton::ascii_key('`');
|
|
break;
|
|
case kHIDUsage_KeyboardComma:
|
|
handle = KeyboardButton::ascii_key(',');
|
|
break;
|
|
case kHIDUsage_KeyboardPeriod:
|
|
handle = KeyboardButton::ascii_key('.');
|
|
break;
|
|
case kHIDUsage_KeyboardSlash:
|
|
handle = KeyboardButton::ascii_key('/');
|
|
break;
|
|
case kHIDUsage_KeyboardCapsLock:
|
|
handle = KeyboardButton::caps_lock();
|
|
break;
|
|
case kHIDUsage_KeyboardF1:
|
|
handle = KeyboardButton::f1();
|
|
break;
|
|
case kHIDUsage_KeyboardF2:
|
|
handle = KeyboardButton::f2();
|
|
break;
|
|
case kHIDUsage_KeyboardF3:
|
|
handle = KeyboardButton::f3();
|
|
break;
|
|
case kHIDUsage_KeyboardF4:
|
|
handle = KeyboardButton::f4();
|
|
break;
|
|
case kHIDUsage_KeyboardF5:
|
|
handle = KeyboardButton::f5();
|
|
break;
|
|
case kHIDUsage_KeyboardF6:
|
|
handle = KeyboardButton::f6();
|
|
break;
|
|
case kHIDUsage_KeyboardF7:
|
|
handle = KeyboardButton::f7();
|
|
break;
|
|
case kHIDUsage_KeyboardF8:
|
|
handle = KeyboardButton::f8();
|
|
break;
|
|
case kHIDUsage_KeyboardF9:
|
|
handle = KeyboardButton::f9();
|
|
break;
|
|
case kHIDUsage_KeyboardF10:
|
|
handle = KeyboardButton::f10();
|
|
break;
|
|
case kHIDUsage_KeyboardF11:
|
|
handle = KeyboardButton::f11();
|
|
break;
|
|
case kHIDUsage_KeyboardF12:
|
|
handle = KeyboardButton::f12();
|
|
break;
|
|
case kHIDUsage_KeyboardPrintScreen:
|
|
handle = KeyboardButton::print_screen();
|
|
break;
|
|
case kHIDUsage_KeyboardScrollLock:
|
|
handle = KeyboardButton::scroll_lock();
|
|
break;
|
|
case kHIDUsage_KeyboardPause:
|
|
handle = KeyboardButton::pause();
|
|
break;
|
|
case kHIDUsage_KeyboardInsert:
|
|
handle = KeyboardButton::insert();
|
|
break;
|
|
case kHIDUsage_KeyboardHome:
|
|
handle = KeyboardButton::home();
|
|
break;
|
|
case kHIDUsage_KeyboardPageUp:
|
|
handle = KeyboardButton::page_up();
|
|
break;
|
|
case kHIDUsage_KeyboardDeleteForward:
|
|
handle = KeyboardButton::del();
|
|
break;
|
|
case kHIDUsage_KeyboardEnd:
|
|
handle = KeyboardButton::end();
|
|
break;
|
|
case kHIDUsage_KeyboardPageDown:
|
|
handle = KeyboardButton::page_down();
|
|
break;
|
|
case kHIDUsage_KeyboardRightArrow:
|
|
handle = KeyboardButton::right();
|
|
break;
|
|
case kHIDUsage_KeyboardLeftArrow:
|
|
handle = KeyboardButton::left();
|
|
break;
|
|
case kHIDUsage_KeyboardDownArrow:
|
|
handle = KeyboardButton::down();
|
|
break;
|
|
case kHIDUsage_KeyboardUpArrow:
|
|
handle = KeyboardButton::up();
|
|
break;
|
|
case kHIDUsage_KeypadNumLock:
|
|
handle = KeyboardButton::num_lock();
|
|
break;
|
|
case kHIDUsage_KeypadSlash:
|
|
handle = KeyboardButton::ascii_key('/');
|
|
break;
|
|
case kHIDUsage_KeypadAsterisk:
|
|
handle = KeyboardButton::ascii_key('*');
|
|
break;
|
|
case kHIDUsage_KeypadHyphen:
|
|
handle = KeyboardButton::ascii_key('-');
|
|
break;
|
|
case kHIDUsage_KeypadPlus:
|
|
handle = KeyboardButton::ascii_key('+');
|
|
break;
|
|
case kHIDUsage_KeypadEnter:
|
|
handle = KeyboardButton::enter();
|
|
break;
|
|
case kHIDUsage_Keypad1:
|
|
handle = KeyboardButton::ascii_key('1');
|
|
break;
|
|
case kHIDUsage_Keypad2:
|
|
handle = KeyboardButton::ascii_key('2');
|
|
break;
|
|
case kHIDUsage_Keypad3:
|
|
handle = KeyboardButton::ascii_key('3');
|
|
break;
|
|
case kHIDUsage_Keypad4:
|
|
handle = KeyboardButton::ascii_key('4');
|
|
break;
|
|
case kHIDUsage_Keypad5:
|
|
handle = KeyboardButton::ascii_key('5');
|
|
break;
|
|
case kHIDUsage_Keypad6:
|
|
handle = KeyboardButton::ascii_key('6');
|
|
break;
|
|
case kHIDUsage_Keypad7:
|
|
handle = KeyboardButton::ascii_key('7');
|
|
break;
|
|
case kHIDUsage_Keypad8:
|
|
handle = KeyboardButton::ascii_key('8');
|
|
break;
|
|
case kHIDUsage_Keypad9:
|
|
handle = KeyboardButton::ascii_key('9');
|
|
break;
|
|
case kHIDUsage_Keypad0:
|
|
handle = KeyboardButton::ascii_key('0');
|
|
break;
|
|
case kHIDUsage_KeypadPeriod:
|
|
handle = KeyboardButton::ascii_key('.');
|
|
break;
|
|
case kHIDUsage_KeyboardNonUSBackslash:
|
|
handle = KeyboardButton::ascii_key('\\');
|
|
break;
|
|
case kHIDUsage_KeypadEqualSign:
|
|
handle = KeyboardButton::ascii_key('=');
|
|
break;
|
|
case kHIDUsage_KeyboardF13:
|
|
handle = KeyboardButton::f13();
|
|
break;
|
|
case kHIDUsage_KeyboardF14:
|
|
handle = KeyboardButton::f14();
|
|
break;
|
|
case kHIDUsage_KeyboardF15:
|
|
handle = KeyboardButton::f15();
|
|
break;
|
|
case kHIDUsage_KeyboardF16:
|
|
handle = KeyboardButton::f16();
|
|
break;
|
|
case kHIDUsage_KeyboardExecute:
|
|
break;
|
|
case kHIDUsage_KeyboardHelp:
|
|
handle = KeyboardButton::help();
|
|
break;
|
|
case kHIDUsage_KeyboardMenu:
|
|
handle = KeyboardButton::menu();
|
|
break;
|
|
case kHIDUsage_KeypadComma:
|
|
handle = KeyboardButton::ascii_key(',');
|
|
break;
|
|
case kHIDUsage_KeypadEqualSignAS400:
|
|
handle = KeyboardButton::ascii_key('=');
|
|
break;
|
|
case kHIDUsage_KeyboardReturn:
|
|
handle = KeyboardButton::enter();
|
|
break;
|
|
case kHIDUsage_KeyboardLeftControl:
|
|
handle = KeyboardButton::lcontrol();
|
|
break;
|
|
case kHIDUsage_KeyboardLeftShift:
|
|
handle = KeyboardButton::lshift();
|
|
break;
|
|
case kHIDUsage_KeyboardLeftAlt:
|
|
handle = KeyboardButton::lalt();
|
|
break;
|
|
case kHIDUsage_KeyboardLeftGUI:
|
|
handle = KeyboardButton::lmeta();
|
|
break;
|
|
case kHIDUsage_KeyboardRightControl:
|
|
handle = KeyboardButton::rcontrol();
|
|
break;
|
|
case kHIDUsage_KeyboardRightShift:
|
|
handle = KeyboardButton::rshift();
|
|
break;
|
|
case kHIDUsage_KeyboardRightAlt:
|
|
handle = KeyboardButton::ralt();
|
|
break;
|
|
case kHIDUsage_KeyboardRightGUI:
|
|
handle = KeyboardButton::rmeta();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kHIDPage_Button:
|
|
if (_device_class == DeviceClass::GAMEPAD) {
|
|
if (_vendor_id == 0x0810 && _product_id == 0xe501) {
|
|
// SNES-style USB gamepad
|
|
static const ButtonHandle gamepad_buttons[] = {
|
|
ButtonHandle::none(),
|
|
GamepadButton::face_x(),
|
|
GamepadButton::face_a(),
|
|
GamepadButton::face_b(),
|
|
GamepadButton::face_y(),
|
|
GamepadButton::lshoulder(),
|
|
GamepadButton::rshoulder(),
|
|
ButtonHandle::none(),
|
|
ButtonHandle::none(),
|
|
GamepadButton::back(),
|
|
GamepadButton::start(),
|
|
};
|
|
if (usage < sizeof(gamepad_buttons) / sizeof(ButtonHandle)) {
|
|
handle = gamepad_buttons[usage];
|
|
}
|
|
} else {
|
|
// These seem to be the button mappings exposed by the 360Controller
|
|
// driver. I don't know if other drivers do the same thing at all.
|
|
static const ButtonHandle gamepad_buttons[] = {
|
|
ButtonHandle::none(),
|
|
GamepadButton::face_a(),
|
|
GamepadButton::face_b(),
|
|
GamepadButton::face_x(),
|
|
GamepadButton::face_y(),
|
|
GamepadButton::lshoulder(),
|
|
GamepadButton::rshoulder(),
|
|
GamepadButton::lstick(),
|
|
GamepadButton::rstick(),
|
|
GamepadButton::start(),
|
|
GamepadButton::back(),
|
|
GamepadButton::guide(),
|
|
GamepadButton::dpad_up(),
|
|
GamepadButton::dpad_down(),
|
|
GamepadButton::dpad_left(),
|
|
GamepadButton::dpad_right(),
|
|
};
|
|
if (usage < sizeof(gamepad_buttons) / sizeof(ButtonHandle)) {
|
|
handle = gamepad_buttons[usage];
|
|
}
|
|
}
|
|
} else if (_device_class == DeviceClass::FLIGHT_STICK) {
|
|
if (usage > 0) {
|
|
handle = GamepadButton::joystick(usage - 1);
|
|
}
|
|
} else if (_device_class == DeviceClass::MOUSE) {
|
|
// In Panda, wheel and right button are flipped around...
|
|
int button = (usage == 2 || usage == 3) ? (4 - usage) : (usage - 1);
|
|
handle = MouseButton::button(button);
|
|
}
|
|
break;
|
|
}
|
|
_buttons.push_back(ButtonState(handle));
|
|
_button_elements.push_back(element);
|
|
break;
|
|
|
|
case kIOHIDElementTypeInput_Axis:
|
|
break;
|
|
|
|
case kIOHIDElementTypeInput_ScanCodes:
|
|
break;
|
|
|
|
case kIOHIDElementTypeOutput:
|
|
break;
|
|
|
|
case kIOHIDElementTypeFeature:
|
|
break;
|
|
|
|
case kIOHIDElementTypeCollection:
|
|
{
|
|
// This doesn't seem to be necessary and instead leads to duplication of
|
|
// axes and buttons.
|
|
/*
|
|
CFArrayRef children = IOHIDElementGetChildren(element);
|
|
CFIndex count = CFArrayGetCount(children);
|
|
for (CFIndex i = 0; i < count; ++i) {
|
|
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(children, i);
|
|
parse_element(element, depth + 2);
|
|
}*/
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 IOKitInputDevice::
|
|
do_poll() {
|
|
for (size_t i = 0; i < _button_elements.size(); ++i) {
|
|
IOHIDValueRef value_ref;
|
|
if (!_button_elements[i]) continue;
|
|
if (IOHIDDeviceGetValue(_device, _button_elements[i], &value_ref) == kIOReturnSuccess) {
|
|
int value = IOHIDValueGetIntegerValue(value_ref);
|
|
button_changed(i, value != 0);
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < _analog_elements.size(); ++i) {
|
|
IOHIDValueRef value_ref;
|
|
if (IOHIDDeviceGetValue(_device, _analog_elements[i], &value_ref) == kIOReturnSuccess) {
|
|
int value = IOHIDValueGetIntegerValue(value_ref);
|
|
axis_changed(i, value);
|
|
}
|
|
}
|
|
|
|
if (_hat_element != nullptr) {
|
|
IOHIDValueRef value_ref;
|
|
if (IOHIDDeviceGetValue(_device, _hat_element, &value_ref) == kIOReturnSuccess) {
|
|
int value = IOHIDValueGetIntegerValue(value_ref);
|
|
button_changed(_hat_left_button + 0, value >= 5 && value <= 7); // left
|
|
button_changed(_hat_left_button + 1, value >= 1 && value <= 3); // right
|
|
button_changed(_hat_left_button + 2, value >= 3 && value <= 5); // down
|
|
button_changed(_hat_left_button + 3, value == 7 || value == 0 || value == 1); // up
|
|
}
|
|
}
|
|
|
|
int x = 0, y = 0;
|
|
if (_pointer_x != nullptr) {
|
|
IOHIDValueRef value_ref;
|
|
if (IOHIDDeviceGetValue(_device, _pointer_x, &value_ref) == kIOReturnSuccess) {
|
|
uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
|
|
if (timestamp != _pointer_x_timestamp) {
|
|
x = IOHIDValueGetIntegerValue(value_ref);
|
|
_pointer_x_timestamp = timestamp;
|
|
}
|
|
}
|
|
}
|
|
if (_pointer_y != nullptr) {
|
|
IOHIDValueRef value_ref;
|
|
if (IOHIDDeviceGetValue(_device, _pointer_y, &value_ref) == kIOReturnSuccess) {
|
|
uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
|
|
if (timestamp != _pointer_y_timestamp) {
|
|
y = IOHIDValueGetIntegerValue(value_ref);
|
|
_pointer_y_timestamp = timestamp;
|
|
}
|
|
}
|
|
}
|
|
if (x != 0 || y != 0) {
|
|
pointer_moved(0, x, y, ClockObject::get_global_clock()->get_frame_time());
|
|
}
|
|
|
|
// Do we have a scroll wheel axis?
|
|
if (_scroll_wheel != nullptr) {
|
|
IOHIDValueRef value_ref;
|
|
if (IOHIDDeviceGetValue(_device, _scroll_wheel, &value_ref) == kIOReturnSuccess) {
|
|
uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
|
|
if (timestamp != _scroll_wheel_timestamp) {
|
|
int value = IOHIDValueGetIntegerValue(value_ref);
|
|
if (value != 0) {
|
|
// Just fire off a rapid down/up event.
|
|
double time = ClockObject::get_global_clock()->get_frame_time();
|
|
ButtonHandle handle = (value > 0) ? MouseButton::wheel_up() : MouseButton::wheel_down();
|
|
_button_events->add_event(ButtonEvent(handle, ButtonEvent::T_down, time));
|
|
_button_events->add_event(ButtonEvent(handle, ButtonEvent::T_up, time));
|
|
}
|
|
_scroll_wheel_timestamp = timestamp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // __APPLE__
|