Controller configurator!
Same keycode names as the on-screen editor to make it easier to identify the possible values. Xbox and PlayStation button names for familiarity. Saving configs handled by the Save and Exit buttons on the navigation bar. Currently known issues: - may be jumpy when cells reload or load onto the screen - loading a new configuration file does not update the value of the cells - loading a new configuration file does not update the "Controller configurator" item in the main Settings window - both of these are solved by closing and reopening the view controller for now
This commit is contained in:
1 parent
83b43238c9
commit
bcdcc080fb
14 files changed
+828
-7
No files matched your search
@@ -127,6 +127,7 @@ add_executable(PojavLauncher
|
||||
LauncherNewsViewController.m
|
||||
LauncherPreferences.m
|
||||
LauncherPreferencesViewController.m
|
||||
LauncherPrefContCfgViewController.m
|
||||
LauncherPrefGameDirViewController.m
|
||||
LauncherSplitViewController.m
|
||||
MinecraftResourceUtils.m
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface LauncherPrefContCfgViewController : UITableViewController
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "input/ControllerInput.h"
|
||||
#import "customcontrols/CustomControlsUtils.h"
|
||||
#import "FileListViewController.h"
|
||||
#import "LauncherNavigationController.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPrefContCfgViewController.h"
|
||||
#import "TOInsetGroupedTableView.h"
|
||||
#import "ios_uikit_bridge.h"
|
||||
#import "utils.h"
|
||||
|
||||
#include "glfw_keycodes.h"
|
||||
|
||||
#define contentNavigationController (LauncherNavigationController *)UIApplication.sharedApplication.keyWindow.rootViewController.splitViewController.viewControllers[1]
|
||||
|
||||
typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
|
||||
|
||||
@interface LauncherPrefContCfgViewController ()<UITextFieldDelegate, UIPopoverPresentationControllerDelegate, UIPickerViewDataSource, UIPickerViewDelegate>
|
||||
@property(nonatomic) NSString *currentFileName;
|
||||
@property(nonatomic) NSMutableDictionary *allMappings;
|
||||
@property(nonatomic) NSDictionary *keycodePlist;
|
||||
@property(nonatomic) UITextField *activeTextField;
|
||||
@property(nonatomic) NSArray<NSString*>* prefSections;
|
||||
@property(nonatomic) NSMutableArray<NSNumber*>* prefSectionsVisibility;
|
||||
@property(nonatomic) NSArray<NSArray<NSDictionary*>*>* prefContents;
|
||||
@property(nonatomic) NSArray<NSArray*>* prefMappings, *prefMappingsTrimmed;
|
||||
@property(nonatomic) NSArray<NSDictionary*>* prefConfigFiles, *prefControllerTypes;
|
||||
@property(nonatomic) NSMutableArray *keyCodeMap, *keyValueMap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LauncherPrefContCfgViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:localize(@"preference.title.default_gamepad_ctrl", nil)];
|
||||
|
||||
self.keycodePlist = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"glfw_keycodes" ofType:@"plist"]];
|
||||
|
||||
self.keyCodeMap = [[NSMutableArray alloc] init];
|
||||
self.keyValueMap = [[NSMutableArray alloc] init];
|
||||
initKeycodeTable(self.keyCodeMap, self.keyValueMap);
|
||||
|
||||
self.tableView = [[TOInsetGroupedTableView alloc] init];
|
||||
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
|
||||
self.tableView.sectionFooterHeight = 50;
|
||||
|
||||
self.prefMappings = [self loadGamepadConfigurationFile:YES shouldSkipImmutables:NO];
|
||||
self.prefMappingsTrimmed = [self loadGamepadConfigurationFile:NO shouldSkipImmutables:YES];
|
||||
self.prefConfigFiles = [self loadGamepadControlFolder];
|
||||
self.prefControllerTypes = [self loadControllerTypeOptions];
|
||||
|
||||
self.prefSections = @[@"config_files", @"game_mappings", @"menu_mappings", @"controller_style"];
|
||||
self.prefContents = @[self.prefConfigFiles, self.prefMappingsTrimmed[0], self.prefMappingsTrimmed[1], self.prefControllerTypes];
|
||||
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:localize(@"Save", nil) style:UIBarButtonItemStyleDone target:self action:@selector(actionMenuSave)];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:localize(@"Exit", nil) style:UIBarButtonItemStyleDone target:self action:@selector(exitButtonSelector)];
|
||||
|
||||
}
|
||||
|
||||
- (NSArray<NSArray<NSDictionary*>*>*) loadGamepadConfigurationFile:(BOOL)isUpdated shouldSkipImmutables:(BOOL)isSkipped {
|
||||
if(isUpdated) {
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/%@", getenv("POJAV_HOME"), getPreference(@"default_gamepad_ctrl")];
|
||||
self.allMappings = parseJSONFromFile(gamepadPath);
|
||||
}
|
||||
|
||||
self.currentFileName = [getPreference(@"default_ctrl") stringByDeletingPathExtension];
|
||||
|
||||
NSMutableArray<NSDictionary*>* tempGameMap = [[NSMutableArray<NSDictionary*> alloc] init];
|
||||
NSMutableArray<NSDictionary*>* tempMenuMap = [[NSMutableArray<NSDictionary*> alloc] init];
|
||||
|
||||
__block NSArray *immutables = @[@"mouse_primary", @"mouse_middle", @"mouse_secondary"];
|
||||
__block NSArray *maps = @[@"mGameMappingList", @"mMenuMappingList"];
|
||||
|
||||
for(NSString *mapName in maps) {
|
||||
for(NSDictionary* mapping in self.allMappings[mapName]) {
|
||||
__block BOOL isImmutable = NO;
|
||||
__block int isThird = 0;
|
||||
for(NSString* name in immutables) {
|
||||
if([name isEqualToString:mapping[@"name"]]) { if(isSkipped) { isImmutable = YES; } }
|
||||
if(isThird == 2 && !isImmutable) {
|
||||
if([mapName isEqualToString:maps[0]]) {
|
||||
[tempGameMap addObject:mapping];
|
||||
} else if([mapName isEqualToString:maps[1]]) {
|
||||
[tempMenuMap addObject:mapping];
|
||||
}
|
||||
}
|
||||
isThird++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @[[tempGameMap copy], [tempMenuMap copy]];
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary*>*) loadGamepadControlFolder {
|
||||
NSArray<NSString*>* gamepadCtrl = @[getPreference(@"default_gamepad_ctrl")];
|
||||
NSMutableArray<NSDictionary*>* finalArray = [[NSMutableArray alloc] init];
|
||||
NSMutableDictionary *holder = [[NSMutableDictionary alloc] init];
|
||||
holder[@"name"] = gamepadCtrl;
|
||||
[finalArray addObject:holder];
|
||||
|
||||
return [finalArray copy];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray<NSDictionary*>*) loadControllerTypeOptions {
|
||||
NSArray<NSString*>* types = @[@"xbox", @"playstation"];
|
||||
NSMutableArray<NSDictionary*>* finalArray = [[NSMutableArray alloc] init];
|
||||
for(NSString *type in types) {
|
||||
NSMutableDictionary *controllerDict = [[NSMutableDictionary alloc] init];
|
||||
controllerDict[@"name"] = type;
|
||||
[finalArray addObject:controllerDict];
|
||||
}
|
||||
|
||||
return [finalArray copy];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
#pragma mark External UITableView functions
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return self.prefSections.count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.prefContents[section].count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
__weak LauncherPrefContCfgViewController *weakSelf = self;
|
||||
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
NSString *cellID = @"cellValue1";
|
||||
UITableViewCellStyle cellStyle = UITableViewCellStyleValue1;
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
|
||||
if (cell == nil) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:cellStyle reuseIdentifier:cellID];
|
||||
cell.detailTextLabel.numberOfLines = 0;
|
||||
cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
}
|
||||
|
||||
// Reset cell properties, as it could be reused
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
cell.accessoryView = nil;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
cell.textLabel.textColor = nil;
|
||||
cell.detailTextLabel.text = nil;
|
||||
|
||||
NSString *name = nil;
|
||||
NSString *value = nil;
|
||||
NSNumber *keycode = 0;
|
||||
|
||||
if(indexPath.section == 0) {
|
||||
name = item[@"name"];
|
||||
value = getPreference(@"default_gamepad_ctrl");
|
||||
cell.textLabel.text = localize(@"controller_configurator.title.current", nil);
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell.detailTextLabel.text = value;
|
||||
} else if(indexPath.section == 1 || indexPath.section == 2) {
|
||||
name = item[@"name"];
|
||||
NSNumber *keycode = (NSNumber *)item[@"keycode"];
|
||||
value = [self.keyCodeMap objectAtIndex:[self.keyValueMap indexOfObject:keycode]];
|
||||
cell.textLabel.text = localize(([NSString stringWithFormat:@"controller_configurator.%@.title.%@", getPreference(@"controller_type"), name]), nil);
|
||||
|
||||
CGFloat shortest = MIN(self.view.frame.size.width, self.view.frame.size.height);
|
||||
CGFloat tempW = MIN(self.view.frame.size.width * 0.75, shortest);
|
||||
CGFloat tempH = MIN(self.view.frame.size.height * 0.6, shortest);
|
||||
|
||||
UITextField *view = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width / 2.1, cell.bounds.size.height)];
|
||||
[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||
view.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
view.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
|
||||
view.delegate = weakSelf;
|
||||
view.returnKeyType = UIReturnKeyDone;
|
||||
view.text = value;
|
||||
view.tag = indexPath.section;
|
||||
view.textAlignment = NSTextAlignmentRight;
|
||||
view.tintColor = UIColor.clearColor;
|
||||
view.adjustsFontSizeToFitWidth = YES;
|
||||
|
||||
UIPickerView *pickerMapping = [[UIPickerView alloc] init];
|
||||
pickerMapping.delegate = self;
|
||||
pickerMapping.dataSource = self;
|
||||
[pickerMapping reloadAllComponents];
|
||||
[pickerMapping selectRow:[self.keyValueMap indexOfObject:keycode] inComponent:0 animated:NO];
|
||||
[self pickerView:pickerMapping didSelectRow:0 inComponent:0];
|
||||
|
||||
|
||||
UIBlurEffectStyle blurStyle;
|
||||
UIVisualEffectView *blurView;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
blurStyle = UIBlurEffectStyleSystemMaterial;
|
||||
} else {
|
||||
blurStyle = UIBlurEffectStyleExtraLight;
|
||||
}
|
||||
blurView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:blurStyle]];
|
||||
blurView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
blurView.frame = CGRectMake(
|
||||
(self.view.frame.size.width - MAX(tempW, tempH))/2,
|
||||
(self.view.frame.size.height - MIN(tempW, tempH))/2,
|
||||
MAX(tempW, tempH), MIN(tempW, tempH));
|
||||
blurView.layer.cornerRadius = 10.0;
|
||||
blurView.clipsToBounds = YES;
|
||||
|
||||
UIToolbar *editPickToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, blurView.frame.size.width, 44.0)];
|
||||
UIBarButtonItem *btnFlexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
|
||||
|
||||
UIBarButtonItem *editDoneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(closeTextField:)];
|
||||
editPickToolbar.items = @[btnFlexibleSpace, editDoneButton];
|
||||
|
||||
view.inputAccessoryView = editPickToolbar;
|
||||
view.inputView = pickerMapping;
|
||||
|
||||
cell.accessoryView = view;
|
||||
} else if(indexPath.section == 3) {
|
||||
name = item[@"name"];
|
||||
value = getPreference(@"default_gamepad_ctrl");
|
||||
cell.textLabel.text = localize([NSString stringWithFormat:@"controller_configurator.title.type.%@", name], nil);
|
||||
if ([getPreference(@"controller_type") isEqualToString:name]) {
|
||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
}
|
||||
}
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleGray;
|
||||
|
||||
if (cell.accessoryView) {
|
||||
objc_setAssociatedObject(cell.accessoryView, @"gamepad_button", name, OBJC_ASSOCIATION_ASSIGN);
|
||||
objc_setAssociatedObject(cell.accessoryView, @"item", item, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
[(id)cell.accessoryView setEnabled:YES];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
NSString *header = NSLocalizedStringWithDefaultValue(([NSString stringWithFormat:@"controller_configurator.section.%@", self.prefSections[section]]), @"Localizable", NSBundle.mainBundle, @" ", nil);
|
||||
if ([header isEqualToString:@" "]) {
|
||||
return nil;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
|
||||
NSString *footer = NSLocalizedStringWithDefaultValue(([NSString stringWithFormat:@"controller_configurator.section.footer.%@", self.prefSections[section]]), @"Localizable", NSBundle.mainBundle, @" ", nil);
|
||||
if ([footer isEqualToString:@" "]) {
|
||||
return nil;
|
||||
}
|
||||
return footer;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
|
||||
if (indexPath.section == 0 || indexPath.section == 3) {
|
||||
[self tableView:tableView invokeActionAtIndexPath:indexPath];
|
||||
return;
|
||||
}
|
||||
// 1 and 2 handle themselves with picker views.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView invokeActionAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
if(indexPath.section == 0) {
|
||||
[self actionMenuLoad];
|
||||
[self.tableView reloadData];
|
||||
} else if(indexPath.section == 3) {
|
||||
if(indexPath.row == 0) {
|
||||
setPreference(@"controller_type", @"xbox");
|
||||
} else if(indexPath.row == 1) {
|
||||
setPreference(@"controller_type", @"playstation");
|
||||
}
|
||||
NSIndexSet *section = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 3)];
|
||||
[self.tableView reloadSections:section withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark UITextField + UIPickerView
|
||||
|
||||
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
|
||||
{
|
||||
UILabel *label = (UILabel *)view;
|
||||
if (label == nil) {
|
||||
label = [UILabel new];
|
||||
label.adjustsFontSizeToFitWidth = YES;
|
||||
label.minimumScaleFactor = 0.5;
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
label.text = [self pickerView:pickerView titleForRow:row forComponent:component];
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
|
||||
self.activeTextField.text = [self.keyCodeMap objectAtIndex:row];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
|
||||
return self.keyCodeMap.count;
|
||||
}
|
||||
|
||||
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
|
||||
return [self.keyCodeMap objectAtIndex:row];
|
||||
}
|
||||
|
||||
- (void)textFieldDidBeginEditing:(UITextField *)textField
|
||||
{
|
||||
self.activeTextField = textField;
|
||||
}
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField
|
||||
{
|
||||
UITableViewCell *cell = (UITableViewCell *)textField.superview;
|
||||
__block NSDictionary *item = objc_getAssociatedObject(cell.accessoryView, @"item");
|
||||
__block NSString *fullString = @"";
|
||||
__block NSArray *arrayToSave = nil;
|
||||
__block NSUInteger btnIndex = 0;
|
||||
__block NSString *index = @"";
|
||||
|
||||
if(textField.tag == 1) {
|
||||
arrayToSave = self.prefMappings[0];
|
||||
index = @"mGameMappingList";
|
||||
} else if(textField.tag == 2) {
|
||||
arrayToSave = self.prefMappings[1];
|
||||
index = @"mMenuMappingList";
|
||||
}
|
||||
|
||||
for(NSDictionary* mapping in arrayToSave) {
|
||||
if(item[@"gamepad_button"] == mapping[@"gamepad_button"]) {
|
||||
btnIndex = [arrayToSave indexOfObject:mapping];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(![textField.text hasPrefix:@"SPECIALBTN"]) {
|
||||
fullString = [@"GLFW_KEY_" stringByAppendingString:textField.text];
|
||||
} else {
|
||||
fullString = textField.text;
|
||||
}
|
||||
|
||||
self.allMappings[index][btnIndex][@"keycode"] = [self.keycodePlist objectForKey:fullString];
|
||||
|
||||
self.activeTextField = nil;
|
||||
}
|
||||
|
||||
- (void)closeTextField:(UIBarButtonItem *)sender {
|
||||
[self.activeTextField endEditing:YES];
|
||||
}
|
||||
|
||||
#pragma mark UI
|
||||
|
||||
- (void) dismissModalViewController {
|
||||
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionOpenFilePicker:(void (^)(NSString *name))handler {
|
||||
FileListViewController *vc = [[FileListViewController alloc] init];
|
||||
vc.listPath = [NSString stringWithFormat:@"%s/controlmap/gamepads", getenv("POJAV_HOME")];
|
||||
|
||||
vc.whenItemSelected = handler;
|
||||
vc.modalPresentationStyle = UIModalPresentationPopover;
|
||||
vc.preferredContentSize = CGSizeMake(350, 250);
|
||||
|
||||
UIPopoverPresentationController *popoverController = [vc popoverPresentationController];
|
||||
popoverController.sourceView = self.tableView;
|
||||
popoverController.sourceRect = [self.tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
popoverController.delegate = self;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionMenuLoad {
|
||||
[self actionOpenFilePicker:^void(NSString* name) {
|
||||
NSString *currentFile = [NSString stringWithFormat:@"%@.json", getPreference(@"default_gamepad_ctrl")];
|
||||
if(![currentFile isEqualToString:name]) {
|
||||
setPreference(@"default_gamepad_ctrl", [NSString stringWithFormat:@"%@.json", name]);
|
||||
self.prefMappings = [self loadGamepadConfigurationFile:YES shouldSkipImmutables:NO];
|
||||
self.prefMappingsTrimmed = [self loadGamepadConfigurationFile:NO shouldSkipImmutables:YES];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)actionMenuSaveWithExit:(BOOL)exit {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:localize(@"custom_controls.control_menu.save", nil)
|
||||
message:exit?localize(@"custom_controls.control_menu.exit.warn", nil):@""
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
||||
textField.placeholder = @"Name";
|
||||
textField.text = self.currentFileName;
|
||||
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
|
||||
textField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
}];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:localize(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSArray *textFields = controller.textFields;
|
||||
UITextField *field = textFields[0];
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self.allMappings options:NSJSONWritingPrettyPrinted error:&error];
|
||||
if (jsonData == nil) {
|
||||
showDialog(self, localize(@"custom_controls.control_menu.save.error.json", nil), error.localizedDescription);
|
||||
return;
|
||||
}
|
||||
BOOL success = [jsonData writeToFile:[NSString stringWithFormat:@"%s/controlmap/gamepads/%@.json", getenv("POJAV_HOME"), field.text] options:NSDataWritingAtomic error:&error];
|
||||
if (!success) {
|
||||
showDialog(self, localize(@"custom_controls.control_menu.save.error.write", nil), error.localizedDescription);
|
||||
return;
|
||||
}
|
||||
|
||||
if (exit) {
|
||||
[self dismissModalViewController];
|
||||
}
|
||||
|
||||
setPreference(@"default_gamepad_ctrl", [NSString stringWithFormat:@"%@.json", field.text]);
|
||||
}]];
|
||||
if (exit) {
|
||||
[controller addAction:[UIAlertAction actionWithTitle:localize(@"custom_controls.control_menu.discard_changes", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
[self dismissModalViewController];
|
||||
}]];
|
||||
}
|
||||
[controller addAction:[UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionMenuSave {
|
||||
[self actionMenuSaveWithExit:NO];
|
||||
}
|
||||
|
||||
- (void)exitButtonSelector {
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/%@", getenv("POJAV_HOME"), getPreference(@"default_gamepad_ctrl")];
|
||||
if([self.allMappings isEqualToDictionary:parseJSONFromFile(gamepadPath)]) {
|
||||
[self dismissModalViewController];
|
||||
} else {
|
||||
[self actionMenuSaveWithExit:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -140,6 +140,7 @@ void loadPreferences(BOOL reset) {
|
||||
setDefaultValueForPref(prefDict, @"appicon", @"AppIcon-Light");
|
||||
setDefaultValueForPref(prefDict, @"debug_logging", @(CONFIG_RELEASE != 1));
|
||||
setDefaultValueForPref(prefDict, @"cosmetica", @YES);
|
||||
setDefaultValueForPref(prefDict, @"controller_type", @"xbox");
|
||||
setDefaultValueForPref(envPrefDict, @"java_home", @"java-8-openjdk");
|
||||
setDefaultValueForPref(envPrefDict, @"renderer", @"auto");
|
||||
setDefaultValueForPref(envPrefDict, @"fullscreen_airplay", @YES);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#import "LauncherMenuViewController.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPreferencesViewController.h"
|
||||
#import "LauncherPrefContCfgViewController.h"
|
||||
#import "LauncherPrefGameDirViewController.h"
|
||||
#import "TOInsetGroupedTableView.h"
|
||||
#import "UIKit+hook.h"
|
||||
@@ -70,6 +71,7 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
|
||||
@"enableCondition": ^BOOL(){
|
||||
return whenNotInGame() && !getenv("DEMO_LOCK");
|
||||
},
|
||||
@"canDismissWithSwipe": @YES,
|
||||
@"class": LauncherPrefGameDirViewController.class,
|
||||
},
|
||||
@{@"key": @"check_sha",
|
||||
@@ -238,9 +240,16 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
|
||||
], @[
|
||||
// Control settings
|
||||
@{@"icon": @"gamecontroller"},
|
||||
@{@"key": @"default_gamepad_ctrl",
|
||||
@"icon": @"hammer",
|
||||
@"type": self.typeChildPane,
|
||||
@"enableCondition": whenNotInGame,
|
||||
@"canDismissWithSwipe": @NO,
|
||||
@"class": LauncherPrefContCfgViewController.class
|
||||
},
|
||||
@{@"key": @"hardware_hide",
|
||||
@"icon": @"eye.slash",
|
||||
@"hasDetail": @"YES",
|
||||
@"hasDetail": @YES,
|
||||
@"type": self.typeSwitch,
|
||||
},
|
||||
@{@"key": @"gesture_mouse",
|
||||
@@ -712,6 +721,9 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:[[item[@"class"] alloc] init]];
|
||||
vc.navigationBar.prefersLargeTitles = YES;
|
||||
if(@available(iOS 13.0, *)) {
|
||||
vc.modalInPresentation = ![item[@"canDismissWithSwipe"] boolValue];
|
||||
}
|
||||
[self.navigationController presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define BTN_SQUARE 50.0, 50.0
|
||||
|
||||
NSMutableDictionary* createButton(NSString* name, int* keycodes, NSString* dynamicX, NSString* dynamicY, CGFloat width, CGFloat height);
|
||||
|
||||
NSMutableDictionary* createGamepadButton(NSString* name, int gamepad_button, int keycode);
|
||||
UIColor* convertARGB2UIColor(int argb);
|
||||
int convertUIColor2ARGB(UIColor* color);
|
||||
int convertUIColor2RGB(UIColor* color);
|
||||
|
||||
@@ -311,7 +311,7 @@ void generateAndSaveDefaultControl() {
|
||||
}
|
||||
|
||||
void generateAndSaveDefaultControlForGamepad() {
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/gamepad-default.json", getenv("POJAV_HOME")];
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/default.json", getenv("POJAV_HOME")];
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:gamepadPath]) {
|
||||
return;
|
||||
}
|
||||
@@ -345,7 +345,7 @@ void generateAndSaveDefaultControlForGamepad() {
|
||||
[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[@"mGameMappingList"] addObject:createGamepadButton(@"thumb_right", GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, GLFW_KEY_LEFT_SHIFT)];
|
||||
|
||||
dict[@"mMenuMappingList"] = [[NSMutableArray alloc] init];
|
||||
|
||||
@@ -356,15 +356,25 @@ void generateAndSaveDefaultControlForGamepad() {
|
||||
[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(@"trigger_left", GLFW_GAMEPAD_BUTTON_LEFT_TRIGGER, GLFW_KEY_UNKNOWN)];
|
||||
[dict[@"mMenuMappingList"] addObject:createGamepadButton(@"trigger_right", GLFW_GAMEPAD_BUTTON_RIGHT_TRIGGER, GLFW_KEY_UNKNOWN)];
|
||||
|
||||
[dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_back", GLFW_GAMEPAD_BUTTON_BACK, GLFW_KEY_UNKNOWN)];
|
||||
[dict[@"mMenuMappingList"] addObject:createGamepadButton(@"named_start", GLFW_GAMEPAD_BUTTON_START, GLFW_KEY_UNKNOWN)];
|
||||
|
||||
[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_up", GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_KEY_UNKNOWN)];
|
||||
[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)];
|
||||
|
||||
[dict[@"mMenuMappingList"] addObject:createGamepadButton(@"thumb_left", GLFW_GAMEPAD_BUTTON_LEFT_THUMB, GLFW_KEY_UNKNOWN)];
|
||||
[dict[@"mMenuMappingList"] addObject:createGamepadButton(@"thumb_right", GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, GLFW_KEY_UNKNOWN)];
|
||||
|
||||
NSOutputStream *os = [[NSOutputStream alloc] initToFileAtPath:gamepadPath append:NO];
|
||||
[os open];
|
||||
[NSJSONSerialization writeJSONObject:dict toStream:os options:NSJSONWritingPrettyPrinted error:nil];
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
|
||||
"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.";
|
||||
"preference.title.default_gamepad_ctrl" = "Controller configuration";
|
||||
"preference.title.hardware_hide" = "Hide controls when hardware is connected";
|
||||
"preference.detail.hardware_hide" = "Enable the behaviour of automatically disabling the on-screen control overlay when a mouse or game controller is connected.";
|
||||
"preference.title.gesture_mouse" = "Mouse gestures";
|
||||
@@ -232,3 +233,49 @@
|
||||
"preference.detail.debug_show_layout_bounds" = "Show clip bounds, margins";
|
||||
"preference.title.debug_show_layout_overlap" = "Show layout overlapping";
|
||||
"preference.detail.debug_show_layout_overlap" = "Overlay every view with a transparent color to reveal overlapping views.";
|
||||
|
||||
"controller_configurator.title.current" = "Gamepad configuration file";
|
||||
"controller_configurator.title.type.xbox" = "Xbox";
|
||||
"controller_configurator.title.type.playstation" = "PlayStation";
|
||||
|
||||
"controller_configurator.xbox.title.bumper_left" = "Left bumper";
|
||||
"controller_configurator.xbox.title.bumper_right" = "Right bumper";
|
||||
"controller_configurator.xbox.title.trigger_left" = "Left trigger";
|
||||
"controller_configurator.xbox.title.trigger_right" = "Right trigger";
|
||||
"controller_configurator.xbox.title.named_back" = "Guide";
|
||||
"controller_configurator.xbox.title.named_start" = "Menu";
|
||||
"controller_configurator.xbox.title.named_a" = "A";
|
||||
"controller_configurator.xbox.title.named_b" = "B";
|
||||
"controller_configurator.xbox.title.named_x" = "X";
|
||||
"controller_configurator.xbox.title.named_y" = "Y";
|
||||
"controller_configurator.xbox.title.dpad_up" = "Up";
|
||||
"controller_configurator.xbox.title.dpad_down" = "Down";
|
||||
"controller_configurator.xbox.title.dpad_left" = "Left";
|
||||
"controller_configurator.xbox.title.dpad_right" = "Right";
|
||||
"controller_configurator.xbox.title.thumb_left" = "Left thumbstick click";
|
||||
"controller_configurator.xbox.title.thumb_right" = "Right thumbstick click";
|
||||
|
||||
"controller_configurator.playstation.title.bumper_left" = "L1";
|
||||
"controller_configurator.playstation.title.bumper_right" = "R1";
|
||||
"controller_configurator.playstation.title.trigger_left" = "L2";
|
||||
"controller_configurator.playstation.title.trigger_right" = "R2";
|
||||
"controller_configurator.playstation.title.named_back" = "Select";
|
||||
"controller_configurator.playstation.title.named_start" = "Start";
|
||||
"controller_configurator.playstation.title.named_a" = "Cross";
|
||||
"controller_configurator.playstation.title.named_b" = "Circle";
|
||||
"controller_configurator.playstation.title.named_x" = "Square";
|
||||
"controller_configurator.playstation.title.named_y" = "Triangle";
|
||||
"controller_configurator.playstation.title.dpad_up" = "Up";
|
||||
"controller_configurator.playstation.title.dpad_down" = "Down";
|
||||
"controller_configurator.playstation.title.dpad_left" = "Left";
|
||||
"controller_configurator.playstation.title.dpad_right" = "Right";
|
||||
"controller_configurator.playstation.title.thumb_left" = "L3";
|
||||
"controller_configurator.playstation.title.thumb_right" = "R3";
|
||||
|
||||
"controller_configurator.section.config_files" = "Current configuration file";
|
||||
"controller_configurator.section.game_mappings" = "Game mappings";
|
||||
"controller_configurator.section.footer.game_mappings" = "Bindings when the mouse is locked in game.";
|
||||
"controller_configurator.section.menu_mappings" = "Menu mappings";
|
||||
"controller_configurator.section.footer.menu_mappings" = "Bindings when the mouse is not locked, such as on the title screen or in the pause menu.";
|
||||
"controller_configurator.section.controller_style" = "Controller type";
|
||||
"controller_configurator.section.footer.controller_style" = "Show different controller button names in this configurator.";
|
||||
@@ -30,7 +30,7 @@ BOOL leftShiftHeld;
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/gamepad-%@", getenv("POJAV_HOME"), getPreference(@"default_gamepad_ctrl")];
|
||||
NSString *gamepadPath = [NSString stringWithFormat:@"%s/controlmap/gamepads/%@", getenv("POJAV_HOME"), getPreference(@"default_gamepad_ctrl")];
|
||||
NSMutableDictionary *gamepadJSON = parseJSONFromFile(gamepadPath);
|
||||
|
||||
gameMap = gamepadJSON[@"mGameMappingList"];
|
||||
|
||||
@@ -7,4 +7,5 @@ UIAlertController* createLoadingAlert(NSString* message);
|
||||
jstring UIKit_accessClipboard(JNIEnv* env, jint action, jstring copySrc);
|
||||
void UIKit_updateProgress(float progress, const char* message);
|
||||
void UIKit_launchMinecraftSurfaceVC();
|
||||
void UIKit_returnToSplitView();
|
||||
void launchInitialViewController(UIWindow *window);
|
||||
@@ -124,6 +124,26 @@ void UIKit_launchMinecraftSurfaceVC() {
|
||||
});
|
||||
}
|
||||
|
||||
void UIKit_returnToSplitView() {
|
||||
// Researching memory-safe ways to return from SurfaceViewController to the split view
|
||||
// so that the app doesn't close when quitting the game (similar behaviour to Android)
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIWindow *window = currentWindow();
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
window.alpha = 0;
|
||||
} completion:^(BOOL b){
|
||||
[window resignKeyWindow];
|
||||
window.alpha = 1;
|
||||
if (@available(iOS 14.0, tvOS 14.0, *)) {
|
||||
window.rootViewController = [[LauncherSplitViewController alloc] initWithStyle:UISplitViewControllerStyleDoubleColumn];
|
||||
} else {
|
||||
window.rootViewController = [[LauncherSplitViewController alloc] init];
|
||||
}
|
||||
[window makeKeyAndVisible];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
void launchInitialViewController(UIWindow *window) {
|
||||
if ([getPreference(@"internal_launch_on_boot") boolValue]) {
|
||||
window.rootViewController = [[SurfaceViewController alloc] init];
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SurfaceViewController.h"
|
||||
#import "ios_uikit_bridge.h"
|
||||
#import "utils.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
@@ -50,7 +51,7 @@ void* hooked_dlopen(const char* path, int mode) {
|
||||
void hooked_exit(int code) {
|
||||
NSLog(@"exit(%d) called", code);
|
||||
if (code == 0) {
|
||||
orig_exit(code);
|
||||
UIKit_returnToSplitView();
|
||||
return;
|
||||
}
|
||||
handle_fatal_exit(code);
|
||||
@@ -59,7 +60,7 @@ void hooked_exit(int code) {
|
||||
(*runtimeJavaVMPtr)->DestroyJavaVM(runtimeJavaVMPtr);
|
||||
}
|
||||
|
||||
orig_exit(code);
|
||||
UIKit_returnToSplitView();
|
||||
}
|
||||
|
||||
int hooked_open(const char *path, int oflag, ...) {
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,268 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>GLFW_KEY_UNKNOWN</key>
|
||||
<integer>0</integer>
|
||||
<key>GLFW_KEY_SPACE</key>
|
||||
<integer>32</integer>
|
||||
<key>GLFW_KEY_APOSTROPHE</key>
|
||||
<integer>39</integer>
|
||||
<key>GLFW_KEY_COMMA</key>
|
||||
<integer>44</integer>
|
||||
<key>GLFW_KEY_MINUS</key>
|
||||
<integer>45</integer>
|
||||
<key>GLFW_KEY_PERIOD</key>
|
||||
<integer>46</integer>
|
||||
<key>GLFW_KEY_SLASH</key>
|
||||
<integer>47</integer>
|
||||
<key>GLFW_KEY_0</key>
|
||||
<integer>48</integer>
|
||||
<key>GLFW_KEY_1</key>
|
||||
<integer>49</integer>
|
||||
<key>GLFW_KEY_2</key>
|
||||
<integer>50</integer>
|
||||
<key>GLFW_KEY_3</key>
|
||||
<integer>51</integer>
|
||||
<key>GLFW_KEY_4</key>
|
||||
<integer>52</integer>
|
||||
<key>GLFW_KEY_5</key>
|
||||
<integer>53</integer>
|
||||
<key>GLFW_KEY_6</key>
|
||||
<integer>54</integer>
|
||||
<key>GLFW_KEY_7</key>
|
||||
<integer>55</integer>
|
||||
<key>GLFW_KEY_8</key>
|
||||
<integer>56</integer>
|
||||
<key>GLFW_KEY_9</key>
|
||||
<integer>57</integer>
|
||||
<key>GLFW_KEY_SEMICOLON</key>
|
||||
<integer>59</integer>
|
||||
<key>GLFW_KEY_EQUAL</key>
|
||||
<integer>61</integer>
|
||||
<key>GLFW_KEY_A</key>
|
||||
<integer>65</integer>
|
||||
<key>GLFW_KEY_B</key>
|
||||
<integer>66</integer>
|
||||
<key>GLFW_KEY_C</key>
|
||||
<integer>67</integer>
|
||||
<key>GLFW_KEY_D</key>
|
||||
<integer>68</integer>
|
||||
<key>GLFW_KEY_E</key>
|
||||
<integer>69</integer>
|
||||
<key>GLFW_KEY_F</key>
|
||||
<integer>70</integer>
|
||||
<key>GLFW_KEY_G</key>
|
||||
<integer>71</integer>
|
||||
<key>GLFW_KEY_H</key>
|
||||
<integer>72</integer>
|
||||
<key>GLFW_KEY_I</key>
|
||||
<integer>73</integer>
|
||||
<key>GLFW_KEY_J</key>
|
||||
<integer>74</integer>
|
||||
<key>GLFW_KEY_K</key>
|
||||
<integer>75</integer>
|
||||
<key>GLFW_KEY_L</key>
|
||||
<integer>76</integer>
|
||||
<key>GLFW_KEY_M</key>
|
||||
<integer>77</integer>
|
||||
<key>GLFW_KEY_N</key>
|
||||
<integer>78</integer>
|
||||
<key>GLFW_KEY_O</key>
|
||||
<integer>79</integer>
|
||||
<key>GLFW_KEY_P</key>
|
||||
<integer>80</integer>
|
||||
<key>GLFW_KEY_Q</key>
|
||||
<integer>81</integer>
|
||||
<key>GLFW_KEY_R</key>
|
||||
<integer>82</integer>
|
||||
<key>GLFW_KEY_S</key>
|
||||
<integer>83</integer>
|
||||
<key>GLFW_KEY_T</key>
|
||||
<integer>84</integer>
|
||||
<key>GLFW_KEY_U</key>
|
||||
<integer>85</integer>
|
||||
<key>GLFW_KEY_V</key>
|
||||
<integer>86</integer>
|
||||
<key>GLFW_KEY_W</key>
|
||||
<integer>87</integer>
|
||||
<key>GLFW_KEY_X</key>
|
||||
<integer>88</integer>
|
||||
<key>GLFW_KEY_Y</key>
|
||||
<integer>89</integer>
|
||||
<key>GLFW_KEY_Z</key>
|
||||
<integer>90</integer>
|
||||
<key>GLFW_KEY_LEFT_BRACKET</key>
|
||||
<integer>91</integer>
|
||||
<key>GLFW_KEY_BACKSLASH</key>
|
||||
<integer>92</integer>
|
||||
<key>GLFW_KEY_RIGHT_BRACKET</key>
|
||||
<integer>93</integer>
|
||||
<key>GLFW_KEY_GRAVE_ACCENT</key>
|
||||
<integer>96</integer>
|
||||
<key>GLFW_KEY_WORLD_1</key>
|
||||
<integer>161</integer>
|
||||
<key>GLFW_KEY_WORLD_2</key>
|
||||
<integer>162</integer>
|
||||
<key>GLFW_KEY_ESCAPE</key>
|
||||
<integer>256</integer>
|
||||
<key>GLFW_KEY_ENTER</key>
|
||||
<integer>257</integer>
|
||||
<key>GLFW_KEY_TAB</key>
|
||||
<integer>258</integer>
|
||||
<key>GLFW_KEY_BACKSPACE</key>
|
||||
<integer>259</integer>
|
||||
<key>GLFW_KEY_INSERT</key>
|
||||
<integer>260</integer>
|
||||
<key>GLFW_KEY_DELETE</key>
|
||||
<integer>261</integer>
|
||||
<key>GLFW_KEY_DPAD_RIGHT</key>
|
||||
<integer>262</integer>
|
||||
<key>GLFW_KEY_DPAD_LEFT</key>
|
||||
<integer>263</integer>
|
||||
<key>GLFW_KEY_DPAD_DOWN</key>
|
||||
<integer>264</integer>
|
||||
<key>GLFW_KEY_DPAD_UP</key>
|
||||
<integer>265</integer>
|
||||
<key>GLFW_KEY_PAGE_UP</key>
|
||||
<integer>266</integer>
|
||||
<key>GLFW_KEY_PAGE_DOWN</key>
|
||||
<integer>267</integer>
|
||||
<key>GLFW_KEY_HOME</key>
|
||||
<integer>268</integer>
|
||||
<key>GLFW_KEY_END</key>
|
||||
<integer>269</integer>
|
||||
<key>GLFW_KEY_CAPS_LOCK</key>
|
||||
<integer>280</integer>
|
||||
<key>GLFW_KEY_SCROLL_LOCK</key>
|
||||
<integer>281</integer>
|
||||
<key>GLFW_KEY_NUM_LOCK</key>
|
||||
<integer>282</integer>
|
||||
<key>GLFW_KEY_PRINT_SCREEN</key>
|
||||
<integer>283</integer>
|
||||
<key>GLFW_KEY_PAUSE</key>
|
||||
<integer>284</integer>
|
||||
<key>GLFW_KEY_F1</key>
|
||||
<integer>290</integer>
|
||||
<key>GLFW_KEY_F2</key>
|
||||
<integer>291</integer>
|
||||
<key>GLFW_KEY_F3</key>
|
||||
<integer>292</integer>
|
||||
<key>GLFW_KEY_F4</key>
|
||||
<integer>293</integer>
|
||||
<key>GLFW_KEY_F5</key>
|
||||
<integer>294</integer>
|
||||
<key>GLFW_KEY_F6</key>
|
||||
<integer>295</integer>
|
||||
<key>GLFW_KEY_F7</key>
|
||||
<integer>296</integer>
|
||||
<key>GLFW_KEY_F8</key>
|
||||
<integer>297</integer>
|
||||
<key>GLFW_KEY_F9</key>
|
||||
<integer>298</integer>
|
||||
<key>GLFW_KEY_F10</key>
|
||||
<integer>299</integer>
|
||||
<key>GLFW_KEY_F11</key>
|
||||
<integer>300</integer>
|
||||
<key>GLFW_KEY_F12</key>
|
||||
<integer>301</integer>
|
||||
<key>GLFW_KEY_F13</key>
|
||||
<integer>302</integer>
|
||||
<key>GLFW_KEY_F14</key>
|
||||
<integer>303</integer>
|
||||
<key>GLFW_KEY_F15</key>
|
||||
<integer>304</integer>
|
||||
<key>GLFW_KEY_F16</key>
|
||||
<integer>305</integer>
|
||||
<key>GLFW_KEY_F17</key>
|
||||
<integer>306</integer>
|
||||
<key>GLFW_KEY_F18</key>
|
||||
<integer>307</integer>
|
||||
<key>GLFW_KEY_F19</key>
|
||||
<integer>308</integer>
|
||||
<key>GLFW_KEY_F20</key>
|
||||
<integer>309</integer>
|
||||
<key>GLFW_KEY_F21</key>
|
||||
<integer>310</integer>
|
||||
<key>GLFW_KEY_F22</key>
|
||||
<integer>311</integer>
|
||||
<key>GLFW_KEY_F23</key>
|
||||
<integer>312</integer>
|
||||
<key>GLFW_KEY_F24</key>
|
||||
<integer>313</integer>
|
||||
<key>GLFW_KEY_F25</key>
|
||||
<integer>314</integer>
|
||||
<key>GLFW_KEY_NUMPAD_0</key>
|
||||
<integer>320</integer>
|
||||
<key>GLFW_KEY_NUMPAD_1</key>
|
||||
<integer>321</integer>
|
||||
<key>GLFW_KEY_NUMPAD_2</key>
|
||||
<integer>322</integer>
|
||||
<key>GLFW_KEY_NUMPAD_3</key>
|
||||
<integer>323</integer>
|
||||
<key>GLFW_KEY_NUMPAD_4</key>
|
||||
<integer>324</integer>
|
||||
<key>GLFW_KEY_NUMPAD_5</key>
|
||||
<integer>325</integer>
|
||||
<key>GLFW_KEY_NUMPAD_6</key>
|
||||
<integer>326</integer>
|
||||
<key>GLFW_KEY_NUMPAD_7</key>
|
||||
<integer>327</integer>
|
||||
<key>GLFW_KEY_NUMPAD_8</key>
|
||||
<integer>328</integer>
|
||||
<key>GLFW_KEY_NUMPAD_9</key>
|
||||
<integer>329</integer>
|
||||
<key>GLFW_KEY_NUMPAD_DECIMAL</key>
|
||||
<integer>330</integer>
|
||||
<key>GLFW_KEY_NUMPAD_DIVIDE</key>
|
||||
<integer>331</integer>
|
||||
<key>GLFW_KEY_NUMPAD_MULTIPLY</key>
|
||||
<integer>332</integer>
|
||||
<key>GLFW_KEY_NUMPAD_SUBTRACT</key>
|
||||
<integer>333</integer>
|
||||
<key>GLFW_KEY_NUMPAD_ADD</key>
|
||||
<integer>334</integer>
|
||||
<key>GLFW_KEY_NUMPAD_ENTER</key>
|
||||
<integer>335</integer>
|
||||
<key>GLFW_KEY_NUMPAD_EQUAL</key>
|
||||
<integer>336</integer>
|
||||
<key>GLFW_KEY_LEFT_SHIFT</key>
|
||||
<integer>340</integer>
|
||||
<key>GLFW_KEY_LEFT_CONTROL</key>
|
||||
<integer>341</integer>
|
||||
<key>GLFW_KEY_LEFT_ALT</key>
|
||||
<integer>342</integer>
|
||||
<key>GLFW_KEY_LEFT_SUPER</key>
|
||||
<integer>343</integer>
|
||||
<key>GLFW_KEY_RIGHT_SHIFT</key>
|
||||
<integer>344</integer>
|
||||
<key>GLFW_KEY_RIGHT_CONTROL</key>
|
||||
<integer>345</integer>
|
||||
<key>GLFW_KEY_RIGHT_ALT</key>
|
||||
<integer>346</integer>
|
||||
<key>GLFW_KEY_RIGHT_SUPER</key>
|
||||
<integer>347</integer>
|
||||
<key>GLFW_KEY_MENU</key>
|
||||
<integer>348</integer>
|
||||
<key>GLFW_KEY_LAST</key>
|
||||
<integer>348</integer>
|
||||
<key>SPECIALBTN_KEYBOARD</key>
|
||||
<integer>-1</integer>
|
||||
<key>SPECIALBTN_TOGGLECTRL</key>
|
||||
<integer>-2</integer>
|
||||
<key>SPECIALBTN_MOUSEPRI</key>
|
||||
<integer>-3</integer>
|
||||
<key>SPECIALBTN_MOUSESEC</key>
|
||||
<integer>-4</integer>
|
||||
<key>SPECIALBTN_VIRTUALMOUSE</key>
|
||||
<integer>-5</integer>
|
||||
<key>SPECIALBTN_MOUSEMID</key>
|
||||
<integer>-6</integer>
|
||||
<key>SPECIALBTN_SCROLLUP</key>
|
||||
<integer>-7</integer>
|
||||
<key>SPECIALBTN_SCROLLDOWN</key>
|
||||
<integer>-8</integer>
|
||||
<key>SPECIALBTN_MENU</key>
|
||||
<integer>-9</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
Reference in new issue
Block a user