diff --git a/Natives/LauncherPreferences.m b/Natives/LauncherPreferences.m index dbdad5b0..085d6a42 100644 --- a/Natives/LauncherPreferences.m +++ b/Natives/LauncherPreferences.m @@ -131,10 +131,12 @@ void loadPreferences(BOOL reset) { setDefaultValueForPref(envPrefDict, @"gyroscope_invert_x_axis", @NO); setDefaultValueForPref(envPrefDict, @"gyroscope_sensitivity", @(100)); setDefaultValueForPref(envPrefDict, @"default_ctrl", @"default.json"); + setDefaultValueForPref(envPrefDict, @"default_gamepad_ctrl", @"default.json"); setDefaultValueForPref(envPrefDict, @"game_directory", @"default"); setDefaultValueForPref(envPrefDict, @"java_args", @""); setDefaultValueForPref(envPrefDict, @"allocated_memory", [NSNumber numberWithFloat:roundf((NSProcessInfo.processInfo.physicalMemory / 1048576) * 0.25)]); setDefaultValueForPref(envPrefDict, @"jitstreamer_server", @"69.69.0.1"); + setDefaultValueForPref(envPrefDict, @"max_framerate", @YES); setDefaultValueForPref(prefDict, @"appicon", @"AppIcon-Light"); setDefaultValueForPref(prefDict, @"debug_logging", @(CONFIG_RELEASE != 1)); setDefaultValueForPref(prefDict, @"cosmetica", @YES); diff --git a/Natives/LauncherPreferencesViewController.m b/Natives/LauncherPreferencesViewController.m index 2649a935..50ec3f5d 100644 --- a/Natives/LauncherPreferencesViewController.m +++ b/Natives/LauncherPreferencesViewController.m @@ -211,6 +211,14 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *); @"min": @(25), @"max": @(150) }, + @{@"key": @"max_framerate", + @"hasDetail": @YES, + @"icon": @"timelapse", + @"type": self.typeSwitch, + @"enableCondition": ^BOOL(){ + return whenNotInGame() && (UIScreen.mainScreen.maximumFramesPerSecond > 60); + } + }, @{@"key": @"fullscreen_airplay", @"hasDetail": @YES, @"icon": @"airplayvideo", diff --git a/Natives/customcontrols/CustomControlsUtils.h b/Natives/customcontrols/CustomControlsUtils.h index bc7c38ee..3dcc2b66 100644 --- a/Natives/customcontrols/CustomControlsUtils.h +++ b/Natives/customcontrols/CustomControlsUtils.h @@ -11,6 +11,7 @@ int convertUIColor2ARGB(UIColor* color); int convertUIColor2RGB(UIColor* color); BOOL convertLayoutIfNecessary(NSMutableDictionary* dict); void generateAndSaveDefaultControl(); +void generateAndSaveDefaultControlForGamepad(); void loadControlObject(UIView* targetView, NSMutableDictionary* controlDictionary); void initKeycodeTable(NSMutableArray* keyCodeMap, NSMutableArray* keyValueMap); diff --git a/Natives/customcontrols/CustomControlsUtils.m b/Natives/customcontrols/CustomControlsUtils.m index 95d087fe..0154ba2e 100644 --- a/Natives/customcontrols/CustomControlsUtils.m +++ b/Natives/customcontrols/CustomControlsUtils.m @@ -23,6 +23,14 @@ NSMutableDictionary* createButton(NSString* name, int* keycodes, NSString* dynam return dict; } +NSMutableDictionary* createGamepadButton(NSString* name, int gamepad_button, int keycode) { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + dict[@"name"] = name; + dict[@"gamepad_button"] = @(gamepad_button); + dict[@"keycode"] = @(keycode); + return dict; +} + UIColor* convertARGB2UIColor(int argb) { return [UIColor colorWithRed:((argb>>16)&0xFF)/255.0 @@ -302,6 +310,67 @@ void generateAndSaveDefaultControl() { */ } +void generateAndSaveDefaultControlForGamepad() { + NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepad-default.json", getenv("POJAV_HOME")]; + if ([NSFileManager.defaultManager fileExistsAtPath:gamepadPath]) { + return; + } + + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + dict[@"version"] = @(1); + + dict[@"mGameMappingList"] = [[NSMutableArray alloc] init]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"mouse_primary", SPECIALBTN_MOUSEPRI, SPECIALBTN_MOUSEPRI)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"mouse_middle", SPECIALBTN_MOUSEMID, SPECIALBTN_MOUSEMID)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"mouse_secondary", SPECIALBTN_MOUSESEC, SPECIALBTN_MOUSESEC)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"bumper_left", GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, SPECIALBTN_SCROLLUP)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"bumper_right", GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, SPECIALBTN_SCROLLDOWN)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"trigger_left", GLFW_GAMEPAD_BUTTON_LEFT_TRIGGER, SPECIALBTN_MOUSESEC)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"trigger_right", GLFW_GAMEPAD_BUTTON_RIGHT_TRIGGER, SPECIALBTN_MOUSEPRI)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_back", GLFW_GAMEPAD_BUTTON_BACK, GLFW_KEY_TAB)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_start", GLFW_GAMEPAD_BUTTON_START, GLFW_KEY_ESCAPE)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_a", GLFW_GAMEPAD_BUTTON_A, GLFW_KEY_SPACE)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_b", GLFW_GAMEPAD_BUTTON_B, GLFW_KEY_Q)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_x", GLFW_GAMEPAD_BUTTON_X, GLFW_KEY_E)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"named_y", GLFW_GAMEPAD_BUTTON_Y, GLFW_KEY_F)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"dpad_up", GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_KEY_LEFT_SHIFT)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"dpad_down", GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW_KEY_O)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"dpad_left", GLFW_GAMEPAD_BUTTON_DPAD_LEFT, GLFW_KEY_J)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"dpad_right", GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, GLFW_KEY_K)]; + + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"thumb_left", GLFW_GAMEPAD_BUTTON_LEFT_THUMB, GLFW_KEY_LEFT_CONTROL)]; + [dict[@"mGameMappingList"] addObject:createGamepadButton(@"thumb_right", GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, -GLFW_KEY_LEFT_SHIFT)]; + + dict[@"mMenuMappingList"] = [[NSMutableArray alloc] init]; + + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"mouse_primary", SPECIALBTN_MOUSEPRI, SPECIALBTN_MOUSEPRI)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"mouse_middle", SPECIALBTN_MOUSEMID, SPECIALBTN_MOUSEMID)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"mouse_secondary", SPECIALBTN_MOUSESEC, SPECIALBTN_MOUSESEC)]; + + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"bumper_left", GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, SPECIALBTN_SCROLLUP)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"bumper_right", GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, SPECIALBTN_SCROLLDOWN)]; + + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_a", GLFW_GAMEPAD_BUTTON_A, SPECIALBTN_MOUSEPRI)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_b", GLFW_GAMEPAD_BUTTON_B, GLFW_KEY_ESCAPE)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_x", GLFW_GAMEPAD_BUTTON_X, SPECIALBTN_MOUSESEC)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_y", GLFW_GAMEPAD_BUTTON_Y, GLFW_KEY_LEFT_SHIFT)]; + + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"dpad_down", GLFW_GAMEPAD_BUTTON_DPAD_DOWN, GLFW_KEY_O)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"dpad_left", GLFW_GAMEPAD_BUTTON_DPAD_LEFT, GLFW_KEY_J)]; + [dict[@"mMenuMappingList"] addObject:createGamepadButton(@"dpad_right", GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, GLFW_KEY_K)]; + + NSOutputStream *os = [[NSOutputStream alloc] initToFileAtPath:gamepadPath append:NO]; + [os open]; + [NSJSONSerialization writeJSONObject:dict toStream:os options:NSJSONWritingPrettyPrinted error:nil]; + [os close]; +} + void loadControlObject(UIView* targetView, NSMutableDictionary* controlDictionary) { NSMutableString *errorString = [[NSMutableString alloc] init]; diff --git a/Natives/en.lproj/Localizable.strings b/Natives/en.lproj/Localizable.strings index 2edea2cd..b3fd0392 100644 --- a/Natives/en.lproj/Localizable.strings +++ b/Natives/en.lproj/Localizable.strings @@ -175,6 +175,8 @@ "preference.title.resolution" = "Resolution (%)"; "preference.detail.resolution" = "Allows you to decrease the game resolution."; +"preference.title.max_framerate" = "Maximum framerate"; +"preference.detail.max_framerate" = "Allows you to limit the game framerate to 60FPS on ProMotion displays."; "preference.title.fullscreen_airplay" = "Fullscreen AirPlay"; "preference.detail.fullscreen_airplay" = "Allows presenting fullscreen game window on the external display rather than mirroring everything on screen."; diff --git a/Natives/input/ControllerInput.m b/Natives/input/ControllerInput.m index b2f2d85e..20013e99 100644 --- a/Natives/input/ControllerInput.m +++ b/Natives/input/ControllerInput.m @@ -1,4 +1,5 @@ #import "ControllerInput.h" +#import "../LauncherPreferences.h" #import "../SurfaceViewController.h" #import "../utils.h" @@ -28,61 +29,27 @@ BOOL leftShiftHeld; if (gameMap && menuMap) { return; } - - gameMap = [[NSMutableDictionary alloc] init]; - - gameMap[@(SPECIALBTN_MOUSEPRI)] = @(SPECIALBTN_MOUSEPRI); - gameMap[@(SPECIALBTN_MOUSEMID)] = @(SPECIALBTN_MOUSEMID); - gameMap[@(SPECIALBTN_MOUSESEC)] = @(SPECIALBTN_MOUSESEC); - - gameMap[@(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)] = @(SPECIALBTN_SCROLLUP); - gameMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)] = @(SPECIALBTN_SCROLLDOWN); - - gameMap[@(GLFW_GAMEPAD_BUTTON_LEFT_TRIGGER)] = @(SPECIALBTN_MOUSESEC); - gameMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_TRIGGER)] = @(SPECIALBTN_MOUSEPRI); - - gameMap[@(GLFW_GAMEPAD_BUTTON_BACK)] = @(GLFW_KEY_TAB); - gameMap[@(GLFW_GAMEPAD_BUTTON_START)] = @(GLFW_KEY_ESCAPE); - //gameMap[@(GLFW_GAMEPAD_BUTTON_GUIDE)] = @(GLFW_KEY_UNKNOWN); - - gameMap[@(GLFW_GAMEPAD_BUTTON_A)] = @(GLFW_KEY_SPACE); - gameMap[@(GLFW_GAMEPAD_BUTTON_B)] = @(GLFW_KEY_Q); - gameMap[@(GLFW_GAMEPAD_BUTTON_X)] = @(GLFW_KEY_E); - gameMap[@(GLFW_GAMEPAD_BUTTON_Y)] = @(GLFW_KEY_F); - - gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_UP)] = @(GLFW_KEY_LEFT_SHIFT); - gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)] = @(GLFW_KEY_O); - gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)] = @(GLFW_KEY_J); - gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)] = @(GLFW_KEY_K); - - gameMap[@(GLFW_GAMEPAD_BUTTON_LEFT_THUMB)] = @(GLFW_KEY_LEFT_CONTROL); - gameMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)] = @(-GLFW_KEY_LEFT_SHIFT); - - menuMap = [[NSMutableDictionary alloc] init]; - - menuMap[@(SPECIALBTN_MOUSEPRI)] = @(SPECIALBTN_MOUSEPRI); - menuMap[@(SPECIALBTN_MOUSEMID)] = @(SPECIALBTN_MOUSEMID); - menuMap[@(SPECIALBTN_MOUSESEC)] = @(SPECIALBTN_MOUSESEC); - - menuMap[@(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)] = @(SPECIALBTN_SCROLLUP); - menuMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)] = @(SPECIALBTN_SCROLLDOWN); - - menuMap[@(GLFW_GAMEPAD_BUTTON_A)] = @(SPECIALBTN_MOUSEPRI); - menuMap[@(GLFW_GAMEPAD_BUTTON_B)] = @(GLFW_KEY_ESCAPE); - menuMap[@(GLFW_GAMEPAD_BUTTON_X)] = @(SPECIALBTN_MOUSESEC); - menuMap[@(GLFW_GAMEPAD_BUTTON_Y)] = @(GLFW_KEY_LEFT_SHIFT); - - menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)] = @(GLFW_KEY_O); - menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)] = @(GLFW_KEY_J); - menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)] = @(GLFW_KEY_K); + + NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepad-%@", getenv("POJAV_HOME"), getPreference(@"default_gamepad_ctrl")]; + NSMutableDictionary *gamepadJSON = parseJSONFromFile(gamepadPath); + + gameMap = gamepadJSON[@"mGameMappingList"]; + menuMap = gamepadJSON[@"mMenuMappingList"]; } + (void)sendKeyEvent:(int)controllerKeycode pressed:(BOOL)pressed { int keycode; + __block NSMutableDictionary *mapping; if (isGrabbing) { - keycode = [gameMap[@(controllerKeycode)] intValue]; + mapping = gameMap; } else { - keycode = [menuMap[@(controllerKeycode)] intValue]; + mapping = menuMap; + } + + for (NSMutableDictionary *buttonDict in mapping) { + if(controllerKeycode == [buttonDict[@"gamepad_button"] intValue]) { + keycode = [buttonDict[@"keycode"] intValue]; + } } switch (keycode) { diff --git a/Natives/main.m b/Natives/main.m index d297dc76..6b5edbb5 100644 --- a/Natives/main.m +++ b/Natives/main.m @@ -242,6 +242,7 @@ void init_setupCustomControls() { NSString *controlPath = [@(getenv("POJAV_HOME")) stringByAppendingPathComponent:@"controlmap"]; [fm createDirectoryAtPath:controlPath withIntermediateDirectories:NO attributes:nil error:nil]; generateAndSaveDefaultControl(); + generateAndSaveDefaultControlForGamepad(); } void init_setupLauncherProfiles() { diff --git a/Natives/resources/Assets.car b/Natives/resources/Assets.car index e78206d0..6acece54 100644 Binary files a/Natives/resources/Assets.car and b/Natives/resources/Assets.car differ