244 lines
9.9 KiB
Objective-C
244 lines
9.9 KiB
Objective-C
#import "ControllerInput.h"
|
|
#import "../LauncherPreferences.h"
|
|
#import "../PLProfiles.h"
|
|
#import "../SurfaceViewController.h"
|
|
#import "../utils.h"
|
|
|
|
#include "../glfw_keycodes.h"
|
|
|
|
// Left thumbstick directions
|
|
#define DIRECTION_EAST 0
|
|
#define DIRECTION_NORTH_EAST 1
|
|
//#define DIRECTION_NORTH 2
|
|
#define DIRECTION_NORTH_WEST 3
|
|
//#define DIRECTION_WEST 4
|
|
#define DIRECTION_SOUTH_WEST 5
|
|
//#define DIRECTION_SOUTH 6
|
|
#define DIRECTION_SOUTH_EAST 7
|
|
#define MOUSE_MAX_ACCELERATION 2
|
|
|
|
CFAbsoluteTime lastFrameTime;
|
|
CGFloat lastXValue; // lastHorizontalValue
|
|
CGFloat lastYValue; // lastVerticalValue
|
|
|
|
@implementation ControllerInput
|
|
|
|
NSMutableDictionary *gameMap, *menuMap;
|
|
BOOL leftShiftHeld;
|
|
|
|
+ (void)initKeycodeTable {
|
|
if (gameMap && menuMap) {
|
|
return;
|
|
}
|
|
|
|
NSString *controlFile = [PLProfiles resolveKeyForCurrentProfile:@"defaultGamepadCtrl"];
|
|
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/%@", getenv("POJAV_HOME"), controlFile];
|
|
NSMutableDictionary *gamepadJSON = parseJSONFromFile(gamepadPath);
|
|
|
|
gameMap = gamepadJSON[@"mGameMappingList"];
|
|
menuMap = gamepadJSON[@"mMenuMappingList"];
|
|
}
|
|
|
|
+ (void)sendKeyEvent:(int)controllerKeycode pressed:(BOOL)pressed {
|
|
int keycode;
|
|
__block NSMutableDictionary *mapping;
|
|
if (isGrabbing) {
|
|
mapping = gameMap;
|
|
} else {
|
|
mapping = menuMap;
|
|
}
|
|
|
|
for (NSMutableDictionary *buttonDict in mapping) {
|
|
if(controllerKeycode == [buttonDict[@"gamepad_button"] intValue]) {
|
|
keycode = [buttonDict[@"keycode"] intValue];
|
|
}
|
|
}
|
|
|
|
switch (keycode) {
|
|
case GLFW_KEY_UNKNOWN:
|
|
// Do nothing
|
|
break;
|
|
case -GLFW_KEY_LEFT_SHIFT:
|
|
if (!pressed) {
|
|
leftShiftHeld = !leftShiftHeld;
|
|
CallbackBridge_nativeSendKey(GLFW_KEY_LEFT_SHIFT, 0, leftShiftHeld, 0);
|
|
}
|
|
break;
|
|
case SPECIALBTN_MOUSEPRI:
|
|
CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, pressed, 0);
|
|
break;
|
|
case SPECIALBTN_MOUSEMID:
|
|
CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, pressed, 0);
|
|
break;
|
|
case SPECIALBTN_MOUSESEC:
|
|
CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, pressed, 0);
|
|
break;
|
|
case SPECIALBTN_SCROLLUP:
|
|
CallbackBridge_nativeSendScroll(0, pressed ? 1 : 0);
|
|
break;
|
|
case SPECIALBTN_SCROLLDOWN:
|
|
CallbackBridge_nativeSendScroll(0, pressed ? -1 : 0);
|
|
break;
|
|
default:
|
|
if (keycode == GLFW_KEY_LEFT_SHIFT) {
|
|
leftShiftHeld = pressed;
|
|
}
|
|
CallbackBridge_nativeSendKey(keycode, 0, pressed, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ (void)registerControllerCallbacks:(GCController *)controller {
|
|
GCExtendedGamepad *gamepad = controller.extendedGamepad;
|
|
|
|
gamepad.leftShoulder.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_LEFT_BUMPER pressed:pressed];
|
|
};
|
|
gamepad.rightShoulder.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER pressed:pressed];
|
|
};
|
|
|
|
gamepad.leftTrigger.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_LEFT_TRIGGER pressed:pressed];
|
|
};
|
|
gamepad.rightTrigger.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_RIGHT_TRIGGER pressed:pressed];
|
|
};
|
|
gamepad.buttonOptions.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_BACK pressed:pressed];
|
|
};
|
|
gamepad.buttonMenu.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_START pressed:pressed];
|
|
};
|
|
gamepad.buttonHome.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_GUIDE pressed:pressed];
|
|
};
|
|
|
|
gamepad.buttonA.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_A pressed:pressed];
|
|
};
|
|
gamepad.buttonB.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_B pressed:pressed];
|
|
};
|
|
gamepad.buttonX.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_X pressed:pressed];
|
|
};
|
|
gamepad.buttonY.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_Y pressed:pressed];
|
|
};
|
|
|
|
gamepad.dpad.up.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_UP pressed:pressed];
|
|
};
|
|
gamepad.dpad.down.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_DOWN pressed:pressed];
|
|
};
|
|
gamepad.dpad.left.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_LEFT pressed:pressed];
|
|
};
|
|
gamepad.dpad.right.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_RIGHT pressed:pressed];
|
|
};
|
|
|
|
gamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
|
|
if (!isGrabbing) {
|
|
// Update virtual mouse position
|
|
lastXValue = xValue;
|
|
lastYValue = yValue;
|
|
return;
|
|
}
|
|
|
|
static char lastLThumbDirection = -2;
|
|
char direction = -1;
|
|
if (xValue != 0 && yValue != 0) {
|
|
CGFloat degree = atan2f(yValue, xValue) * (180.0 / M_PI);
|
|
if (degree < 0) {
|
|
degree += 360;
|
|
}
|
|
direction = (int)((degree+22.5)/45.0) % 8;
|
|
}
|
|
if (lastLThumbDirection == direction) {
|
|
return;
|
|
}
|
|
|
|
// Update WASD states
|
|
CallbackBridge_nativeSendKey(GLFW_KEY_W, 0,
|
|
direction >= DIRECTION_NORTH_EAST &&
|
|
direction <= DIRECTION_NORTH_WEST, 0);
|
|
CallbackBridge_nativeSendKey(GLFW_KEY_A, 0,
|
|
direction >= DIRECTION_NORTH_WEST &&
|
|
direction <= DIRECTION_SOUTH_WEST, 0);
|
|
CallbackBridge_nativeSendKey(GLFW_KEY_S, 0,
|
|
direction >= DIRECTION_SOUTH_WEST &&
|
|
direction <= DIRECTION_SOUTH_EAST, 0);
|
|
CallbackBridge_nativeSendKey(GLFW_KEY_D, 0,
|
|
direction == DIRECTION_SOUTH_EAST ||
|
|
direction == DIRECTION_EAST ||
|
|
direction == DIRECTION_NORTH_EAST, 0);
|
|
|
|
lastLThumbDirection = direction;
|
|
};
|
|
gamepad.rightThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
|
|
if (isGrabbing) {
|
|
lastXValue = xValue;
|
|
lastYValue = yValue;
|
|
}
|
|
};
|
|
gamepad.leftThumbstickButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_LEFT_THUMB pressed:pressed];
|
|
};
|
|
gamepad.rightThumbstickButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[self sendKeyEvent:GLFW_GAMEPAD_BUTTON_RIGHT_THUMB pressed:pressed];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Send the new mouse position, computing the delta
|
|
*/
|
|
+ (void)tick {
|
|
// There isn't a convenient way to get ns, use ms at this point
|
|
CGFloat frameTime = CACurrentMediaTime();
|
|
// GameController automatically performs deadzone calculations
|
|
// so we just take the raw input
|
|
if (lastFrameTime != 0 && (lastXValue != 0 || lastYValue != 0)) {
|
|
CGFloat acceleration = pow(MathUtils_dist(0, 0, lastXValue, lastYValue), MOUSE_MAX_ACCELERATION); // magnitude
|
|
if (acceleration > 1) acceleration = 1;
|
|
|
|
// Compute delta since last tick time
|
|
CGFloat deltaX = lastXValue * acceleration * 18;
|
|
CGFloat deltaY = -lastYValue * acceleration * 18;
|
|
CGFloat deltaTimeScale = (frameTime - lastFrameTime) / (1.0/60.0); // Scale of 1 = 60Hz
|
|
deltaX *= deltaTimeScale;
|
|
deltaY *= deltaTimeScale;
|
|
|
|
SurfaceViewController *vc = (id)UIWindow.mainWindow.rootViewController;
|
|
[vc sendTouchPoint:CGPointMake(deltaX, deltaY) withEvent:ACTION_MOVE_MOTION];
|
|
}
|
|
lastFrameTime = frameTime;
|
|
}
|
|
|
|
+ (void)unregisterControllerCallbacks:(GCController *)controller {
|
|
GCExtendedGamepad *gamepad = controller.extendedGamepad;
|
|
gamepad.leftShoulder.pressedChangedHandler = nil;
|
|
gamepad.rightShoulder.pressedChangedHandler = nil;
|
|
gamepad.leftTrigger.pressedChangedHandler = nil;
|
|
gamepad.rightTrigger.pressedChangedHandler = nil;
|
|
gamepad.buttonOptions.pressedChangedHandler = nil;
|
|
gamepad.buttonMenu.pressedChangedHandler = nil;
|
|
gamepad.buttonHome.pressedChangedHandler = nil;
|
|
gamepad.buttonA.pressedChangedHandler = nil;
|
|
gamepad.buttonB.pressedChangedHandler = nil;
|
|
gamepad.buttonX.pressedChangedHandler = nil;
|
|
gamepad.buttonY.pressedChangedHandler = nil;
|
|
gamepad.dpad.up.pressedChangedHandler = nil;
|
|
gamepad.dpad.down.pressedChangedHandler = nil;
|
|
gamepad.dpad.left.pressedChangedHandler = nil;
|
|
gamepad.dpad.right.pressedChangedHandler = nil;
|
|
gamepad.leftThumbstick.valueChangedHandler = nil;
|
|
gamepad.rightThumbstick.valueChangedHandler = nil;
|
|
gamepad.leftThumbstickButton.pressedChangedHandler = nil;
|
|
gamepad.rightThumbstickButton.pressedChangedHandler = nil;
|
|
}
|
|
|
|
@end
|