mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 03:57:17 +01:00
Pulling down Control Center starts a touch on our view that UIKit doesn't always end or cancel. The tracker kept that slot down forever, and touch input stopped working until the app was restarted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
570 lines
22 KiB
Plaintext
570 lines
22 KiB
Plaintext
#include "Controls.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <memory>
|
|
|
|
#include "Common/Data/Encoding/Utf8.h"
|
|
#include "Common/Log.h"
|
|
#include "Common/TimeUtil.h"
|
|
#include "Common/Input/InputState.h"
|
|
#include "Common/System/NativeApp.h"
|
|
#include "Common/System/Display.h"
|
|
#include "Core/KeyMap.h"
|
|
|
|
static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) {
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_PAD_0;
|
|
key.flags = pressed ? KeyInputFlags::DOWN : KeyInputFlags::UP;
|
|
key.keyCode = keyCode;
|
|
NativeKey(key);
|
|
}
|
|
|
|
static void analogTriggerPressed(InputAxis axis, float value) {
|
|
AxisInput axisInput;
|
|
axisInput.deviceId = DEVICE_ID_PAD_0;
|
|
axisInput.axisId = axis;
|
|
axisInput.value = value;
|
|
NativeAxis(&axisInput, 1);
|
|
}
|
|
|
|
static void bindButton(GCControllerButtonInput *input, InputKeyCode keyCode) {
|
|
// Optional buttons are nil on controllers that don't have them.
|
|
if (input == nil) {
|
|
return;
|
|
}
|
|
input.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
controllerButtonPressed(pressed, keyCode);
|
|
};
|
|
}
|
|
|
|
static void bindTrigger(GCControllerButtonInput *trigger, InputAxis axis) {
|
|
if (trigger == nil) {
|
|
return;
|
|
}
|
|
trigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
analogTriggerPressed(axis, value);
|
|
};
|
|
}
|
|
|
|
static void bindDpad(GCControllerDirectionPad *dpad) {
|
|
if (dpad == nil) {
|
|
return;
|
|
}
|
|
bindButton(dpad.up, NKCODE_DPAD_UP);
|
|
bindButton(dpad.down, NKCODE_DPAD_DOWN);
|
|
bindButton(dpad.left, NKCODE_DPAD_LEFT);
|
|
bindButton(dpad.right, NKCODE_DPAD_RIGHT);
|
|
}
|
|
|
|
static void bindStick(GCControllerDirectionPad *stick, InputAxis xAxis, InputAxis yAxis) {
|
|
if (stick == nil) {
|
|
return;
|
|
}
|
|
stick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
|
AxisInput axisInput;
|
|
axisInput.deviceId = DEVICE_ID_PAD_0;
|
|
axisInput.axisId = xAxis;
|
|
axisInput.value = value;
|
|
NativeAxis(&axisInput, 1);
|
|
};
|
|
stick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
|
AxisInput axisInput;
|
|
axisInput.deviceId = DEVICE_ID_PAD_0;
|
|
axisInput.axisId = yAxis;
|
|
axisInput.value = -value;
|
|
NativeAxis(&axisInput, 1);
|
|
};
|
|
}
|
|
|
|
// Newer iOS versions (17.4+) also have GCInputDirectionalDpad as a name for it.
|
|
static GCControllerDirectionPad *findDpad(GCPhysicalInputProfile *profile) {
|
|
GCControllerDirectionPad *dpad = profile.dpads[GCInputDirectionPad];
|
|
if (dpad == nil) {
|
|
if (@available(iOS 17.4, tvOS 17.4, *)) {
|
|
dpad = profile.dpads[GCInputDirectionalDpad];
|
|
}
|
|
}
|
|
return dpad;
|
|
}
|
|
|
|
bool InitController(GCController *controller) {
|
|
GCExtendedGamepad *extendedProfile = controller.extendedGamepad;
|
|
GCPhysicalInputProfile *profile = controller.physicalInputProfile;
|
|
|
|
// Controllers without thumbsticks (like the 8BitDo FlipPad) have no extended profile, only the
|
|
// physical one. Take those if they at least look like a gamepad.
|
|
NSDictionary<NSString *, GCControllerButtonInput *> *buttons = profile.buttons;
|
|
NSDictionary<NSString *, GCControllerDirectionPad *> *dpads = profile.dpads;
|
|
if (extendedProfile == nil && (buttons[GCInputButtonA] == nil || findDpad(profile) == nil)) {
|
|
INFO_LOG(Log::System, "Ignoring controller without a gamepad layout: %s", [controller.vendorName ?: @"(unnamed)" UTF8String]);
|
|
return false;
|
|
}
|
|
|
|
for (GCControllerElement* element in profile.allElements) {
|
|
element.preferredSystemGestureState = GCSystemGestureStateDisabled;
|
|
}
|
|
|
|
const std::string controllerName = [controller.vendorName ?: @"Gamepad" UTF8String];
|
|
KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, controllerName);
|
|
|
|
if (extendedProfile != nil) {
|
|
bindButton(extendedProfile.buttonA, NKCODE_BUTTON_2); // Cross
|
|
bindButton(extendedProfile.buttonB, NKCODE_BUTTON_3); // Circle
|
|
bindButton(extendedProfile.buttonX, NKCODE_BUTTON_4); // Square
|
|
bindButton(extendedProfile.buttonY, NKCODE_BUTTON_1); // Triangle
|
|
bindButton(extendedProfile.leftShoulder, NKCODE_BUTTON_L1); // LTrigger
|
|
bindButton(extendedProfile.rightShoulder, NKCODE_BUTTON_R1); // RTrigger
|
|
bindDpad(extendedProfile.dpad);
|
|
bindTrigger(extendedProfile.leftTrigger, JOYSTICK_AXIS_LTRIGGER);
|
|
bindTrigger(extendedProfile.rightTrigger, JOYSTICK_AXIS_RTRIGGER);
|
|
bindButton(extendedProfile.leftThumbstickButton, NKCODE_BUTTON_THUMBL);
|
|
bindButton(extendedProfile.rightThumbstickButton, NKCODE_BUTTON_THUMBR);
|
|
bindButton(extendedProfile.buttonOptions, NKCODE_BUTTON_SELECT);
|
|
bindButton(extendedProfile.buttonMenu, NKCODE_BUTTON_START);
|
|
bindButton(extendedProfile.buttonHome, NKCODE_HOME);
|
|
bindStick(extendedProfile.leftThumbstick, JOYSTICK_AXIS_X, JOYSTICK_AXIS_Y);
|
|
// Map right thumbstick as another analog stick, particularly useful for controllers
|
|
// like the DualShock 3/4 when connected to an iOS device
|
|
bindStick(extendedProfile.rightThumbstick, JOYSTICK_AXIS_Z, JOYSTICK_AXIS_RZ);
|
|
return true;
|
|
}
|
|
|
|
// The same layout, looked up by element name. Anything the controller lacks is nil.
|
|
NSMutableArray<NSString *> *names = [NSMutableArray arrayWithArray:buttons.allKeys];
|
|
[names addObjectsFromArray:dpads.allKeys];
|
|
INFO_LOG(Log::System, "Controller %s has no extended profile, using its elements: %s", controllerName.c_str(), [[names componentsJoinedByString:@", "] UTF8String]);
|
|
|
|
bindButton(buttons[GCInputButtonA], NKCODE_BUTTON_2);
|
|
bindButton(buttons[GCInputButtonB], NKCODE_BUTTON_3);
|
|
bindButton(buttons[GCInputButtonX], NKCODE_BUTTON_4);
|
|
bindButton(buttons[GCInputButtonY], NKCODE_BUTTON_1);
|
|
bindButton(buttons[GCInputLeftShoulder], NKCODE_BUTTON_L1);
|
|
bindButton(buttons[GCInputRightShoulder], NKCODE_BUTTON_R1);
|
|
bindDpad(findDpad(profile));
|
|
bindTrigger(buttons[GCInputLeftTrigger], JOYSTICK_AXIS_LTRIGGER);
|
|
bindTrigger(buttons[GCInputRightTrigger], JOYSTICK_AXIS_RTRIGGER);
|
|
bindButton(buttons[GCInputLeftThumbstickButton], NKCODE_BUTTON_THUMBL);
|
|
bindButton(buttons[GCInputRightThumbstickButton], NKCODE_BUTTON_THUMBR);
|
|
bindButton(buttons[GCInputButtonOptions], NKCODE_BUTTON_SELECT);
|
|
bindButton(buttons[GCInputButtonMenu], NKCODE_BUTTON_START);
|
|
bindButton(buttons[GCInputButtonHome], NKCODE_HOME);
|
|
bindStick(dpads[GCInputLeftThumbstick], JOYSTICK_AXIS_X, JOYSTICK_AXIS_Y);
|
|
bindStick(dpads[GCInputRightThumbstick], JOYSTICK_AXIS_Z, JOYSTICK_AXIS_RZ);
|
|
return true;
|
|
}
|
|
|
|
void ShutdownController(GCController *controller) {
|
|
for (GCControllerElement* element in controller.physicalInputProfile.allElements) {
|
|
element.preferredSystemGestureState = GCSystemGestureStateEnabled;
|
|
}
|
|
static const InputKeyCode keycodes[] = {
|
|
NKCODE_BUTTON_1,
|
|
NKCODE_BUTTON_2,
|
|
NKCODE_BUTTON_3,
|
|
NKCODE_BUTTON_4,
|
|
NKCODE_BUTTON_L1,
|
|
NKCODE_BUTTON_R1,
|
|
NKCODE_DPAD_UP,
|
|
NKCODE_DPAD_DOWN,
|
|
NKCODE_DPAD_LEFT,
|
|
NKCODE_DPAD_RIGHT,
|
|
NKCODE_BUTTON_THUMBL,
|
|
NKCODE_BUTTON_THUMBR,
|
|
NKCODE_BUTTON_SELECT,
|
|
NKCODE_BUTTON_START,
|
|
NKCODE_HOME
|
|
};
|
|
for (InputKeyCode keyCode : keycodes) {
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_PAD_0;
|
|
key.flags = KeyInputFlags::UP;
|
|
key.keyCode = keyCode;
|
|
NativeKey(key);
|
|
}
|
|
|
|
static const InputAxis axes[] = {
|
|
JOYSTICK_AXIS_X,
|
|
JOYSTICK_AXIS_Y,
|
|
JOYSTICK_AXIS_Z,
|
|
JOYSTICK_AXIS_RZ,
|
|
JOYSTICK_AXIS_LTRIGGER,
|
|
JOYSTICK_AXIS_RTRIGGER
|
|
};
|
|
AxisInput axisInput;
|
|
axisInput.deviceId = DEVICE_ID_PAD_0;
|
|
for (InputAxis axis : axes) {
|
|
axisInput.axisId = axis;
|
|
axisInput.value = 0.0f;
|
|
NativeAxis(&axisInput, 1);
|
|
}
|
|
KeyMap::NotifyPadDisconnected(DEVICE_ID_PAD_0);
|
|
}
|
|
|
|
static void remoteButtonPressed(BOOL pressed, InputKeyCode keyCode) {
|
|
// As keyboard keys, which the UI already understands (arrows, enter, escape), and which have
|
|
// default in-game mappings.
|
|
KeyInput key;
|
|
key.deviceId = DEVICE_ID_KEYBOARD;
|
|
key.flags = pressed ? KeyInputFlags::DOWN : KeyInputFlags::UP;
|
|
key.keyCode = keyCode;
|
|
NativeKey(key);
|
|
}
|
|
|
|
// A click on a remote without a separate ring (the 1st generation Siri Remote): an arrow at the
|
|
// edges of the touch surface, enter in the middle. Handlers run on the main queue, so no locking.
|
|
struct RemoteClickState {
|
|
bool clicking = false;
|
|
InputKeyCode key = NKCODE_UNKNOWN;
|
|
};
|
|
|
|
// A click further out than this from the center is an arrow. The surface is -1..1 on each axis.
|
|
static const float REMOTE_EDGE_CLICK = 0.5f;
|
|
|
|
static void remoteClicked(RemoteClickState *s, GCControllerDirectionPad *touch, BOOL pressed) {
|
|
if (pressed) {
|
|
if (s->clicking) {
|
|
return;
|
|
}
|
|
const float x = touch.xAxis.value;
|
|
const float y = touch.yAxis.value;
|
|
if (std::max(fabsf(x), fabsf(y)) < REMOTE_EDGE_CLICK) {
|
|
s->key = NKCODE_ENTER;
|
|
} else if (fabsf(x) > fabsf(y)) {
|
|
s->key = x > 0.0f ? NKCODE_DPAD_RIGHT : NKCODE_DPAD_LEFT;
|
|
} else {
|
|
s->key = y > 0.0f ? NKCODE_DPAD_UP : NKCODE_DPAD_DOWN;
|
|
}
|
|
s->clicking = true;
|
|
remoteButtonPressed(YES, s->key);
|
|
} else if (s->clicking) {
|
|
s->clicking = false;
|
|
remoteButtonPressed(NO, s->key);
|
|
}
|
|
}
|
|
|
|
bool InitSiriRemote(GCController *controller) {
|
|
GCMicroGamepad *micro = controller.microGamepad;
|
|
if (micro == nil || controller.extendedGamepad != nil) {
|
|
return false;
|
|
}
|
|
// A gamepad without thumbsticks can have a micro profile too. Remotes have no B button.
|
|
if (controller.physicalInputProfile.buttons[GCInputButtonB] != nil) {
|
|
return false;
|
|
}
|
|
|
|
micro.allowsRotation = NO;
|
|
|
|
// Swiping on the touch surface isn't used for now. One swipe step per so much travel fought
|
|
// with the ring presses. Maybe it could scroll.
|
|
GCPhysicalInputProfile *profile = controller.physicalInputProfile;
|
|
GCControllerDirectionPad *ring = profile.dpads[GCInputDirectionalCardinalDpad];
|
|
GCControllerButtonInput *center = profile.buttons[GCInputDirectionalCenterButton];
|
|
if (ring != nil && center != nil) {
|
|
// The 2nd generation remote, whose ring has real buttons. This takes
|
|
// GCSupportsMultipleMicroGamepads in Info.plist. buttonA isn't used, since it's pressed
|
|
// along with every ring button.
|
|
ring.up.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_DPAD_UP);
|
|
};
|
|
ring.down.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_DPAD_DOWN);
|
|
};
|
|
ring.left.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_DPAD_LEFT);
|
|
};
|
|
ring.right.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_DPAD_RIGHT);
|
|
};
|
|
center.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_ENTER);
|
|
};
|
|
} else {
|
|
// Where the finger is when clicking, rather than how far it moved since it went down.
|
|
micro.reportsAbsoluteDpadValues = YES;
|
|
GCControllerDirectionPad *touch = micro.dpad;
|
|
std::shared_ptr<RemoteClickState> state = std::make_shared<RemoteClickState>();
|
|
micro.buttonA.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteClicked(state.get(), touch, pressed);
|
|
};
|
|
}
|
|
// Play/pause. Escape opens the pause menu in-game.
|
|
micro.buttonX.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_ESCAPE);
|
|
};
|
|
// The Menu (or Back) button.
|
|
micro.buttonMenu.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
remoteButtonPressed(pressed, NKCODE_BACK);
|
|
};
|
|
INFO_LOG(Log::System, "Siri Remote set up: %s (ring: %s)", [controller.vendorName ?: @"Remote" UTF8String], ring != nil ? "yes" : "no");
|
|
return true;
|
|
}
|
|
|
|
void TouchTracker::SendTouchEvent(CGPoint point, UIView *view, int code, int pointerId) {
|
|
// From points to dp. The view covers the whole display.
|
|
CGSize size = view.bounds.size;
|
|
if (size.width <= 0.0 || size.height <= 0.0) {
|
|
return;
|
|
}
|
|
|
|
TouchInput input;
|
|
input.x = point.x * g_display.dp_xres / size.width;
|
|
input.y = point.y * g_display.dp_yres / size.height;
|
|
switch (code) {
|
|
case 1: input.flags = TouchInputFlags::DOWN; break;
|
|
case 2: input.flags = TouchInputFlags::UP; break;
|
|
default: input.flags = TouchInputFlags::MOVE; break;
|
|
}
|
|
input.id = pointerId;
|
|
NativeTouch(input);
|
|
}
|
|
|
|
int TouchTracker::ToTouchID(UITouch *uiTouch, bool allowAllocate) {
|
|
// Find the id for the touch.
|
|
for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) {
|
|
if (touches_[localId] == uiTouch) {
|
|
return localId;
|
|
}
|
|
}
|
|
|
|
// Allocate a new one, perhaps?
|
|
if (allowAllocate) {
|
|
for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) {
|
|
if (touches_[localId] == 0) {
|
|
touches_[localId] = uiTouch;
|
|
return localId;
|
|
}
|
|
}
|
|
|
|
// None were free. Ignore?
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void TouchTracker::Began(NSSet *touches, UIView *view) {
|
|
for (UITouch* touch in touches) {
|
|
CGPoint point = [touch locationInView:view];
|
|
int touchId = ToTouchID(touch, true);
|
|
SendTouchEvent(point, view, 1, touchId);
|
|
}
|
|
}
|
|
|
|
void TouchTracker::Moved(NSSet *touches, UIView *view) {
|
|
for (UITouch* touch in touches) {
|
|
CGPoint point = [touch locationInView:view];
|
|
int touchId = ToTouchID(touch, true);
|
|
SendTouchEvent(point, view, 0, touchId);
|
|
}
|
|
}
|
|
|
|
void TouchTracker::Ended(NSSet *touches, UIView *view) {
|
|
for (UITouch* touch in touches) {
|
|
CGPoint point = [touch locationInView:view];
|
|
int touchId = ToTouchID(touch, false);
|
|
if (touchId >= 0) {
|
|
SendTouchEvent(point, view, 2, touchId);
|
|
touches_[touchId] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TouchTracker::Cancelled(NSSet *touches, UIView *view) {
|
|
for (UITouch* touch in touches) {
|
|
CGPoint point = [touch locationInView:view];
|
|
int touchId = ToTouchID(touch, false);
|
|
if (touchId >= 0) {
|
|
SendTouchEvent(point, view, 2, touchId);
|
|
touches_[touchId] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TouchTracker::CancelAll() {
|
|
for (int touchId = 0; touchId < (int)ARRAY_SIZE(touches_); ++touchId) {
|
|
if (touches_[touchId]) {
|
|
TouchInput input{};
|
|
input.flags = TouchInputFlags::UP | TouchInputFlags::CANCEL;
|
|
input.id = touchId;
|
|
NativeTouch(input);
|
|
touches_[touchId] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !PPSSPP_PLATFORM(TVOS)
|
|
void ProcessAccelerometerData(CMAccelerometerData *accData) {
|
|
CMAcceleration acc = accData.acceleration;
|
|
// INFO_LOG(SYSTEM, "%f %f %f", acc.x, acc.y, acc.z);
|
|
|
|
// Core Motion reports acceleration in g, with the opposite sign of Android's m/s^2.
|
|
// Might need to change these for portrait or inverse landscape
|
|
const float standardGravity = 9.81f;
|
|
NativeAccelerometer(-acc.x * standardGravity, -acc.y * standardGravity, -acc.z * standardGravity);
|
|
}
|
|
|
|
void ProcessGyroData(CMGyroData *gyroData) {
|
|
// Same axes and units (rad/s, right-handed) as Android.
|
|
CMRotationRate rate = gyroData.rotationRate;
|
|
NativeGyroscope(rate.x, rate.y, rate.z, gyroData.timestamp);
|
|
}
|
|
#endif
|
|
|
|
void SendKeyboardChars(std::string_view str) {
|
|
UTF8 chars(str);
|
|
while (!chars.end()) {
|
|
uint32_t codePoint = chars.next();
|
|
KeyInput input{};
|
|
input.deviceId = DEVICE_ID_KEYBOARD;
|
|
input.flags = KeyInputFlags::CHAR;
|
|
input.unicodeChar = codePoint;
|
|
NativeKey(input);
|
|
}
|
|
}
|
|
|
|
static void SendPresses(NSSet<UIPress *> *presses, KeyInputFlags flags) {
|
|
for (UIPress *press in presses) {
|
|
if (!press.key) {
|
|
// I guess we could support remotes and stuff.
|
|
continue;
|
|
}
|
|
InputKeyCode code = HIDUsageToInputKeyCode(press.key.keyCode);
|
|
if (code != NKCODE_UNKNOWN) {
|
|
KeyInput input{};
|
|
input.deviceId = DEVICE_ID_KEYBOARD;
|
|
input.keyCode = code;
|
|
input.flags = flags;
|
|
NativeKey(input);
|
|
}
|
|
if ((flags & KeyInputFlags::DOWN) && press.key.characters) {
|
|
std::string chars([press.key.characters UTF8String]);
|
|
SendKeyboardChars(chars);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyboardPressesBegan(NSSet<UIPress *> *presses, UIPressesEvent *event) {
|
|
SendPresses(presses, KeyInputFlags::DOWN);
|
|
}
|
|
|
|
void KeyboardPressesEnded(NSSet<UIPress *> *presses, UIPressesEvent *event) {
|
|
SendPresses(presses, KeyInputFlags::UP);
|
|
}
|
|
|
|
InputKeyCode HIDUsageToInputKeyCode(UIKeyboardHIDUsage usage) {
|
|
switch (usage) {
|
|
case UIKeyboardHIDUsageKeyboardA: return NKCODE_A;
|
|
case UIKeyboardHIDUsageKeyboardB: return NKCODE_B;
|
|
case UIKeyboardHIDUsageKeyboardC: return NKCODE_C;
|
|
case UIKeyboardHIDUsageKeyboardD: return NKCODE_D;
|
|
case UIKeyboardHIDUsageKeyboardE: return NKCODE_E;
|
|
case UIKeyboardHIDUsageKeyboardF: return NKCODE_F;
|
|
case UIKeyboardHIDUsageKeyboardG: return NKCODE_G;
|
|
case UIKeyboardHIDUsageKeyboardH: return NKCODE_H;
|
|
case UIKeyboardHIDUsageKeyboardI: return NKCODE_I;
|
|
case UIKeyboardHIDUsageKeyboardJ: return NKCODE_J;
|
|
case UIKeyboardHIDUsageKeyboardK: return NKCODE_K;
|
|
case UIKeyboardHIDUsageKeyboardL: return NKCODE_L;
|
|
case UIKeyboardHIDUsageKeyboardM: return NKCODE_M;
|
|
case UIKeyboardHIDUsageKeyboardN: return NKCODE_N;
|
|
case UIKeyboardHIDUsageKeyboardO: return NKCODE_O;
|
|
case UIKeyboardHIDUsageKeyboardP: return NKCODE_P;
|
|
case UIKeyboardHIDUsageKeyboardQ: return NKCODE_Q;
|
|
case UIKeyboardHIDUsageKeyboardR: return NKCODE_R;
|
|
case UIKeyboardHIDUsageKeyboardS: return NKCODE_S;
|
|
case UIKeyboardHIDUsageKeyboardT: return NKCODE_T;
|
|
case UIKeyboardHIDUsageKeyboardU: return NKCODE_U;
|
|
case UIKeyboardHIDUsageKeyboardV: return NKCODE_V;
|
|
case UIKeyboardHIDUsageKeyboardW: return NKCODE_W;
|
|
case UIKeyboardHIDUsageKeyboardX: return NKCODE_X;
|
|
case UIKeyboardHIDUsageKeyboardY: return NKCODE_Y;
|
|
case UIKeyboardHIDUsageKeyboardZ: return NKCODE_Z;
|
|
case UIKeyboardHIDUsageKeyboard1: return NKCODE_1;
|
|
case UIKeyboardHIDUsageKeyboard2: return NKCODE_2;
|
|
case UIKeyboardHIDUsageKeyboard3: return NKCODE_3;
|
|
case UIKeyboardHIDUsageKeyboard4: return NKCODE_4;
|
|
case UIKeyboardHIDUsageKeyboard5: return NKCODE_5;
|
|
case UIKeyboardHIDUsageKeyboard6: return NKCODE_6;
|
|
case UIKeyboardHIDUsageKeyboard7: return NKCODE_7;
|
|
case UIKeyboardHIDUsageKeyboard8: return NKCODE_8;
|
|
case UIKeyboardHIDUsageKeyboard9: return NKCODE_9;
|
|
case UIKeyboardHIDUsageKeyboard0: return NKCODE_0;
|
|
case UIKeyboardHIDUsageKeyboardReturnOrEnter: return NKCODE_NUMPAD_ENTER;
|
|
case UIKeyboardHIDUsageKeyboardEscape: return NKCODE_ESCAPE;
|
|
case UIKeyboardHIDUsageKeyboardDeleteOrBackspace: return NKCODE_DEL; // really.
|
|
case UIKeyboardHIDUsageKeyboardTab: return NKCODE_TAB;
|
|
case UIKeyboardHIDUsageKeyboardSpacebar: return NKCODE_SPACE;
|
|
case UIKeyboardHIDUsageKeyboardHyphen: return NKCODE_MINUS;
|
|
case UIKeyboardHIDUsageKeyboardEqualSign: return NKCODE_EQUALS;
|
|
case UIKeyboardHIDUsageKeyboardOpenBracket: return NKCODE_LEFT_BRACKET;
|
|
case UIKeyboardHIDUsageKeyboardCloseBracket: return NKCODE_RIGHT_BRACKET;
|
|
case UIKeyboardHIDUsageKeyboardBackslash: return NKCODE_BACKSLASH;
|
|
case UIKeyboardHIDUsageKeyboardNonUSPound: return NKCODE_POUND;
|
|
case UIKeyboardHIDUsageKeyboardSemicolon: return NKCODE_SEMICOLON;
|
|
case UIKeyboardHIDUsageKeyboardQuote: return NKCODE_APOSTROPHE;
|
|
case UIKeyboardHIDUsageKeyboardGraveAccentAndTilde: return NKCODE_GRAVE;
|
|
case UIKeyboardHIDUsageKeyboardComma: return NKCODE_COMMA;
|
|
case UIKeyboardHIDUsageKeyboardPeriod: return NKCODE_PERIOD;
|
|
case UIKeyboardHIDUsageKeyboardSlash: return NKCODE_SLASH;
|
|
case UIKeyboardHIDUsageKeyboardCapsLock: return NKCODE_CAPS_LOCK;
|
|
case UIKeyboardHIDUsageKeyboardF1: return NKCODE_F1;
|
|
case UIKeyboardHIDUsageKeyboardF2: return NKCODE_F2;
|
|
case UIKeyboardHIDUsageKeyboardF3: return NKCODE_F3;
|
|
case UIKeyboardHIDUsageKeyboardF4: return NKCODE_F4;
|
|
case UIKeyboardHIDUsageKeyboardF5: return NKCODE_F5;
|
|
case UIKeyboardHIDUsageKeyboardF6: return NKCODE_F6;
|
|
case UIKeyboardHIDUsageKeyboardF7: return NKCODE_F7;
|
|
case UIKeyboardHIDUsageKeyboardF8: return NKCODE_F8;
|
|
case UIKeyboardHIDUsageKeyboardF9: return NKCODE_F9;
|
|
case UIKeyboardHIDUsageKeyboardF10: return NKCODE_F10;
|
|
case UIKeyboardHIDUsageKeyboardF11: return NKCODE_F11;
|
|
case UIKeyboardHIDUsageKeyboardF12: return NKCODE_F12;
|
|
case UIKeyboardHIDUsageKeyboardScrollLock: return NKCODE_SCROLL_LOCK;
|
|
case UIKeyboardHIDUsageKeyboardInsert: return NKCODE_INSERT;
|
|
case UIKeyboardHIDUsageKeyboardHome: return NKCODE_HOME;
|
|
case UIKeyboardHIDUsageKeyboardPageUp: return NKCODE_PAGE_UP;
|
|
case UIKeyboardHIDUsageKeyboardDeleteForward: return NKCODE_DEL;
|
|
case UIKeyboardHIDUsageKeyboardEnd: return NKCODE_MOVE_END;
|
|
case UIKeyboardHIDUsageKeyboardPageDown: return NKCODE_PAGE_DOWN;
|
|
case UIKeyboardHIDUsageKeyboardRightArrow: return NKCODE_DPAD_RIGHT;
|
|
case UIKeyboardHIDUsageKeyboardLeftArrow: return NKCODE_DPAD_LEFT;
|
|
case UIKeyboardHIDUsageKeyboardDownArrow: return NKCODE_DPAD_DOWN;
|
|
case UIKeyboardHIDUsageKeyboardUpArrow: return NKCODE_DPAD_UP;
|
|
case UIKeyboardHIDUsageKeypadNumLock: return NKCODE_NUM_LOCK;
|
|
case UIKeyboardHIDUsageKeypadSlash: return NKCODE_NUMPAD_DIVIDE;
|
|
case UIKeyboardHIDUsageKeypadAsterisk: return NKCODE_NUMPAD_MULTIPLY;
|
|
case UIKeyboardHIDUsageKeypadHyphen: return NKCODE_NUMPAD_SUBTRACT;
|
|
case UIKeyboardHIDUsageKeypadPlus: return NKCODE_NUMPAD_ADD;
|
|
case UIKeyboardHIDUsageKeypadEnter: return NKCODE_NUMPAD_ENTER;
|
|
case UIKeyboardHIDUsageKeypad1: return NKCODE_NUMPAD_1;
|
|
case UIKeyboardHIDUsageKeypad2: return NKCODE_NUMPAD_2;
|
|
case UIKeyboardHIDUsageKeypad3: return NKCODE_NUMPAD_3;
|
|
case UIKeyboardHIDUsageKeypad4: return NKCODE_NUMPAD_4;
|
|
case UIKeyboardHIDUsageKeypad5: return NKCODE_NUMPAD_5;
|
|
case UIKeyboardHIDUsageKeypad6: return NKCODE_NUMPAD_6;
|
|
case UIKeyboardHIDUsageKeypad7: return NKCODE_NUMPAD_7;
|
|
case UIKeyboardHIDUsageKeypad8: return NKCODE_NUMPAD_8;
|
|
case UIKeyboardHIDUsageKeypad9: return NKCODE_NUMPAD_9;
|
|
case UIKeyboardHIDUsageKeypad0: return NKCODE_NUMPAD_0;
|
|
case UIKeyboardHIDUsageKeypadPeriod: return NKCODE_NUMPAD_COMMA;
|
|
case UIKeyboardHIDUsageKeyboardNonUSBackslash: return NKCODE_BACKSLASH;
|
|
case UIKeyboardHIDUsageKeyboardApplication: return NKCODE_APP_SWITCH;
|
|
case UIKeyboardHIDUsageKeyboardPower: return NKCODE_POWER;
|
|
case UIKeyboardHIDUsageKeypadEqualSign: return NKCODE_NUMPAD_EQUALS;
|
|
case UIKeyboardHIDUsageKeyboardMenu: return NKCODE_MENU;
|
|
case UIKeyboardHIDUsageKeyboardMute: return NKCODE_MUTE;
|
|
case UIKeyboardHIDUsageKeyboardVolumeUp: return NKCODE_VOLUME_UP;
|
|
case UIKeyboardHIDUsageKeypadComma: return NKCODE_NUMPAD_COMMA;
|
|
case UIKeyboardHIDUsageKeyboardLeftShift: return NKCODE_SHIFT_LEFT;
|
|
case UIKeyboardHIDUsageKeyboardRightShift: return NKCODE_SHIFT_RIGHT;
|
|
case UIKeyboardHIDUsageKeyboardLeftControl: return NKCODE_CTRL_LEFT;
|
|
case UIKeyboardHIDUsageKeyboardRightControl: return NKCODE_CTRL_RIGHT;
|
|
case UIKeyboardHIDUsageKeyboardLeftAlt: return NKCODE_ALT_LEFT;
|
|
case UIKeyboardHIDUsageKeyboardRightAlt: return NKCODE_ALT_RIGHT;
|
|
case UIKeyboardHIDUsageKeyboardLeftGUI: return NKCODE_META_LEFT;
|
|
case UIKeyboardHIDUsageKeyboardRightGUI: return NKCODE_META_RIGHT;
|
|
default: return NKCODE_UNKNOWN;
|
|
}
|
|
}
|