LCOV - code coverage report
Current view: top level - Core/Entities - PlayerEntityKeyMapper.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 57 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : PlayerEntityKeyMapper.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2019 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */ 
      24             : 
      25             : #import "PlayerEntityKeyMapper.h"
      26             : #import "PlayerEntityControls.h"
      27             : #import "PlayerEntityScriptMethods.h"
      28             : #import "OOTexture.h"
      29             : #import "OOCollectionExtractors.h"
      30             : #import "HeadUpDisplay.h"
      31             : #import "ResourceManager.h"
      32             : #import "GameController.h"
      33             : #import "OOEquipmentType.h"
      34             : 
      35           0 : static NSUInteger key_index;
      36           0 : static long current_row;
      37           0 : static long kbd_row = GUI_ROW_KC_FUNCSTART;
      38           0 : static BOOL has_error = NO;
      39           0 : static BOOL last_shift = NO;
      40           0 : static NSDictionary *selected_entry = nil;
      41           0 : static NSMutableArray *key_list = nil;
      42           0 : static NSDictionary *kdic_check = nil;
      43           0 : static NSArray *nav_keys = nil;
      44           0 : static NSArray *camera_keys = nil;
      45             : 
      46             : @interface PlayerEntity (KeyMapperInternal)
      47             : 
      48           0 : - (void)resetKeyFunctions;
      49           0 : - (void)updateKeyDefinition:(NSString *)keystring index:(NSUInteger)index;
      50           0 : - (void)updateShiftKeyDefinition:(NSString *)key index:(NSUInteger)index;
      51           0 : - (void)displayKeyFunctionList:(GuiDisplayGen *)gui skip:(NSUInteger)skip;
      52           0 : - (NSString *)keyboardDescription:(NSString *)kbd;
      53           0 : - (void)displayKeyboardLayoutList:(GuiDisplayGen *)gui skip:(NSUInteger)skip;
      54           0 : - (BOOL)entryIsIndexCustomEquip:(NSUInteger)idx;
      55           0 : - (BOOL)entryIsDictCustomEquip:(NSDictionary *)dict;
      56           0 : - (BOOL)entryIsCustomEquip:(NSString *)entry;
      57           0 : - (NSArray *)getCustomEquipArray:(NSString *)key_def;
      58           0 : - (NSString *)getCustomEquipKeyDefType:(NSString *)key_def;
      59           0 : - (NSArray *)keyFunctionList;
      60           0 : - (NSArray *)validateAllKeys;
      61           0 : - (NSString *)searchArrayForMatch:(NSArray *)search_list key:(NSString *)key checkKeys:(NSArray *)check_keys;
      62           0 : - (NSUInteger)getCustomEquipIndex:(NSString *)key_def;
      63           0 : - (BOOL)entryIsEqualToDefault:(NSString *)key;
      64           0 : - (BOOL)compareKeyEntries:(NSDictionary *)first second:(NSDictionary *)second;
      65           0 : - (void)saveKeySetting:(NSString *)key;
      66           0 : - (void)unsetKeySetting:(NSString *)key;
      67           0 : - (void)deleteKeySetting:(NSString *)key;
      68           0 : - (void)deleteAllKeySettings;
      69           0 : - (NSDictionary *)loadKeySettings;
      70           0 : - (void) reloadPage;
      71             : 
      72             : @end
      73             : 
      74             : @implementation PlayerEntity (KeyMapper)
      75             : 
      76             : // sets up a copy of the raw keyconfig.plist file so we can run checks against it to tell if a key is set to default
      77             : - (void) initCheckingDictionary
      78             : {
      79             :         NSMutableDictionary *kdicmaster = [NSMutableDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:@"keyconfig2.plist" inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
      80             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      81             :         NSString *kbd = [defaults oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
      82             :         NSMutableDictionary *kdic = [NSMutableDictionary dictionaryWithDictionary:[kdicmaster objectForKey:kbd]];
      83             : 
      84             :         NSUInteger i;
      85             :         NSArray *keys = nil;
      86             :         id key = nil;
      87             :         NSArray *def_list = nil;
      88             : 
      89             :         keys = [kdic allKeys];
      90             :         for (i = 0; i < [keys count]; i++)
      91             :         {
      92             :                 key = [keys objectAtIndex:i];
      93             : 
      94             :                 if ([[kdic objectForKey: key] isKindOfClass:[NSArray class]])
      95             :                 {
      96             :                         def_list = (NSArray*)[kdic objectForKey: key];
      97             :                         [kdic setObject:[self processKeyCode:def_list] forKey:key];
      98             :                 }
      99             :         }
     100             :         [kdic_check release];
     101             :         kdic_check = [[NSDictionary alloc] initWithDictionary:kdic];
     102             : 
     103             :         // these keys can't be used with mod keys
     104             :         [nav_keys release];
     105             :         nav_keys = [[NSArray alloc] initWithObjects:@"key_roll_left", @"key_roll_right", @"key_pitch_forward", @"key_pitch_back", @"key_yaw_left", @"key_yaw_right", 
     106             :                 @"key_fire_lasers", @"key_gui_arrow_up", @"key_gui_arrow_down", @"key_gui_arrow_right", @"key_gui_arrow_left", nil];
     107             :         // these keys can't be used with ctrl
     108             :         [camera_keys release];
     109             :         camera_keys = [[NSArray alloc] initWithObjects:@"key_custom_view_zoom_out", @"key_custom_view_zoom_in", @"key_custom_view_roll_left", @"key_custom_view_roll_right",
     110             :                 @"key_custom_view_pan_left", @"key_custom_view_pan_right", @"key_custom_view_rotate_up", @"key_custom_view_rotate_down", @"key_custom_view_pan_down",
     111             :                 @"key_custom_view_pan_up", @"key_custom_view_rotate_left", @"key_custom_view_rotate_right", nil];
     112             : }
     113             : 
     114             : 
     115             : - (void) resetKeyFunctions
     116             : {
     117             :         [keyFunctions release];
     118             :         keyFunctions = nil;
     119             : }
     120             : 
     121             : 
     122             : - (void) setGuiToKeyMapperScreen:(unsigned)skip
     123             : {
     124             :         [self setGuiToKeyMapperScreen:skip resetCurrentRow:NO];
     125             : }
     126             : 
     127             : - (void) setGuiToKeyMapperScreen:(unsigned)skip resetCurrentRow:(BOOL)resetCurrentRow
     128             : {
     129             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     130             :         NSString *kbd = [defaults oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
     131             : 
     132             :         GuiDisplayGen *gui = [UNIVERSE gui];
     133             :         MyOpenGLView *gameView = [UNIVERSE gameView];
     134             :         OOGUIScreenID oldScreen = gui_screen;
     135             :         OOGUITabStop tabStop[GUI_MAX_COLUMNS];
     136             :         tabStop[0] = 10;
     137             :         tabStop[1] = 290;
     138             :         tabStop[2] = 400;
     139             :         [gui setTabStops:tabStop];
     140             : 
     141             :         if (!kdic_check) [self initCheckingDictionary];
     142             : 
     143             :         gui_screen = GUI_SCREEN_KEYBOARD;
     144             :         BOOL guiChanged = (oldScreen != gui_screen);
     145             :         [[UNIVERSE gameController] setMouseInteractionModeForUIWithMouseInteraction:YES];
     146             : 
     147             :         [gui clear];
     148             :         [gui setTitle:[NSString stringWithFormat:@"Configure Keyboard"]];
     149             : 
     150             :         // show keyboard layout
     151             :         [gui setArray:[NSArray arrayWithObjects:DESC(@"oolite-keyconfig-keyboard"), [self keyboardDescription:kbd], nil] forRow:GUI_ROW_KC_SELECTKBD];
     152             :         [gui setKey:[NSString stringWithFormat:@"kbd:%@", kbd] forRow:GUI_ROW_KC_SELECTKBD];
     153             :         [gui setColor:[OOColor yellowColor] forRow:GUI_ROW_KC_SELECTKBD];
     154             : 
     155             :         [self displayKeyFunctionList:gui skip:skip];
     156             : 
     157             :         has_error = NO;
     158             :         if ([[self validateAllKeys] count] > 0)
     159             :         {
     160             :                 has_error = YES;
     161             :                 [gui setText:DESC(@"oolite-keyconfig-validation-error") forRow:GUI_ROW_KC_ERROR align:GUI_ALIGN_CENTER];
     162             :                 [gui setColor:[OOColor redColor] forRow:GUI_ROW_KC_ERROR];
     163             : 
     164             :         }
     165             :         [gui setArray:[NSArray arrayWithObject:DESC(@"oolite-keyconfig-initial-info-1")] forRow:GUI_ROW_KC_INSTRUCT];
     166             :         [gui setText:DESC(@"oolite-keyconfig-initial-info-2") forRow:GUI_ROW_KC_INSTRUCT+1 align:GUI_ALIGN_CENTER];
     167             :         if (has_error)
     168             :         {
     169             :                 [gui setText:DESC(@"oolite-keyconfig-initial-error") forRow:GUI_ROW_KC_INSTRUCT+2 align:GUI_ALIGN_CENTER];
     170             :         }
     171             :         else
     172             :         {
     173             :                 [gui setText:DESC(@"oolite-keyconfig-initial-info-3") forRow:GUI_ROW_KC_INSTRUCT+2 align:GUI_ALIGN_CENTER];
     174             :         }
     175             : 
     176             :         if (resetCurrentRow)
     177             :         {
     178             :                 int offset = 0;
     179             :                 if ([[keyFunctions objectAtIndex:skip] objectForKey:KEY_KC_HEADER]) offset = 1;
     180             :                 [gui setSelectedRow:GUI_ROW_KC_FUNCSTART + offset];
     181             :         }
     182             :         else 
     183             :         {
     184             :                 [gui setSelectedRow:current_row];
     185             :         }
     186             : 
     187             :         [gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
     188             :         [gui setBackgroundTextureKey:@"keyboardsettings"];
     189             : 
     190             :         [gameView clearMouse];
     191             :         [gameView clearKeys];
     192             :         [UNIVERSE enterGUIViewModeWithMouseInteraction:YES];
     193             : 
     194             :         if (guiChanged) [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
     195             : }
     196             : 
     197             : 
     198             : - (void) keyMapperInputHandler:(GuiDisplayGen *)gui view:(MyOpenGLView *)gameView
     199             : {
     200             :         [self handleGUIUpDownArrowKeys];
     201             :         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]);
     202             :         if ([gameView isDown:gvMouseDoubleClick])  [gameView clearMouse];
     203             : 
     204             :         NSString *key = [gui keyForRow: [gui selectedRow]];
     205             :         if ([key hasPrefix:@"Index:"])
     206             :                 selFunctionIdx=[[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
     207             :         else
     208             :                 selFunctionIdx=-1;
     209             : 
     210             :         if (selectKeyPress)
     211             :         {
     212             :                 if ([key hasPrefix:@"More:"])
     213             :                 {
     214             :                         int from_function = [[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
     215             :                         if (from_function < 0)  from_function = 0;
     216             : 
     217             :                         current_row = GUI_ROW_KC_FUNCSTART;
     218             :                         if (from_function == 0) current_row = GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1;
     219             :                         [self setGuiToKeyMapperScreen:from_function];
     220             :                         if ([gameView isDown:gvMouseDoubleClick]) [gameView clearMouse];
     221             :                         return;
     222             :                 }
     223             :                 if ([key hasPrefix:@"kbd:"])
     224             :                 {
     225             :                         [self setGuiToKeyboardLayoutScreen:0];
     226             :                         if ([gameView isDown:gvMouseDoubleClick]) [gameView clearMouse];
     227             :                         return;
     228             :                 }
     229             :                 current_row = [gui selectedRow];
     230             :                 selected_entry = [keyFunctions objectAtIndex:selFunctionIdx];
     231             :                 [key_list release];
     232             :                 if (![self entryIsDictCustomEquip:selected_entry]) 
     233             :                 {
     234             :                         key_list = [[NSMutableArray alloc] initWithArray:(NSArray *)[keyconfig2_settings objectForKey:[selected_entry objectForKey:KEY_KC_DEFINITION]] copyItems:YES];
     235             :                 }
     236             :                 else 
     237             :                 {
     238             :                         key_list = [[NSMutableArray alloc] initWithArray:[self getCustomEquipArray:[selected_entry oo_stringForKey:KEY_KC_DEFINITION]]];
     239             :                 }
     240             :                 [gameView clearKeys];   // try to stop key bounces
     241             :                 [self setGuiToKeyConfigScreen:YES];
     242             :         }
     243             : 
     244             :         if ([gameView isDown:'u'])
     245             :         {
     246             :                 // pressed 'u' on an "more" line
     247             :                 if ([key hasPrefix:@"More:"]) return;
     248             : 
     249             :                 current_row = [gui selectedRow];
     250             :                 [self unsetKeySetting:[[keyFunctions objectAtIndex:selFunctionIdx] objectForKey:KEY_KC_DEFINITION]];
     251             :                 [self reloadPage];
     252             :         }
     253             : 
     254             :         if ([gameView isDown:'r'])
     255             :         {
     256             :                 // reset single entry or all
     257             :                 if (![gameView isCtrlDown]) 
     258             :                 {
     259             :                         // pressed 'r' on an "more" line
     260             :                         if ([key hasPrefix:@"More:"]) return;
     261             : 
     262             :                         current_row = [gui selectedRow];
     263             :                         
     264             :                         NSString *delkey = [[keyFunctions objectAtIndex:selFunctionIdx] objectForKey:KEY_KC_DEFINITION];
     265             :                         [self deleteKeySetting:delkey];
     266             :                         // special case - when default activate/mode key set in custom equipment
     267             :                         if ([self entryIsCustomEquip:delkey]) 
     268             :                         {
     269             :                                 int idx = [self getCustomEquipIndex:delkey];
     270             :                                 NSString *eq = nil;
     271             :                                 NSString *lookupKey = nil;
     272             :                                 bool update = false;
     273             : 
     274             :                                 if ([delkey hasPrefix:@"activate_"]) 
     275             :                                 {
     276             :                                         eq = [delkey stringByReplacingOccurrencesOfString:@"activate_" withString:@""];
     277             :                                         lookupKey = CUSTOMEQUIP_KEYACTIVATE;
     278             :                                 }
     279             :                                 if ([delkey hasPrefix:@"mode_"]) 
     280             :                                 {
     281             :                                         eq = [delkey stringByReplacingOccurrencesOfString:@"mode_" withString:@""];
     282             :                                         lookupKey = CUSTOMEQUIP_KEYMODE;
     283             :                                 }
     284             : 
     285             :                                 OOEquipmentType *item = [OOEquipmentType equipmentTypeWithIdentifier:eq];
     286             :                                 
     287             :                                 if ([item defaultActivateKey] && [lookupKey isEqualToString:CUSTOMEQUIP_KEYACTIVATE]) 
     288             :                                 {
     289             :                                         [[customEquipActivation objectAtIndex:idx] setObject:[item defaultActivateKey] forKey:lookupKey];
     290             :                                         update = true;
     291             :                                 }
     292             :                                 if ([item defaultModeKey] && [lookupKey isEqualToString:CUSTOMEQUIP_KEYMODE]) 
     293             :                                 {
     294             :                                         [[customEquipActivation objectAtIndex:idx] setObject:[item defaultModeKey] forKey:lookupKey];
     295             :                                         update = true;
     296             :                                 }
     297             : 
     298             :                                 if (update) 
     299             :                                 {
     300             :                                         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     301             :                                         [defaults setObject:customEquipActivation forKey:KEYCONFIG_CUSTOMEQUIP];
     302             :                                 }
     303             :                         }
     304             :                         
     305             :                         [self reloadPage];
     306             :                 }
     307             :                 else
     308             :                 {
     309             :                         [self setGuiToConfirmClearScreen];
     310             :                 }
     311             :         }
     312             :         if ([gameView isDown:' '] && !has_error) [self setGuiToGameOptionsScreen];
     313             : }
     314             : 
     315             : 
     316           0 : - (BOOL) entryIsIndexCustomEquip:(NSUInteger)idx
     317             : {
     318             :         return [self entryIsCustomEquip:[[keyFunctions objectAtIndex:idx] oo_stringForKey:KEY_KC_DEFINITION]];
     319             : }
     320             : 
     321             : 
     322           0 : - (BOOL) entryIsDictCustomEquip:(NSDictionary *)dict
     323             : {
     324             :         return [self entryIsCustomEquip:[dict oo_stringForKey:KEY_KC_DEFINITION]];
     325             : }
     326             : 
     327           0 : - (BOOL) entryIsCustomEquip:(NSString *)entry
     328             : {
     329             :         BOOL result = NO;
     330             :         if ([entry hasPrefix:@"activate_"] || [entry hasPrefix:@"mode_"])
     331             :                 result = YES;
     332             :         return result;
     333             : }
     334             : 
     335           0 : - (NSArray *) getCustomEquipArray:(NSString *)key_def
     336             : {
     337             :         NSString *eq = nil;
     338             :         NSUInteger i;
     339             :         NSString *key;
     340             :         if ([key_def hasPrefix:@"activate_"]) 
     341             :         {
     342             :                 eq = [key_def stringByReplacingOccurrencesOfString:@"activate_" withString:@""];
     343             :                 key = CUSTOMEQUIP_KEYACTIVATE;
     344             :         }
     345             :         if ([key_def hasPrefix:@"mode_"]) 
     346             :         {
     347             :                 eq = [key_def stringByReplacingOccurrencesOfString:@"mode_" withString:@""];
     348             :                 key = CUSTOMEQUIP_KEYMODE;
     349             :         }
     350             :         if (eq == nil) return nil;
     351             :         for (i = 0; i < [customEquipActivation count]; i++)
     352             :         {
     353             :                 if ([[[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY] isEqualToString:eq])
     354             :                 {
     355             :                         return [[customEquipActivation objectAtIndex:i] oo_arrayForKey:key];
     356             :                 }
     357             :         }
     358             :         return nil;
     359             : }
     360             : 
     361             : 
     362           0 : - (NSUInteger) getCustomEquipIndex:(NSString *)key_def
     363             : {
     364             :         NSString *eq = nil;
     365             :         NSUInteger i;
     366             :         if ([key_def hasPrefix:@"activate_"]) 
     367             :         {
     368             :                 eq = [key_def stringByReplacingOccurrencesOfString:@"activate_" withString:@""];
     369             :         }
     370             :         if ([key_def hasPrefix:@"mode_"]) 
     371             :         {
     372             :                 eq = [key_def stringByReplacingOccurrencesOfString:@"mode_" withString:@""];
     373             :         }
     374             :         if (eq == nil) return -1;
     375             :         for (i = 0; i < [customEquipActivation count]; i++)
     376             :         {
     377             :                 if ([[[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY] isEqualToString:eq])
     378             :                 {
     379             :                         return i;
     380             :                 }
     381             :         }
     382             :         return -1;
     383             : }
     384             : 
     385             : 
     386           0 : - (NSString *) getCustomEquipKeyDefType:(NSString *)key_def
     387             : {
     388             :         if ([key_def hasPrefix:@"activate_"]) 
     389             :         {
     390             :                 return CUSTOMEQUIP_KEYACTIVATE;
     391             :         }
     392             :         if ([key_def hasPrefix:@"mode_"]) 
     393             :         {
     394             :                 return CUSTOMEQUIP_KEYMODE;
     395             :         }
     396             :         return @"";
     397             : }
     398             : 
     399             : 
     400             : - (void) setGuiToKeyConfigScreen
     401             : {
     402             :         [self setGuiToKeyConfigScreen:NO];
     403             : }
     404             : 
     405             : 
     406             : - (void) setGuiToKeyConfigScreen:(BOOL)resetSelectedRow
     407             : {
     408             :         NSUInteger i = 0;
     409             :         GuiDisplayGen *gui=[UNIVERSE gui];
     410             :         OOGUIScreenID oldScreen = gui_screen;
     411             :         OOGUITabStop tabStop[GUI_MAX_COLUMNS];
     412             :         tabStop[0] = 10;
     413             :         tabStop[1] = 290;
     414             :         [gui setTabStops:tabStop];
     415             : 
     416             :         gui_screen = GUI_SCREEN_KEYBOARD_CONFIG;
     417             :         BOOL guiChanged = (oldScreen != gui_screen);
     418             :         [gui clear];
     419             :         [gui setTitle:[NSString stringWithFormat:@"%@", DESC(@"oolite-keyconfig-update-title")]];
     420             : 
     421             :         [gui setArray: [NSArray arrayWithObjects: 
     422             :                                                                 DESC(@"oolite-keyconfig-update-function"), [selected_entry objectForKey: KEY_KC_GUIDESC], nil]
     423             :                                         forRow: GUI_ROW_KC_UPDATE_FUNCNAME];
     424             :         [gui setColor:[OOColor greenColor] forRow:GUI_ROW_KC_UPDATE_FUNCNAME];
     425             : 
     426             :         NSString *keystring = nil;
     427             :         NSString *keyshift = nil;
     428             :         NSString *keymod1 = nil;
     429             :         NSString *keymod2 = nil;
     430             : 
     431             :         NSDictionary *def = nil;
     432             :         NSString *key = nil;
     433             :         OOKeyCode k_int;
     434             : 
     435             :         // get each key for the first two item in the selected entry
     436             :         for (i = 0; i <= 1; i++)
     437             :         {
     438             :                 keystring = DESC(@"oolite-keycode-unset");
     439             :                 keyshift = DESC(@"oolite-keyconfig-modkey-off");
     440             :                 keymod1 = DESC(@"oolite-keyconfig-modkey-off");
     441             :                 keymod2 = DESC(@"oolite-keyconfig-modkey-off");
     442             : 
     443             :                 if ([key_list count] > i)
     444             :                 {
     445             :                         def = [key_list objectAtIndex:i];
     446             :                         key = [def objectForKey:@"key"];
     447             :                         k_int = (OOKeyCode)[key integerValue];
     448             :                         if (k_int > 0)
     449             :                         {
     450             :                                 keystring = [self keyCodeDescription:k_int];
     451             :                                 if ([[def objectForKey:@"shift"] boolValue] == YES) keyshift = DESC(@"oolite-keyconfig-modkey-on");
     452             :                                 if ([[def objectForKey:@"mod1"] boolValue] == YES) keymod1 = DESC(@"oolite-keyconfig-modkey-on");
     453             :                                 if ([[def objectForKey:@"mod2"] boolValue] == YES) keymod2 = DESC(@"oolite-keyconfig-modkey-on");
     454             :                         }
     455             :                 }
     456             : 
     457             :                 [self outputKeyDefinition:keystring shift:keyshift mod1:keymod1 mod2:keymod2 skiprows:(i * 5)];
     458             :         }
     459             : 
     460             :         NSString *helper = DESC(@"oolite-keyconfig-update-helper");
     461             :         if ([nav_keys containsObject:[selected_entry objectForKey: KEY_KC_DEFINITION]])
     462             :                 helper = [NSString stringWithFormat:@"%@ %@", helper, DESC(@"oolite-keyconfig-update-navkeys")];
     463             :         if ([camera_keys containsObject:[selected_entry objectForKey: KEY_KC_DEFINITION]])
     464             :                 helper = [NSString stringWithFormat:@"%@ %@", helper, DESC(@"oolite-keyconfig-update-camkeys")];
     465             :         [gui addLongText:helper startingAtRow:GUI_ROW_KC_UPDATE_INFO align:GUI_ALIGN_LEFT];
     466             : 
     467             :         [gui setText:@"" forRow:GUI_ROW_KC_VALIDATION];
     468             : 
     469             :         [gui setText:DESC(@"oolite-keyconfig-update-save") forRow:GUI_ROW_KC_SAVE align:GUI_ALIGN_CENTER];
     470             :         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_SAVE];
     471             :         
     472             :         [gui setText:DESC(@"oolite-keyconfig-update-cancel") forRow:GUI_ROW_KC_CANCEL align:GUI_ALIGN_CENTER];
     473             :         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_CANCEL];
     474             : 
     475             :         [gui setSelectableRange: NSMakeRange(GUI_ROW_KC_KEY, (GUI_ROW_KC_CANCEL - GUI_ROW_KC_KEY) + 1)];
     476             : 
     477             :         NSString *validate = [self validateKey:[selected_entry objectForKey:KEY_KC_DEFINITION] checkKeys:key_list];
     478             :         if (validate)
     479             :         {
     480             :                 for (i = 0; i < [keyFunctions count]; i++)
     481             :                 {
     482             :                         if ([[[keyFunctions objectAtIndex:i] objectForKey:KEY_KC_DEFINITION] isEqualToString:validate])
     483             :                         {
     484             :                                 [gui setText:[NSString stringWithFormat:DESC(@"oolite-keyconfig-update-validation-@"), (NSString *)[[keyFunctions objectAtIndex:i] objectForKey:KEY_KC_GUIDESC]] 
     485             :                                         forRow:GUI_ROW_KC_VALIDATION align:GUI_ALIGN_CENTER];
     486             :                                 [gui setColor:[OOColor orangeColor] forRow:GUI_ROW_KC_VALIDATION];
     487             :                                 break;
     488             :                         }
     489             :                 }
     490             :         }
     491             : 
     492             :         if (resetSelectedRow)
     493             :         {
     494             :                 [gui setSelectedRow: GUI_ROW_KC_KEY];
     495             :         }
     496             : 
     497             :         [gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
     498             :         [gui setBackgroundTextureKey:@"keyboardsettings"];
     499             :         [[UNIVERSE gameView] clearMouse];
     500             :         [[UNIVERSE gameView] clearKeys];
     501             :         if (guiChanged) [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
     502             : }
     503             : 
     504             : 
     505             : - (void) outputKeyDefinition:(NSString *)key shift:(NSString *)shift mod1:(NSString *)mod1 mod2:(NSString *)mod2 skiprows:(NSUInteger)skiprows
     506             : {
     507             :         GuiDisplayGen *gui=[UNIVERSE gui];
     508             : 
     509             :         [gui setArray:[NSArray arrayWithObjects: 
     510             :                                                                 (skiprows == 0 ? DESC(@"oolite-keyconfig-update-key") : DESC(@"oolite-keyconfig-update-alternate")), key, nil]
     511             :                                         forRow:GUI_ROW_KC_KEY + skiprows];
     512             :         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_KEY + skiprows];
     513             : 
     514             :         if (![nav_keys containsObject:[selected_entry objectForKey: KEY_KC_DEFINITION]]) {
     515             :                 if (![key isEqualToString:DESC(@"oolite-keycode-unset")])
     516             :                 {
     517             :                         [gui setArray:[NSArray arrayWithObjects: 
     518             :                                                                                 DESC(@"oolite-keyconfig-update-shift"), shift, nil]
     519             :                                                         forRow:GUI_ROW_KC_SHIFT + skiprows];
     520             :                         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_SHIFT + skiprows];
     521             : 
     522             :                         // camera movement keys can't use ctrl
     523             :                         if (![camera_keys containsObject:[selected_entry objectForKey: KEY_KC_DEFINITION]]) {
     524             :                                 [gui setArray:[NSArray arrayWithObjects: 
     525             :                                                                                         DESC(@"oolite-keyconfig-update-mod1"), mod1, nil]
     526             :                                                                 forRow:GUI_ROW_KC_MOD1 + skiprows];
     527             :                                 [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_MOD1 + skiprows];
     528             :                         } 
     529             :                         else 
     530             :                         {
     531             :                                 [gui setArray:[NSArray arrayWithObjects: 
     532             :                                                                                         DESC(@"oolite-keyconfig-update-mod1"), DESC(@"not-applicable"), nil]
     533             :                                                                 forRow:GUI_ROW_KC_MOD1 + skiprows];
     534             :                         }
     535             :                                         
     536             : #if OOLITE_MAC_OS_X
     537             :                         [gui setArray:[NSArray arrayWithObjects: 
     538             :                                                                                 DESC(@"oolite-keyconfig-update-mod2-mac"), mod2, nil]
     539             :                                                         forRow:GUI_ROW_KC_MOD2 + skiprows];
     540             : #else
     541             :                         [gui setArray:[NSArray arrayWithObjects: 
     542             :                                                                                 DESC(@"oolite-keyconfig-update-mod2-pc"), mod2, nil]
     543             :                                                         forRow: GUI_ROW_KC_MOD2 + skiprows];
     544             : #endif
     545             :                         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_MOD2 + skiprows];
     546             :                 }
     547             :         }
     548             : }
     549             : 
     550             : 
     551             : - (void) handleKeyConfigKeys:(GuiDisplayGen *)gui view:(MyOpenGLView *)gameView
     552             : {
     553             :         [self handleGUIUpDownArrowKeys];
     554             :         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]);
     555             :         if ([gameView isDown:gvMouseDoubleClick])  [gameView clearMouse];
     556             :         
     557             :         if (selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_KEY || [gui selectedRow] == (GUI_ROW_KC_KEY + 5)))
     558             :         {
     559             :                 key_index = ([gui selectedRow] == GUI_ROW_KC_KEY ? 0 : 1);
     560             :                 [self setGuiToKeyConfigEntryScreen];
     561             :         }
     562             : 
     563             :         if (selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_SHIFT || [gui selectedRow] == (GUI_ROW_KC_SHIFT + 5)))
     564             :         {
     565             :                 [self updateShiftKeyDefinition:@"shift" index:([gui selectedRow] == GUI_ROW_KC_SHIFT ? 0 : 1)];
     566             :                 [self setGuiToKeyConfigScreen];
     567             :         }
     568             :         if (selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_MOD1 || [gui selectedRow] == (GUI_ROW_KC_MOD1 + 5)))
     569             :         {
     570             :                 [self updateShiftKeyDefinition:@"mod1" index:([gui selectedRow] == GUI_ROW_KC_MOD1 ? 0 : 1)];
     571             :                 [self setGuiToKeyConfigScreen];
     572             :         }
     573             :         if (selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_MOD2 || [gui selectedRow] == (GUI_ROW_KC_MOD2 + 5)))
     574             :         {
     575             :                 [self updateShiftKeyDefinition:@"mod2" index:([gui selectedRow] == GUI_ROW_KC_MOD2 ? 0 : 1)];
     576             :                 [self setGuiToKeyConfigScreen];
     577             :         }
     578             : 
     579             :         if (selectKeyPress && [gui selectedRow] == GUI_ROW_KC_SAVE)
     580             :         {
     581             :                 [self saveKeySetting:[selected_entry objectForKey: KEY_KC_DEFINITION]];
     582             :                 [self reloadPage];
     583             :         }
     584             : 
     585             :         if ((selectKeyPress && [gui selectedRow] == GUI_ROW_KC_CANCEL) || [gameView isDown:27])
     586             :         {
     587             :                 // esc or Cancel was pressed - get out of here
     588             :                 [self reloadPage];
     589             :         }
     590             : }
     591             : 
     592             : 
     593             : - (void) setGuiToKeyConfigEntryScreen
     594             : {
     595             :         GuiDisplayGen *gui = [UNIVERSE gui];
     596             :         MyOpenGLView *gameView = [UNIVERSE gameView];
     597             :         OOGUIScreenID oldScreen = gui_screen;
     598             :         gui_screen = GUI_SCREEN_KEYBOARD_ENTRY;
     599             :         BOOL guiChanged = (oldScreen != gui_screen);
     600             :         
     601             :         // make sure the index we're looking for exists
     602             :         if ([key_list count] < (key_index + 1))
     603             :         {
     604             :                 // add the missing element to the array
     605             :                 NSMutableDictionary *key1 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"", @"key", [NSNumber numberWithBool:NO], @"shift", [NSNumber numberWithBool:NO], @"mod1", [NSNumber numberWithBool:NO], @"mod2", nil];
     606             :                 [key_list addObject:key1];
     607             :                 [key1 release];
     608             :         }
     609             :         NSDictionary *def = [key_list objectAtIndex:key_index];
     610             :         NSString *key = [def objectForKey:@"key"];
     611             :         //if ([key isEqualToString:@"(not set)"]) key = @"";
     612             :         OOKeyCode k_int = (OOKeyCode)[key integerValue];
     613             :         [gameView resetTypedString];
     614             :         [gameView setTypedString:(k_int != 0 ? [self keyCodeDescriptionShort:k_int] : @"")];
     615             :         [gameView setStringInput:gvStringInputAll];
     616             : 
     617             :         [gui clear];
     618             :         [gui setTitle:[NSString stringWithFormat:@"%@", DESC(@"oolite-keyconfig-update-entry-title")]];
     619             :         
     620             :         NSUInteger end_row = 21;
     621             :         if ([[self hud] allowBigGui]) 
     622             :         {
     623             :                 end_row = 27;
     624             :         }
     625             : 
     626             :         [gui addLongText:DESC(@"oolite-keyconfig-update-entry-info") startingAtRow:GUI_ROW_KC_ENTRY_INFO align:GUI_ALIGN_LEFT];
     627             : 
     628             :         [gui setText:[NSString stringWithFormat:DESC(@"Key: %@"), [gameView typedString]] forRow:end_row align:GUI_ALIGN_LEFT];
     629             :         [gui setColor:[OOColor cyanColor] forRow:end_row];
     630             :         [gui setSelectableRange:NSMakeRange(0,0)];
     631             : 
     632             :         [gui setShowTextCursor:YES];
     633             :         [gui setCurrentRow:end_row];
     634             : 
     635             :         [gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
     636             :         [gui setBackgroundTextureKey:@"keyboardsettings"];
     637             :         [UNIVERSE enterGUIViewModeWithMouseInteraction:NO];
     638             : 
     639             :         [gameView clearMouse];
     640             :         [gameView clearKeys];
     641             :         if (guiChanged) [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
     642             : }
     643             : 
     644             : 
     645             : - (void) handleKeyConfigEntryKeys:(GuiDisplayGen *)gui view:(MyOpenGLView *)gameView
     646             : {
     647             :         NSUInteger end_row = 21;
     648             :         if ([[self hud] allowBigGui]) 
     649             :         {
     650             :                 end_row = 27;
     651             :         }
     652             : 
     653             :         [self handleGUIUpDownArrowKeys];
     654             :         if ([gameView lastKeyWasShifted]) last_shift = YES;
     655             : 
     656             :         [gui setText:
     657             :                 [NSString stringWithFormat:DESC(@"Key: %@"), [gameView typedString]]
     658             :                   forRow: end_row];
     659             :         [gui setColor:[OOColor cyanColor] forRow:end_row];
     660             : 
     661             :         if ([self checkKeyPress:n_key_gui_select]) 
     662             :         {
     663             :                 [gameView suppressKeysUntilKeyUp];
     664             :                 // update function key
     665             :                 [self updateKeyDefinition:[gameView typedString] index:key_index];
     666             :                 [gameView clearKeys];   // try to stop key bounces
     667             :                 [self setGuiToKeyConfigScreen:YES];
     668             :         }
     669             :         if ([gameView isDown:27]) // escape
     670             :         {
     671             :                 [gameView suppressKeysUntilKeyUp];
     672             :                 // don't update function key
     673             :                 [self setGuiToKeyConfigScreen:YES];
     674             :         }
     675             : }
     676             : 
     677             : // updates the overridden definition of a key to a new keycode value
     678           0 : - (void) updateKeyDefinition:(NSString *)keystring index:(NSUInteger)index
     679             : {
     680             :         NSMutableDictionary *key_def = [[NSMutableDictionary alloc] initWithDictionary:(NSDictionary *)[key_list objectAtIndex:index] copyItems:YES];
     681             :         [key_def setObject:keystring forKey:@"key"];
     682             :         // auto=turn on shift if the entered key was shifted
     683             : 
     684             :         if (last_shift && [keystring length] == 1 && ![nav_keys containsObject:[selected_entry objectForKey: KEY_KC_DEFINITION]]) 
     685             :         {
     686             :                 [key_def setObject:[NSNumber numberWithBool:YES] forKey:@"shift"];
     687             :         }
     688             :         if (!last_shift && [keystring length] == 1)
     689             :         {
     690             :                 [key_def setObject:[NSNumber numberWithBool:NO] forKey:@"shift"];
     691             :         }
     692             :         last_shift = NO;
     693             :         if (index > [key_list count] - 1)
     694             :         {
     695             :                 [key_list insertObject:key_def atIndex:index];
     696             :         }
     697             :         else 
     698             :         {
     699             :                 [key_list replaceObjectAtIndex:index withObject:key_def];
     700             :         }
     701             :         [key_def release];
     702             :         NSArray *new_array = [self processKeyCode:key_list];
     703             :         [key_list release];
     704             :         key_list = [[NSMutableArray alloc] initWithArray:new_array copyItems:YES];
     705             :         [new_array release];
     706             : }
     707             : 
     708             : 
     709             : // changes the shift/ctrl/alt state of an overridden definition
     710           0 : - (void) updateShiftKeyDefinition:(NSString *)key index:(NSUInteger)index
     711             : {
     712             :         NSMutableDictionary *key_def = [[NSMutableDictionary alloc] initWithDictionary:(NSDictionary *)[key_list objectAtIndex:index] copyItems:YES];
     713             :         BOOL current = [[key_def objectForKey:key] boolValue];
     714             :         BOOL keycode_changed = NO;
     715             :         current = !current;
     716             :         [key_def setObject:[NSNumber numberWithBool:current] forKey:key];
     717             :         if ([key isEqualToString:@"shift"]) 
     718             :         {
     719             :                 // force the key into upper or lower case, to limit invalid key combos as much as possible
     720             :                 NSString* keycode = [key_def objectForKey:@"key"];
     721             :                 NSInteger k_int = (OOKeyCode)[keycode integerValue];
     722             :                 if (k_int > 0)
     723             :                 {
     724             :                         NSString* keystring = [self keyCodeDescription:k_int];
     725             :                         NSString* newstring;
     726             :                         if ([keystring length] == 1) 
     727             :                         {
     728             :                                 // try switching the case. for characters that can't be switched (eg 1,2,3,etc), this should do nothing
     729             :                                 if (current) 
     730             :                                 {
     731             :                                         newstring = [keystring uppercaseString];
     732             :                                 } 
     733             :                                 else 
     734             :                                 {
     735             :                                         newstring = [keystring lowercaseString];
     736             :                                 }
     737             :                                 if (![newstring isEqualToString:keystring]) 
     738             :                                 {
     739             :                                         [key_def setObject:newstring forKey:@"key"];
     740             :                                         keycode_changed = YES;
     741             :                                 }
     742             :                         }
     743             :                 }
     744             :         }
     745             :         if (index > [key_list count] - 1)
     746             :         {
     747             :                 [key_list insertObject:key_def atIndex:index];
     748             :         }
     749             :         else 
     750             :         {
     751             :                 [key_list replaceObjectAtIndex:index withObject:key_def];
     752             :         }
     753             :         [key_def release];
     754             :         if (keycode_changed) 
     755             :         {
     756             :                 NSArray *new_array = [self processKeyCode:key_list];
     757             :                 [key_list release];
     758             :                 key_list = [[NSMutableArray alloc] initWithArray:new_array copyItems:YES];
     759             :                 [new_array release];
     760             :         }
     761             : }
     762             : 
     763             : 
     764             : - (void) setGuiToConfirmClearScreen
     765             : {
     766             :         GuiDisplayGen *gui=[UNIVERSE gui];
     767             :         OOGUIScreenID oldScreen = gui_screen;
     768             :         
     769             :         gui_screen = GUI_SCREEN_KEYBOARD_CONFIRMCLEAR;
     770             :         BOOL guiChanged = (oldScreen != gui_screen);
     771             :         
     772             :         [gui clear];
     773             :         [gui setTitle:[NSString stringWithFormat:@"%@", DESC(@"oolite-keyconfig-clear-overrides-title")]];
     774             :         
     775             :         [gui addLongText:[NSString stringWithFormat:@"%@", DESC(@"oolite-keyconfig-clear-overrides")]
     776             :                                                                 startingAtRow:GUI_ROW_KC_CONFIRMCLEAR align:GUI_ALIGN_LEFT];
     777             :         
     778             :         [gui setText:DESC(@"oolite-keyconfig-clear-yes") forRow: GUI_ROW_KC_CONFIRMCLEAR_YES align:GUI_ALIGN_CENTER];
     779             :         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_CONFIRMCLEAR_YES];
     780             :         
     781             :         [gui setText:DESC(@"oolite-keyconfig-clear-no") forRow:GUI_ROW_KC_CONFIRMCLEAR_NO align:GUI_ALIGN_CENTER];
     782             :         [gui setKey:GUI_KEY_OK forRow:GUI_ROW_KC_CONFIRMCLEAR_NO];
     783             :         
     784             :         [gui setSelectableRange:NSMakeRange(GUI_ROW_KC_CONFIRMCLEAR_YES, 2)];
     785             :         [gui setSelectedRow:GUI_ROW_KC_CONFIRMCLEAR_NO];
     786             : 
     787             :         [gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
     788             :         [gui setBackgroundTextureKey:@"keyboardsettings"];
     789             : 
     790             :         [[UNIVERSE gameView] clearMouse];
     791             :         [[UNIVERSE gameView] clearKeys];
     792             :         if (guiChanged) [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
     793             : }
     794             : 
     795             : 
     796             : - (void) handleKeyMapperConfirmClearKeys:(GuiDisplayGen *)gui view:(MyOpenGLView *)gameView
     797             : {
     798             :         [self handleGUIUpDownArrowKeys];
     799             : 
     800             :         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]);
     801             :         if ([gameView isDown:gvMouseDoubleClick]) [gameView clearMouse];
     802             : 
     803             :         // Translation issue: we can't confidently use raw Y and N ascii as shortcuts. It's better to use the load-previous-commander keys.
     804             :         id valueYes = [[[UNIVERSE descriptions] oo_stringForKey:@"load-previous-commander-yes" defaultValue:@"y"] lowercaseString];
     805             :         id valueNo = [[[UNIVERSE descriptions] oo_stringForKey:@"load-previous-commander-no" defaultValue:@"n"] lowercaseString];
     806             :         unsigned char cYes, cNo;
     807             :         
     808             :         cYes = [valueYes characterAtIndex: 0] & 0x00ff;     // Use lower byte of unichar.
     809             :         cNo = [valueNo characterAtIndex: 0] & 0x00ff;       // Use lower byte of unichar.
     810             :         
     811             :         if ((selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_CONFIRMCLEAR_YES))||[gameView isDown:cYes]||[gameView isDown:cYes - 32])
     812             :         {
     813             :                 [self deleteAllKeySettings];
     814             :                 [gameView suppressKeysUntilKeyUp];
     815             :                 [self setGuiToKeyMapperScreen:0 resetCurrentRow:YES];
     816             :         }
     817             :         
     818             :         if ((selectKeyPress && ([gui selectedRow] == GUI_ROW_KC_CONFIRMCLEAR_NO))||[gameView isDown:27]||[gameView isDown:cNo]||[gameView isDown:cNo - 32])
     819             :         {
     820             :                 // esc or NO was pressed - get out of here
     821             :                 [gameView suppressKeysUntilKeyUp];
     822             :                 [self setGuiToKeyMapperScreen:0 resetCurrentRow:YES];
     823             :         }
     824             : }
     825             : 
     826             : 
     827           0 : - (void) displayKeyFunctionList:(GuiDisplayGen *)gui skip:(NSUInteger)skip
     828             : {
     829             :         [gui setColor:[OOColor greenColor] forRow:GUI_ROW_KC_HEADING];
     830             :         [gui setArray:[NSArray arrayWithObjects:
     831             :                                    @"Function", @"Assigned to", @"Overrides", nil]
     832             :                    forRow:GUI_ROW_KC_HEADING];
     833             : 
     834             :         NSDictionary *overrides = [self loadKeySettings];
     835             : 
     836             :         if(!keyFunctions)
     837             :         {
     838             :                 keyFunctions = [[self keyFunctionList] retain];
     839             :         }
     840             : 
     841             :         NSUInteger i, n_functions = [keyFunctions count];
     842             :         NSInteger n_rows, start_row, previous = 0;
     843             :         NSString *validate = nil;
     844             : 
     845             :         if (skip >= n_functions)
     846             :                 skip = n_functions - 1;
     847             :         
     848             :         if (n_functions < MAX_ROWS_KC_FUNCTIONS)
     849             :         {
     850             :                 skip = 0;
     851             :                 previous = 0;
     852             :                 n_rows = MAX_ROWS_KC_FUNCTIONS;
     853             :                 start_row = GUI_ROW_KC_FUNCSTART;
     854             :         }
     855             :         else
     856             :         {
     857             :                 n_rows = MAX_ROWS_KC_FUNCTIONS  - 1;
     858             :                 start_row = GUI_ROW_KC_FUNCSTART;
     859             :                 if (skip > 0)
     860             :                 {
     861             :                         n_rows -= 1;
     862             :                         start_row += 1;
     863             :                         if (skip > MAX_ROWS_KC_FUNCTIONS)
     864             :                                 previous = skip - (MAX_ROWS_KC_FUNCTIONS - 2);
     865             :                         else
     866             :                                 previous = 0;
     867             :                 }
     868             :         }
     869             :         
     870             :         if (n_functions > 0)
     871             :         {
     872             :                 if (skip > 0)
     873             :                 {
     874             :                         [gui setColor:[OOColor greenColor] forRow:GUI_ROW_KC_FUNCSTART];
     875             :                         [gui setArray:[NSArray arrayWithObjects:DESC(@"gui-back"), @" <-- ", nil] forRow:GUI_ROW_KC_FUNCSTART];
     876             :                         [gui setKey:[NSString stringWithFormat:@"More:%ld", previous] forRow:GUI_ROW_KC_FUNCSTART];
     877             :                 }
     878             :                 
     879             :                 for(i = 0; i < (n_functions - skip) && (int)i < n_rows; i++)
     880             :                 {
     881             :                         NSDictionary *entry = [keyFunctions objectAtIndex:i + skip];
     882             :                         if ([entry objectForKey:KEY_KC_HEADER]) {
     883             :                                 NSString *header = [entry objectForKey:KEY_KC_HEADER];
     884             :                                 [gui setArray:[NSArray arrayWithObjects:header, @"", @"", nil] forRow:i + start_row];
     885             :                                 [gui setColor:[OOColor cyanColor] forRow:i + start_row];
     886             :                         }
     887             :                         else
     888             :                         {
     889             :                                 NSString *assignment = nil;
     890             :                                 NSString *override = nil;
     891             :                                 if (![self entryIsDictCustomEquip:entry])
     892             :                                 {
     893             :                                         // Find out what's assigned for this function currently.
     894             :                                         assignment = [PLAYER keyBindingDescription2:[entry objectForKey:KEY_KC_DEFINITION]];
     895             :                                         override = ([overrides objectForKey:[entry objectForKey:KEY_KC_DEFINITION]] ? @"Yes" : @""); // work out whether this assignment is overriding the setting in keyconfig2.plist
     896             :                                         validate = [self validateKey:[entry objectForKey:KEY_KC_DEFINITION] checkKeys:(NSArray *)[keyconfig2_settings objectForKey:[entry objectForKey:KEY_KC_DEFINITION]]];
     897             :                                 }
     898             :                                 else 
     899             :                                 {
     900             :                                         NSString *custom_keytype = [self getCustomEquipKeyDefType:[entry oo_stringForKey:KEY_KC_DEFINITION]];
     901             :                                         NSUInteger idx = [self getCustomEquipIndex:[entry oo_stringForKey:KEY_KC_DEFINITION]];
     902             :                                         assignment = [PLAYER getKeyBindingDescription:[[customEquipActivation objectAtIndex:idx] oo_arrayForKey:custom_keytype]];
     903             :                                         OOEquipmentType *item = [OOEquipmentType equipmentTypeWithIdentifier:[[customEquipActivation objectAtIndex:idx] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]];
     904             :                                         bool result = true;
     905             :                                         int j, k;
     906             :                                         NSArray *defArray = nil;
     907             :                                         NSArray *compArray = nil;
     908             : 
     909             :                                         if ([custom_keytype isEqualToString:CUSTOMEQUIP_KEYACTIVATE]) 
     910             :                                         {
     911             :                                                 defArray = [item defaultActivateKey];
     912             :                                                 compArray = [[customEquipActivation objectAtIndex:idx] oo_arrayForKey:custom_keytype];
     913             :                                         }
     914             :                                         if ([custom_keytype isEqualToString:CUSTOMEQUIP_KEYMODE]) 
     915             :                                         {
     916             :                                                 defArray = [item defaultModeKey];
     917             :                                                 compArray = [[customEquipActivation objectAtIndex:idx] oo_arrayForKey:custom_keytype];
     918             :                                         }
     919             :                                         for (j = 0; j < [defArray count]; j++) 
     920             :                                         {
     921             :                                                 for (k = 0; k < [compArray count]; k++)
     922             :                                                 {
     923             :                                                         if (![self compareKeyEntries:[defArray objectAtIndex:j] second:[compArray objectAtIndex:k]])
     924             :                                                         {
     925             :                                                                 result = false;
     926             :                                                                 break;
     927             :                                                         }
     928             :                                                 }
     929             :                                                 if (result == false) break;
     930             :                                         }
     931             : 
     932             :                                         override = (!result ? @"Yes" : @"");
     933             :                                         validate = [self validateKey:[entry objectForKey:KEY_KC_DEFINITION] checkKeys:(NSArray *)[[customEquipActivation objectAtIndex:idx] oo_arrayForKey:custom_keytype]];
     934             :                                 }
     935             :                                 if (assignment == nil)
     936             :                                 {
     937             :                                         assignment = @"   -   ";
     938             :                                 }
     939             :                                 
     940             :                                 [gui setArray:[NSArray arrayWithObjects: 
     941             :                                                                 [entry objectForKey:KEY_KC_GUIDESC], assignment, override, nil]
     942             :                                         forRow:i + start_row];
     943             :                                 [gui setKey:[NSString stringWithFormat:@"Index:%ld", i + skip] forRow:i + start_row];
     944             :                                 if (validate) 
     945             :                                 {
     946             :                                         [gui setColor:[OOColor orangeColor] forRow:i + start_row];
     947             :                                 }
     948             :                         }
     949             :                 }
     950             :                 if (i < n_functions - skip)
     951             :                 {
     952             :                         [gui setColor:[OOColor greenColor] forRow:start_row + i];
     953             :                         [gui setArray:[NSArray arrayWithObjects:DESC(@"gui-more"), @" --> ", nil] forRow:start_row + i];
     954             :                         [gui setKey:[NSString stringWithFormat:@"More:%ld", n_rows + skip] forRow:start_row + i];
     955             :                         i++;
     956             :                 }
     957             :                 
     958             :                 [gui setSelectableRange:NSMakeRange(GUI_ROW_KC_SELECTKBD, (i + start_row - GUI_ROW_KC_FUNCSTART) + (GUI_ROW_KC_FUNCSTART - GUI_ROW_KC_SELECTKBD))];
     959             :         }
     960             : }
     961             : 
     962             : 
     963           0 : - (NSArray *)keyFunctionList
     964             : {
     965             :         NSMutableArray *funcList = [NSMutableArray array];
     966             : 
     967             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-screen-access")]];
     968             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_launch_ship") keyDef:@"key_launch_ship"]];
     969             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_screen_options") keyDef:@"key_gui_screen_options"]];
     970             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_screen_equipship") keyDef:@"key_gui_screen_equipship"]];
     971             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_screen_interfaces") keyDef:@"key_gui_screen_interfaces"]];
     972             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_screen_status") keyDef:@"key_gui_screen_status"]];
     973             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_chart_screens") keyDef:@"key_gui_chart_screens"]];
     974             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_system_data") keyDef:@"key_gui_system_data"]];
     975             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_market") keyDef:@"key_gui_market"]];
     976             : 
     977             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-propulsion")]];
     978             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_roll_left") keyDef:@"key_roll_left"]];
     979             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_roll_right") keyDef:@"key_roll_right"]];
     980             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_pitch_forward") keyDef:@"key_pitch_forward"]];
     981             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_pitch_back") keyDef:@"key_pitch_back"]];
     982             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_yaw_left") keyDef:@"key_yaw_left"]];
     983             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_yaw_right") keyDef:@"key_yaw_right"]];
     984             : 
     985             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_increase_speed") keyDef:@"key_increase_speed"]];
     986             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_decrease_speed") keyDef:@"key_decrease_speed"]];
     987             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_inject_fuel") keyDef:@"key_inject_fuel"]];
     988             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_jumpdrive") keyDef:@"key_jumpdrive"]];
     989             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_hyperspace") keyDef:@"key_hyperspace"]];
     990             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_galactic_hyperspace") keyDef:@"key_galactic_hyperspace"]];
     991             : 
     992             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-navigation")]];
     993             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_next_compass_mode") keyDef:@"key_next_compass_mode"]];
     994             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_prev_compass_mode") keyDef:@"key_prev_compass_mode"]];
     995             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_scanner_zoom") keyDef:@"key_scanner_zoom"]];
     996             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_scanner_unzoom") keyDef:@"key_scanner_unzoom"]];
     997             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_view_forward") keyDef:@"key_view_forward"]];
     998             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_view_aft") keyDef:@"key_view_aft"]];
     999             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_view_port") keyDef:@"key_view_port"]];
    1000             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_view_starboard") keyDef:@"key_view_starboard"]];
    1001             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_ident_system") keyDef:@"key_ident_system"]];
    1002             : 
    1003             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_docking_clearance_request") keyDef:@"key_docking_clearance_request"]];
    1004             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_autopilot") keyDef:@"key_autopilot"]];
    1005             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_autodock") keyDef:@"key_autodock"]];
    1006             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_docking_music") keyDef:@"key_docking_music"]];
    1007             : 
    1008             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-offensive")]];
    1009             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_weapons_online_toggle") keyDef:@"key_weapons_online_toggle"]];
    1010             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_fire_lasers") keyDef:@"key_fire_lasers"]];
    1011             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_launch_missile") keyDef:@"key_launch_missile"]];
    1012             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_target_missile") keyDef:@"key_target_missile"]];
    1013             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_untarget_missile") keyDef:@"key_untarget_missile"]];
    1014             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_target_incoming_missile") keyDef:@"key_target_incoming_missile"]];
    1015             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_next_missile") keyDef:@"key_next_missile"]];
    1016             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_next_target") keyDef:@"key_next_target"]];
    1017             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_previous_target") keyDef:@"key_previous_target"]];
    1018             : 
    1019             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-defensive")]];
    1020             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_ecm") keyDef:@"key_ecm"]];
    1021             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_dump_cargo") keyDef:@"key_dump_cargo"]];
    1022             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_rotate_cargo") keyDef:@"key_rotate_cargo"]];
    1023             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_launch_escapepod") keyDef:@"key_launch_escapepod"]];
    1024             : 
    1025             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-special-equip")]];
    1026             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_cycle_next_mfd") keyDef:@"key_cycle_next_mfd"]];
    1027             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_cycle_previous_mfd") keyDef:@"key_cycle_previous_mfd"]];
    1028             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_switch_next_mfd") keyDef:@"key_switch_next_mfd"]];
    1029             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_switch_previous_mfd") keyDef:@"key_switch_previous_mfd"]];
    1030             : 
    1031             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_prime_next_equipment") keyDef:@"key_prime_next_equipment"]];
    1032             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_prime_previous_equipment") keyDef:@"key_prime_previous_equipment"]];
    1033             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_activate_equipment") keyDef:@"key_activate_equipment"]];
    1034             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_mode_equipment") keyDef:@"key_mode_equipment"]];
    1035             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_fastactivate_equipment_a") keyDef:@"key_fastactivate_equipment_a"]];
    1036             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_fastactivate_equipment_b") keyDef:@"key_fastactivate_equipment_b"]];
    1037             : 
    1038             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-chart-screen")]];
    1039             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_advanced_nav_array_next") keyDef:@"key_advanced_nav_array_next"]];
    1040             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_advanced_nav_array_previous") keyDef:@"key_advanced_nav_array_previous"]];
    1041             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_home") keyDef:@"key_map_home"]];
    1042             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_end") keyDef:@"key_map_end"]];
    1043             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_info") keyDef:@"key_map_info"]];
    1044             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_zoom_in") keyDef:@"key_map_zoom_in"]];
    1045             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_zoom_out") keyDef:@"key_map_zoom_out"]];
    1046             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_next_system") keyDef:@"key_map_next_system"]];
    1047             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_map_previous_system") keyDef:@"key_map_previous_system"]];
    1048             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_chart_highlight") keyDef:@"key_chart_highlight"]];
    1049             : 
    1050             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-planet-info-screen")]];
    1051             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_system_home") keyDef:@"key_system_home"]];
    1052             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_system_end") keyDef:@"key_system_end"]];
    1053             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_system_next_system") keyDef:@"key_system_next_system"]];
    1054             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_system_previous_system") keyDef:@"key_system_previous_system"]];
    1055             : 
    1056             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-market-screen")]];
    1057             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_filter_cycle") keyDef:@"key_market_filter_cycle"]];
    1058             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_sorter_cycle") keyDef:@"key_market_sorter_cycle"]];
    1059             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_buy_one") keyDef:@"key_market_buy_one"]];
    1060             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_sell_one") keyDef:@"key_market_sell_one"]];
    1061             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_buy_max") keyDef:@"key_market_buy_max"]];
    1062             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_market_sell_max") keyDef:@"key_market_sell_max"]];
    1063             : 
    1064             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-misc")]];
    1065             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_snapshot") keyDef:@"key_snapshot"]];
    1066             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_pausebutton") keyDef:@"key_pausebutton"]];
    1067             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_show_fps") keyDef:@"key_show_fps"]];
    1068             :         //[funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_bloom_toggle") keyDef:@"key_bloom_toggle"]];
    1069             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_mouse_control_roll") keyDef:@"key_mouse_control_roll"]];
    1070             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_mouse_control_yaw") keyDef:@"key_mouse_control_yaw"]];
    1071             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_hud_toggle") keyDef:@"key_hud_toggle"]];
    1072             : #if OO_FOV_INFLIGHT_CONTROL_ENABLED
    1073             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_inc_field_of_view") keyDef:@"key_inc_field_of_view"]];
    1074             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_dec_field_of_view") keyDef:@"key_dec_field_of_view"]];
    1075             : #endif
    1076             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_comms_log") keyDef:@"key_comms_log"]];
    1077             : 
    1078             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-custom-view")]];
    1079             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view") keyDef:@"key_custom_view"]];
    1080             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_zoom_in") keyDef:@"key_custom_view_zoom_in"]];
    1081             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_zoom_out") keyDef:@"key_custom_view_zoom_out"]];
    1082             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_roll_left") keyDef:@"key_custom_view_roll_left"]];
    1083             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_roll_right") keyDef:@"key_custom_view_roll_right"]];
    1084             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_pan_left") keyDef:@"key_custom_view_pan_left"]];
    1085             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_pan_right") keyDef:@"key_custom_view_pan_right"]];
    1086             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_pan_up") keyDef:@"key_custom_view_pan_up"]];
    1087             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_pan_down") keyDef:@"key_custom_view_pan_down"]];
    1088             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_rotate_left") keyDef:@"key_custom_view_rotate_left"]];
    1089             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_rotate_right") keyDef:@"key_custom_view_rotate_right"]];
    1090             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_rotate_up") keyDef:@"key_custom_view_rotate_up"]];
    1091             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_custom_view_rotate_down") keyDef:@"key_custom_view_rotate_down"]];
    1092             : 
    1093             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-oxz-manager")]];
    1094             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_oxzmanager_setfilter") keyDef:@"key_oxzmanager_setfilter"]];
    1095             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_oxzmanager_showinfo") keyDef:@"key_oxzmanager_showinfo"]];
    1096             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_oxzmanager_extract") keyDef:@"key_oxzmanager_extract"]];
    1097             : 
    1098             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-gui")]];
    1099             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_arrow_left") keyDef:@"key_gui_arrow_left"]];
    1100             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_arrow_right") keyDef:@"key_gui_arrow_right"]];
    1101             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_arrow_up") keyDef:@"key_gui_arrow_up"]];
    1102             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_arrow_down") keyDef:@"key_gui_arrow_down"]];
    1103             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_page_down") keyDef:@"key_gui_page_down"]];
    1104             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_page_up") keyDef:@"key_gui_page_up"]];
    1105             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_gui_select") keyDef:@"key_gui_select"]];
    1106             : 
    1107             :         [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-debug")]];
    1108             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_dump_target_state") keyDef:@"key_dump_target_state"]];
    1109             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_dump_entity_list") keyDef:@"key_dump_entity_list"]];
    1110             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_full") keyDef:@"key_debug_full"]];
    1111             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_collision") keyDef:@"key_debug_collision"]];
    1112             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_console_connect") keyDef:@"key_debug_console_connect"]];
    1113             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_bounding_boxes") keyDef:@"key_debug_bounding_boxes"]];
    1114             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_shaders") keyDef:@"key_debug_shaders"]];
    1115             :         [funcList addObject:[self makeKeyGuiDict:DESC(@"oolite-keydesc-key_debug_off") keyDef:@"key_debug_off"]];
    1116             : 
    1117             :         if ([customEquipActivation count] > 0) 
    1118             :         {
    1119             :                 [funcList addObject:[self makeKeyGuiDictHeader:DESC(@"oolite-keydesc-header-oxp-equip")]];
    1120             :                 int i;
    1121             :                 for (i = 0; i < [customEquipActivation count]; i++)
    1122             :                 {
    1123             :                         [funcList addObject:[self makeKeyGuiDict:[NSString stringWithFormat: @"Activate '%@'", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPNAME]] 
    1124             :                                 keyDef:[NSString stringWithFormat:@"activate_%@", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]]]];
    1125             :                         [funcList addObject:[self makeKeyGuiDict:[NSString stringWithFormat: @"Mode '%@'", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPNAME]] 
    1126             :                                 keyDef:[NSString stringWithFormat:@"mode_%@", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]]]];
    1127             :                 }
    1128             :         }
    1129             :         return funcList;
    1130             : }
    1131             : 
    1132             : 
    1133             : - (NSDictionary *)makeKeyGuiDict:(NSString *)what keyDef:(NSString*)key_def
    1134             : {
    1135             :         NSMutableDictionary *guiDict = [NSMutableDictionary dictionary];
    1136             :         if ([what length] > 50) what = [[what substringToIndex:48] stringByAppendingString:@"..."];
    1137             :         [guiDict setObject:what forKey:KEY_KC_GUIDESC];
    1138             :         [guiDict setObject:key_def forKey:KEY_KC_DEFINITION];
    1139             :         return guiDict;
    1140             : }
    1141             : 
    1142             : 
    1143             : - (NSDictionary *)makeKeyGuiDictHeader:(NSString *)header
    1144             : {
    1145             :         NSMutableDictionary *guiDict = [NSMutableDictionary dictionary];
    1146             :         [guiDict setObject:header forKey:KEY_KC_HEADER];
    1147             :         [guiDict setObject:@"" forKey:KEY_KC_GUIDESC];
    1148             :         [guiDict setObject:@"" forKey:KEY_KC_DEFINITION];
    1149             :         return guiDict;
    1150             : }
    1151             : 
    1152             : 
    1153             : - (void) setGuiToKeyboardLayoutScreen:(unsigned)skip
    1154             : {
    1155             :         [self setGuiToKeyboardLayoutScreen:skip resetCurrentRow:NO];
    1156             : }
    1157             : 
    1158             : 
    1159             : - (void) setGuiToKeyboardLayoutScreen:(unsigned)skip resetCurrentRow:(BOOL)resetCurrentRow
    1160             : {
    1161             :         GuiDisplayGen *gui = [UNIVERSE gui];
    1162             :         MyOpenGLView *gameView = [UNIVERSE gameView];
    1163             :         OOGUIScreenID oldScreen = gui_screen;
    1164             :         OOGUITabStop tabStop[GUI_MAX_COLUMNS];
    1165             :         tabStop[0] = 10;
    1166             :         tabStop[1] = 290;
    1167             :         [gui setTabStops:tabStop];
    1168             : 
    1169             :         gui_screen = GUI_SCREEN_KEYBOARD_LAYOUT;
    1170             :         BOOL guiChanged = (oldScreen != gui_screen);
    1171             : 
    1172             :         [[UNIVERSE gameController] setMouseInteractionModeForUIWithMouseInteraction:YES];
    1173             : 
    1174             :         [gui clear];
    1175             :         [gui setTitle:[NSString stringWithFormat:@"Select Keyboard Layout"]];
    1176             : 
    1177             :         [self displayKeyboardLayoutList:gui skip:skip];
    1178             : 
    1179             :         [gui setArray:[NSArray arrayWithObject:DESC(@"oolite-keyconfig-keyboard-info")] forRow:GUI_ROW_KC_INSTRUCT];
    1180             : 
    1181             :         [gui setSelectedRow:kbd_row];
    1182             : 
    1183             :         [gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
    1184             :         [gui setBackgroundTextureKey:@"keyboardsettings"];
    1185             : 
    1186             :         [gameView clearMouse];
    1187             :         [gameView clearKeys];
    1188             :         [UNIVERSE enterGUIViewModeWithMouseInteraction:YES];
    1189             : 
    1190             :         if (guiChanged) [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
    1191             : }
    1192             : 
    1193             : 
    1194             : - (void) handleKeyboardLayoutEntryKeys:(GuiDisplayGen *)gui view:(MyOpenGLView *)gameView
    1195             : {
    1196             :         [self handleGUIUpDownArrowKeys];
    1197             :         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]);
    1198             :         if ([gameView isDown:gvMouseDoubleClick])  [gameView clearMouse];
    1199             : 
    1200             :         NSString *key = [gui keyForRow: [gui selectedRow]];
    1201             :         if (selectKeyPress)
    1202             :         {
    1203             :                 if ([key hasPrefix:@"More:"])
    1204             :                 {
    1205             :                         int from_function = [[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
    1206             :                         if (from_function < 0)  from_function = 0;
    1207             : 
    1208             :                         current_row = GUI_ROW_KC_FUNCSTART;
    1209             :                         if (from_function == 0) current_row = GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1;
    1210             :                         [self setGuiToKeyboardLayoutScreen:from_function];
    1211             :                         if ([gameView isDown:gvMouseDoubleClick]) [gameView clearMouse];
    1212             :                         return;
    1213             :                 }
    1214             : 
    1215             :                 // update the keyboard code
    1216             :                 NSUInteger idx =[[[key componentsSeparatedByString:@":"] objectAtIndex:1] intValue];
    1217             :                 NSString *kbd = [[kbdLayouts objectAtIndex:idx] objectForKey:@"key"];
    1218             :                 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1219             :                 [defaults setObject:kbd forKey:@"keyboard-code"];
    1220             :                 [self initKeyConfigSettings];
    1221             :                 [self initCheckingDictionary];
    1222             : 
    1223             :                 [gameView clearKeys];   // try to stop key bounces
    1224             :                 [self setGuiToKeyMapperScreen:0 resetCurrentRow:YES];
    1225             :         }
    1226             :         if ([gameView isDown:27]) // escape - return without change
    1227             :         {
    1228             :                 [gameView clearKeys];   // try to stop key bounces
    1229             :                 [self setGuiToKeyMapperScreen:0 resetCurrentRow:YES];
    1230             :         }       
    1231             : }
    1232             : 
    1233             : 
    1234           0 : - (NSString *)keyboardDescription:(NSString *)kbd
    1235             : {
    1236             :         NSString *map = @"";
    1237             : #if OOLITE_WINDOWS      
    1238             :         map = @"keymappings_windows.plist";
    1239             : #endif
    1240             : #if OOLITE_LINUX
    1241             :         map = @"keymappings_linux.plist";
    1242             : #endif
    1243             : #if OOLITE_MAC_OS_X
    1244             :         map = @"keymappings_mac.plist";
    1245             : #endif
    1246             :         NSDictionary *kmap = [NSDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:map inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
    1247             :         NSDictionary *sect = [kmap objectForKey:kbd];
    1248             :         return [sect objectForKey:@"description"];
    1249             : }
    1250             : 
    1251             : 
    1252           0 : - (NSArray *)keyboardLayoutList
    1253             : {
    1254             :         NSString *map = @"";
    1255             : #if OOLITE_WINDOWS      
    1256             :         map = @"keymappings_windows.plist";
    1257             : #endif
    1258             : #if OOLITE_LINUX
    1259             :         map = @"keymappings_linux.plist";
    1260             : #endif
    1261             : #if OOLITE_MAC_OS_X
    1262             :         map = @"keymappings_mac.plist";
    1263             : #endif
    1264             :         NSDictionary *kmap = [NSDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:map inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
    1265             :         NSMutableArray *kbdList = [NSMutableArray array];
    1266             :         NSArray *keys = [kmap allKeys];
    1267             :         NSUInteger i;
    1268             :         NSDictionary *def = nil;
    1269             : 
    1270             :         for (i = 0; i < [keys count]; i++)
    1271             :         {
    1272             :                 if (![[keys objectAtIndex:i] isEqualToString:@"default"])
    1273             :                 {
    1274             :                         [kbdList addObject:[[NSDictionary alloc] initWithObjectsAndKeys:[keys objectAtIndex:i], @"key", 
    1275             :                                 [self keyboardDescription:[keys objectAtIndex:i]], @"description", 
    1276             :                                 //([[keys objectAtIndex:i] isEqualToString:kbd] ? @"Current" : @""), @"selected",
    1277             :                                 nil]];
    1278             :                 }
    1279             :                 else 
    1280             :                 {
    1281             :                         // key the "default" item separate, so we can add it at the top of the list, rather than getting it sorted
    1282             :                         def = [[NSDictionary alloc] initWithObjectsAndKeys:[keys objectAtIndex:i], @"key", 
    1283             :                                 [self keyboardDescription:[keys objectAtIndex:i]], @"description", 
    1284             :                                 //([[keys objectAtIndex:i] isEqualToString:kbd] ? @"Current" : @""), @"selected",
    1285             :                                 nil];
    1286             :                 }
    1287             :         }
    1288             : 
    1289             :         NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"description" ascending:YES];
    1290             :         NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    1291             :         NSMutableArray *sorted = [NSMutableArray arrayWithArray:[kbdList sortedArrayUsingDescriptors:sortDescriptors]];
    1292             :         [sorted insertObject:def atIndex:0];
    1293             :         
    1294             :         [sortDescriptor release];
    1295             : 
    1296             :         return sorted;
    1297             : }
    1298             : 
    1299             : 
    1300           0 : - (void) displayKeyboardLayoutList:(GuiDisplayGen *)gui skip:(NSUInteger)skip
    1301             : {
    1302             :         [gui setColor:[OOColor greenColor] forRow:GUI_ROW_KC_HEADING];
    1303             :         [gui setArray:[NSArray arrayWithObjects:@"Keyboard layout", nil] forRow:GUI_ROW_KC_HEADING];
    1304             : 
    1305             :         if (!kbdLayouts) kbdLayouts = [[self keyboardLayoutList] retain];
    1306             : 
    1307             :         NSUInteger i, n_functions = [kbdLayouts count];
    1308             :         NSInteger n_rows, start_row, previous = 0;
    1309             : 
    1310             :         if (skip >= n_functions)
    1311             :                 skip = n_functions - 1;
    1312             :         
    1313             :         if (n_functions < MAX_ROWS_KC_FUNCTIONS)
    1314             :         {
    1315             :                 skip = 0;
    1316             :                 previous = 0;
    1317             :                 n_rows = MAX_ROWS_KC_FUNCTIONS;
    1318             :                 start_row = GUI_ROW_KC_FUNCSTART;
    1319             :         }
    1320             :         else
    1321             :         {
    1322             :                 n_rows = MAX_ROWS_KC_FUNCTIONS  - 1;
    1323             :                 start_row = GUI_ROW_KC_FUNCSTART;
    1324             :                 if (skip > 0)
    1325             :                 {
    1326             :                         n_rows -= 1;
    1327             :                         start_row += 1;
    1328             :                         if (skip > MAX_ROWS_KC_FUNCTIONS)
    1329             :                                 previous = skip - (MAX_ROWS_KC_FUNCTIONS - 2);
    1330             :                         else
    1331             :                                 previous = 0;
    1332             :                 }
    1333             :         }
    1334             :         
    1335             :         if (n_functions > 0)
    1336             :         {
    1337             :                 if (skip > 0)
    1338             :                 {
    1339             :                         [gui setColor:[OOColor greenColor] forRow:GUI_ROW_KC_FUNCSTART];
    1340             :                         [gui setArray:[NSArray arrayWithObjects:DESC(@"gui-back"), @" <-- ", nil] forRow:GUI_ROW_KC_FUNCSTART];
    1341             :                         [gui setKey:[NSString stringWithFormat:@"More:%ld", previous] forRow:GUI_ROW_KC_FUNCSTART];
    1342             :                 }
    1343             :                 
    1344             :                 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1345             :                 NSString *kbd = [defaults oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
    1346             : 
    1347             :                 for(i = 0; i < (n_functions - skip) && (int)i < n_rows; i++)
    1348             :                 {
    1349             :                         NSDictionary *entry = [kbdLayouts objectAtIndex:i + skip];
    1350             :                         NSString *desc = [entry objectForKey:@"description"];
    1351             :                         NSString *selected = @"";
    1352             :                         if ([[entry objectForKey:@"key"] isEqualToString:kbd]) selected = @"Current";
    1353             :                         [gui setArray:[NSArray arrayWithObjects:desc, selected, nil] forRow:i + start_row];
    1354             :                         [gui setKey:[NSString stringWithFormat:@"Index:%ld", i + skip] forRow:i + start_row];
    1355             :                 }
    1356             :                 if (i < n_functions - skip)
    1357             :                 {
    1358             :                         [gui setColor:[OOColor greenColor] forRow:start_row + i];
    1359             :                         [gui setArray:[NSArray arrayWithObjects:DESC(@"gui-more"), @" --> ", nil] forRow:start_row + i];
    1360             :                         [gui setKey:[NSString stringWithFormat:@"More:%ld", n_rows + skip] forRow:start_row + i];
    1361             :                         i++;
    1362             :                 }
    1363             :                 
    1364             :                 [gui setSelectableRange:NSMakeRange(GUI_ROW_KC_FUNCSTART, i + start_row - GUI_ROW_KC_FUNCSTART)];
    1365             :         }
    1366             : }
    1367             : 
    1368             : 
    1369             : 
    1370             : // return an array of all functions currently in conflict
    1371           0 : - (NSArray *) validateAllKeys
    1372             : {
    1373             :         NSMutableArray *failed = [[NSMutableArray alloc] init];
    1374             :         NSString *validate = nil;
    1375             :         NSUInteger i;
    1376             : 
    1377             :         for (i = 0; i < [keyFunctions count]; i++)
    1378             :         {
    1379             :                 NSDictionary *entry = [keyFunctions objectAtIndex:i];
    1380             :                 validate = [self validateKey:[entry objectForKey:KEY_KC_DEFINITION] checkKeys:(NSArray *)[keyconfig2_settings objectForKey:[entry objectForKey:KEY_KC_DEFINITION]]];
    1381             :                 if (validate) 
    1382             :                 {
    1383             :                         [failed addObject:validate];
    1384             :                 }
    1385             :         }
    1386             :         return [failed copy];
    1387             : }
    1388             : 
    1389             : 
    1390             : // validate a single key against any other key that might apply to it
    1391             : - (NSString *) validateKey:(NSString *)key checkKeys:(NSArray *)check_keys
    1392             : {
    1393             :         NSString *result = nil;
    1394             :         
    1395             :         // need to group keys into validation groups
    1396             :         NSArray *gui_keys = [NSArray arrayWithObjects:@"key_gui_arrow_left", @"key_gui_arrow_right", @"key_gui_arrow_up", @"key_gui_arrow_down", @"key_gui_page_up", 
    1397             :                 @"key_gui_page_down", @"key_gui_select", nil];
    1398             : 
    1399             :         if ([gui_keys containsObject:key]) 
    1400             :         {
    1401             :                 result = [self searchArrayForMatch:gui_keys key:key checkKeys:check_keys];
    1402             :                 if (result) return result;
    1403             :         }
    1404             : 
    1405             :         NSArray *debug_keys = [NSArray arrayWithObjects:
    1406             :                 @"key_dump_target_state", @"key_dump_entity_list", @"key_debug_full", @"key_debug_collision", @"key_debug_console_connect", @"key_debug_bounding_boxes", 
    1407             :                 @"key_debug_shaders", @"key_debug_off", nil];
    1408             : 
    1409             :         if ([debug_keys containsObject:key]) 
    1410             :         {
    1411             :                 result = [self searchArrayForMatch:debug_keys key:key checkKeys:check_keys];
    1412             :                 if (result) return result;
    1413             :         }
    1414             : 
    1415             :         NSArray *customview_keys = [NSArray arrayWithObjects:
    1416             :                 @"key_custom_view", @"key_custom_view_zoom_out", @"key_custom_view_zoom_in", @"key_custom_view_roll_left", @"key_custom_view_pan_left", 
    1417             :                 @"key_custom_view_roll_right", @"key_custom_view_pan_right", @"key_custom_view_rotate_up", @"key_custom_view_pan_up", @"key_custom_view_rotate_down", 
    1418             :                 @"key_custom_view_pan_down", @"key_custom_view_rotate_left", @"key_custom_view_rotate_right", nil];
    1419             : 
    1420             :         if ([customview_keys containsObject:key]) 
    1421             :         {
    1422             :                 result = [self searchArrayForMatch:customview_keys key:key checkKeys:check_keys];
    1423             :                 if (result) return result;
    1424             :         }
    1425             : 
    1426             :         NSMutableArray *inflight_keys = [NSMutableArray arrayWithObjects:
    1427             :                 @"key_roll_left", @"key_roll_right", @"key_pitch_forward", @"key_pitch_back", @"key_yaw_left", @"key_yaw_right", @"key_view_forward", @"key_view_aft", 
    1428             :                 @"key_view_port", @"key_view_starboard", @"key_increase_speed", @"key_decrease_speed", @"key_inject_fuel", @"key_fire_lasers", @"key_weapons_online_toggle", 
    1429             :                 @"key_launch_missile", @"key_next_missile", @"key_ecm", @"key_prime_next_equipment", @"key_prime_previous_equipment", @"key_activate_equipment", 
    1430             :                 @"key_mode_equipment", @"key_fastactivate_equipment_a", @"key_fastactivate_equipment_b", @"key_target_incoming_missile", @"key_target_missile", 
    1431             :                 @"key_untarget_missile", @"key_ident_system", @"key_scanner_zoom", @"key_scanner_unzoom", @"key_launch_escapepod", @"key_galactic_hyperspace", 
    1432             :                 @"key_hyperspace", @"key_jumpdrive", @"key_dump_cargo", @"key_rotate_cargo", @"key_autopilot", @"key_autodock", @"key_docking_clearance_request", 
    1433             :                 @"key_snapshot", @"key_cycle_next_mfd", @"key_cycle_previous_mfd", @"key_switch_next_mfd", @"key_switch_previous_mfd", 
    1434             :                 @"key_next_target", @"key_previous_target", @"key_comms_log", @"key_prev_compass_mode", @"key_next_compass_mode", @"key_custom_view", 
    1435             : #if OO_FOV_INFLIGHT_CONTROL_ENABLED
    1436             :                 @"key_inc_field_of_view", @"key_dec_field_of_view", 
    1437             : #endif
    1438             :                 @"key_pausebutton", @"key_dump_target_state", nil];
    1439             :         
    1440             :         if ([self entryIsCustomEquip:key]) {
    1441             :                 NSUInteger i;
    1442             :                 for (i = 0; i < [customEquipActivation count]; i++)
    1443             :                 {
    1444             :                         [inflight_keys addObject:[NSString stringWithFormat:@"activate_%@", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]]];
    1445             :                         [inflight_keys addObject:[NSString stringWithFormat:@"mode_%@", [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]]];
    1446             :                 }
    1447             :         }
    1448             : 
    1449             :         if ([inflight_keys containsObject:key]) 
    1450             :         {
    1451             :                 result = [self searchArrayForMatch:inflight_keys key:key checkKeys:check_keys];
    1452             :                 if (result) return result;
    1453             :         }
    1454             : 
    1455             :         NSArray *docking_keys = [NSArray arrayWithObjects:
    1456             :                 @"key_docking_music", @"key_autopilot", @"key_pausebutton", nil];
    1457             : 
    1458             :         if ([docking_keys containsObject:key]) 
    1459             :         {
    1460             :                 result = [self searchArrayForMatch:docking_keys key:key checkKeys:check_keys];
    1461             :                 if (result) return result;
    1462             :         }
    1463             : 
    1464             :         NSArray *docked_keys = [
    1465             :                 [NSArray arrayWithObjects:@"key_launch_ship", @"key_gui_screen_options", @"key_gui_screen_equipship", @"key_gui_screen_interfaces", @"key_gui_screen_status", 
    1466             :                 @"key_gui_chart_screens", @"key_gui_system_data", @"key_gui_market", nil]
    1467             :                 arrayByAddingObjectsFromArray:gui_keys];
    1468             : 
    1469             :         if ([docked_keys containsObject:key])
    1470             :         {
    1471             :                 result = [self searchArrayForMatch:docked_keys key:key checkKeys:check_keys];
    1472             :                 if (result) return result;
    1473             :         }
    1474             : 
    1475             :         NSArray *paused_keys = [[
    1476             :                 [NSArray arrayWithObjects:@"key_pausebutton", @"key_gui_screen_options", @"key_hud_toggle", @"key_show_fps", @"key_mouse_control_roll", 
    1477             :                 @"key_mouse_control_yaw", nil] 
    1478             :                 arrayByAddingObjectsFromArray:debug_keys]
    1479             :                 arrayByAddingObjectsFromArray:customview_keys];
    1480             : 
    1481             :         if ([paused_keys containsObject:key])
    1482             :         {
    1483             :                 result = [self searchArrayForMatch:paused_keys key:key checkKeys:check_keys];
    1484             :                 if (result) return result;
    1485             :         }
    1486             : 
    1487             :         NSArray *chart_keys = [NSArray arrayWithObjects:
    1488             :                 @"key_advanced_nav_array_next", @"key_advanced_nav_array_previous", @"key_map_home", @"key_map_end", @"key_map_info", 
    1489             :                 @"key_map_zoom_in", @"key_map_zoom_out", @"key_map_next_system", @"key_map_previous_system", @"key_chart_highlight", 
    1490             :                 @"key_launch_ship", @"key_gui_screen_options", @"key_gui_screen_equipship", @"key_gui_screen_interfaces", @"key_gui_screen_status", 
    1491             :                 @"key_gui_chart_screens", @"key_gui_system_data", @"key_gui_market", nil];
    1492             : 
    1493             :         if ([chart_keys containsObject:key])
    1494             :         {
    1495             :                 result = [self searchArrayForMatch:chart_keys key:key checkKeys:check_keys];
    1496             :                 if (result) return result;
    1497             :         }
    1498             : 
    1499             :         NSArray *sysinfo_keys = [NSArray arrayWithObjects:
    1500             :                 @"key_system_home", @"key_system_end", @"key_system_next_system", @"key_system_previous_system", 
    1501             :                 @"key_launch_ship", @"key_gui_screen_options", @"key_gui_screen_equipship", @"key_gui_screen_interfaces", @"key_gui_screen_status", 
    1502             :                 @"key_gui_chart_screens", @"key_gui_system_data", @"key_gui_market", nil];
    1503             : 
    1504             :         if ([sysinfo_keys containsObject:key])
    1505             :         {
    1506             :                 result = [self searchArrayForMatch:sysinfo_keys key:key checkKeys:check_keys];
    1507             :                 if (result) return result;
    1508             :         }
    1509             : 
    1510             :         NSArray *market_keys = [NSArray arrayWithObjects:
    1511             :                 @"key_market_filter_cycle", @"key_market_sorter_cycle", @"key_market_buy_one", @"key_market_sell_one", @"key_market_buy_max", 
    1512             :                 @"key_market_sell_max", @"key_launch_ship", @"key_gui_screen_options", @"key_gui_screen_equipship", @"key_gui_screen_interfaces", @"key_gui_screen_status", 
    1513             :                 @"key_gui_chart_screens", @"key_gui_system_data", @"key_gui_market", @"key_gui_arrow_up", @"key_gui_arrow_down", @"key_gui_page_up", 
    1514             :                 @"key_gui_page_down", @"key_gui_select", nil];
    1515             :                 
    1516             :         if ([market_keys containsObject:key])
    1517             :         {
    1518             :                 result = [self searchArrayForMatch:market_keys key:key checkKeys:check_keys];
    1519             :                 if (result) return result;
    1520             :         }
    1521             : 
    1522             :         // if we get here, we should be good
    1523             :         return nil;
    1524             : }
    1525             : 
    1526             : 
    1527             : // performs a search of all keys in the search_list, and for any key that isn't the one we've passed, check the 
    1528             : // keys against the values we're passing in. if there's a hit, return the key found
    1529           0 : - (NSString *) searchArrayForMatch:(NSArray *)search_list key:(NSString *)key checkKeys:(NSArray *)check_keys
    1530             : {
    1531             :         NSString *search = nil;
    1532             :         NSUInteger i, j, k;
    1533             :         for (i = 0; i < [search_list count]; i++)
    1534             :         {
    1535             :                 search = (NSString*)[search_list objectAtIndex:i];
    1536             :                 // only check other key settings, not the one we've been passed
    1537             :                 if (![search isEqualToString:key])
    1538             :                 {
    1539             :                         // get the array from keyconfig2_settings
    1540             :                         // we need to compare all entries to each other to look for any match, as any match would indicate a conflict
    1541             :                         NSArray *current = nil;
    1542             :                         if (![self entryIsCustomEquip:search])
    1543             :                         {
    1544             :                                 current = (NSArray *)[keyconfig2_settings objectForKey:search];
    1545             :                         }
    1546             :                         else 
    1547             :                         {
    1548             :                                 NSUInteger idx = [self getCustomEquipIndex:search];
    1549             :                                 NSString *keytype = [self getCustomEquipKeyDefType:search];
    1550             :                                 current = (NSArray *)[[customEquipActivation objectAtIndex:idx] objectForKey:keytype];
    1551             :                         }
    1552             :                         for (j = 0; j < [current count]; j++) 
    1553             :                         {
    1554             :                                 for (k = 0; k < [check_keys count]; k++)
    1555             :                                 {
    1556             :                                         if ([self compareKeyEntries:[current objectAtIndex:j] second:[check_keys objectAtIndex:k]]) return search;
    1557             :                                 }
    1558             :                         }
    1559             :                 }
    1560             :         }
    1561             :         return nil;
    1562             : }
    1563             : 
    1564             : 
    1565             : // compares the currently stored key_list against the base default from keyconfig2.plist
    1566           0 : - (BOOL) entryIsEqualToDefault:(NSString*)key
    1567             : {
    1568             :         NSArray *def = (NSArray *)[kdic_check objectForKey:key];
    1569             :         NSUInteger i;
    1570             : 
    1571             :         if ([def count] != [key_list count]) return NO;
    1572             :         for (i = 0; i < [key_list count]; i++)
    1573             :         {
    1574             :                 NSDictionary *orig = (NSDictionary *)[def objectAtIndex:i];
    1575             :                 NSDictionary *entrd = (NSDictionary *)[key_list objectAtIndex:i];
    1576             :                 if (![self compareKeyEntries:orig second:entrd]) return NO;
    1577             :         }
    1578             :         return YES;
    1579             : }
    1580             : 
    1581             : 
    1582             : // compares two key dictionaries to see if they have the same settings
    1583           0 : - (BOOL) compareKeyEntries:(NSDictionary*)first second:(NSDictionary*)second
    1584             : {
    1585             :         if ([(NSString *)[first objectForKey:@"key"] integerValue] == [(NSString *)[second objectForKey:@"key"] integerValue])
    1586             :         {
    1587             :                 if ([[first objectForKey:@"shift"] boolValue] == [[second objectForKey:@"shift"] boolValue] &&
    1588             :                         [[first objectForKey:@"mod1"] boolValue] == [[second objectForKey:@"mod1"] boolValue] &&
    1589             :                         [[first objectForKey:@"mod2"] boolValue] == [[second objectForKey:@"mod2"] boolValue]) 
    1590             :                         return YES;
    1591             :         }
    1592             :         return NO;
    1593             : }
    1594             : 
    1595             : 
    1596             : // saves the currently store key_list to the defaults file and updates the global definition
    1597           0 : - (void) saveKeySetting:(NSString*)key
    1598             : {
    1599             :         // check for a blank entry
    1600             :         if ([key_list count] > 1 && [[(NSDictionary*)[key_list objectAtIndex:1] objectForKey:@"key"] integerValue] == 0) 
    1601             :         {
    1602             :                 [key_list removeObjectAtIndex:1];
    1603             :         }
    1604             :         // make sure the primary and alternate keys are different
    1605             :         if ([key_list count] > 1) {
    1606             :                 if ([self compareKeyEntries:[key_list objectAtIndex:0] second:[key_list objectAtIndex:1]])
    1607             :                 {
    1608             :                         [key_list removeObjectAtIndex:1];
    1609             :                 }
    1610             :         }
    1611             :         // see if we've set the key settings to blank - in which case, delete the override
    1612             :         if ([[(NSDictionary*)[key_list objectAtIndex:0] objectForKey:@"key"] integerValue] == 0)
    1613             :         {
    1614             :                 if ([key_list count] == 1 || ([key_list count] > 1 && [[(NSDictionary*)[key_list objectAtIndex:1] objectForKey:@"key"] isEqualToString:@""]))
    1615             :                 {
    1616             :                         [self deleteKeySetting:key];
    1617             :                         // reload settings
    1618             :                         [self initKeyConfigSettings];
    1619             :                         [self reloadPage];
    1620             :                         return;
    1621             :                 }
    1622             :         }
    1623             : 
    1624             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1625             : 
    1626             :         if (![self entryIsCustomEquip:key])
    1627             :         {
    1628             :                 // if we've got the same settings as the default, revert to the default
    1629             :                 if ([self entryIsEqualToDefault:key])
    1630             :                 {
    1631             :                         [self deleteKeySetting:key];
    1632             :                         // reload settings
    1633             :                         [self initKeyConfigSettings];
    1634             :                         [self reloadPage];
    1635             :                         return;
    1636             :                 }
    1637             :                 NSMutableDictionary *keyconf = [NSMutableDictionary dictionaryWithDictionary:[defaults objectForKey:KEYCONFIG_OVERRIDES]];
    1638             :                 [keyconf setObject:key_list forKey:key];
    1639             :                 [defaults setObject:keyconf forKey:KEYCONFIG_OVERRIDES];
    1640             :         }
    1641             :         else 
    1642             :         {
    1643             :                 NSUInteger idx = [self getCustomEquipIndex:key];
    1644             :                 NSString *custkey = [self getCustomEquipKeyDefType:key];
    1645             :                 NSMutableDictionary *custEquip = [[customEquipActivation objectAtIndex:idx] mutableCopy];
    1646             :                 [custEquip setObject:key_list forKey:custkey];
    1647             :                 [customEquipActivation replaceObjectAtIndex:idx withObject:custEquip];
    1648             :                 [defaults setObject:customEquipActivation forKey:KEYCONFIG_CUSTOMEQUIP];
    1649             :         }
    1650             :         // reload settings
    1651             :         [self initKeyConfigSettings];
    1652             :         [self reloadPage];
    1653             : }
    1654             : 
    1655             : // unsets the key setting in the overrides, and updates the global definition
    1656           0 : - (void) unsetKeySetting:(NSString*)key
    1657             : {
    1658             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1659             :         if (![self entryIsCustomEquip:key])
    1660             :         {
    1661             :                 NSMutableDictionary *keyconf = [NSMutableDictionary dictionaryWithDictionary:[defaults objectForKey:KEYCONFIG_OVERRIDES]];
    1662             :                 NSMutableArray *empty = [[NSMutableArray alloc] init];
    1663             :                 [keyconf setObject:empty forKey:key];
    1664             :                 [defaults setObject:keyconf forKey:KEYCONFIG_OVERRIDES];
    1665             :                 [empty release];
    1666             :         }
    1667             :         else 
    1668             :         {
    1669             :                 NSString *custkey = [self getCustomEquipKeyDefType:key];
    1670             :                 [[customEquipActivation objectAtIndex:[self getCustomEquipIndex:key]] removeObjectForKey:custkey];
    1671             :                 [defaults setObject:customEquipActivation forKey:KEYCONFIG_CUSTOMEQUIP];
    1672             :         }
    1673             :         // reload settings
    1674             :         [self initKeyConfigSettings];
    1675             : }
    1676             : 
    1677             : 
    1678             : // removes the key setting from the overrides, and updates the global definition
    1679           0 : - (void) deleteKeySetting:(NSString*)key
    1680             : {
    1681             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1682             :         if (![self entryIsCustomEquip:key])
    1683             :         {
    1684             :                 NSMutableDictionary *keyconf = [NSMutableDictionary dictionaryWithDictionary:[defaults objectForKey:KEYCONFIG_OVERRIDES]];
    1685             :                 [keyconf removeObjectForKey:key];
    1686             :                 [defaults setObject:keyconf forKey:KEYCONFIG_OVERRIDES];
    1687             :         }
    1688             :         else 
    1689             :         {
    1690             :                 NSString *custkey = [self getCustomEquipKeyDefType:key];
    1691             :                 [[customEquipActivation objectAtIndex:[self getCustomEquipIndex:key]] removeObjectForKey:custkey];
    1692             :                 [defaults setObject:customEquipActivation forKey:KEYCONFIG_CUSTOMEQUIP];
    1693             :         }
    1694             :         // reload settings
    1695             :         [self initKeyConfigSettings];
    1696             : }
    1697             : 
    1698             : 
    1699             : // removes all key settings from the overrides, and updates the global definition
    1700           0 : - (void) deleteAllKeySettings
    1701             : {
    1702             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1703             :         [defaults removeObjectForKey:KEYCONFIG_OVERRIDES];
    1704             :         if ([customEquipActivation count] > 0)
    1705             :         {
    1706             :                 NSUInteger i;
    1707             :                 for (i = 0; i < [customEquipActivation count]; i++)
    1708             :                 {
    1709             :                         NSString *eq = [[customEquipActivation objectAtIndex:i] oo_stringForKey:CUSTOMEQUIP_EQUIPKEY];
    1710             :                         OOEquipmentType *item = [OOEquipmentType equipmentTypeWithIdentifier:eq];
    1711             :                         if ([item defaultActivateKey]) 
    1712             :                                 [[customEquipActivation objectAtIndex:i] setObject:[item defaultActivateKey] forKey:CUSTOMEQUIP_KEYACTIVATE];
    1713             :                         else
    1714             :                                 [[customEquipActivation objectAtIndex:i] removeObjectForKey:CUSTOMEQUIP_KEYACTIVATE];
    1715             : 
    1716             :                         if ([item defaultModeKey])
    1717             :                                 [[customEquipActivation objectAtIndex:i] setObject:[item defaultModeKey] forKey:CUSTOMEQUIP_KEYMODE];
    1718             :                         else
    1719             :                                 [[customEquipActivation objectAtIndex:i] removeObjectForKey:CUSTOMEQUIP_KEYMODE];
    1720             :                 }
    1721             :                 [defaults setObject:customEquipActivation forKey:KEYCONFIG_CUSTOMEQUIP];
    1722             :         }
    1723             :         // reload settings
    1724             :         [self initKeyConfigSettings];
    1725             : }
    1726             : 
    1727             : 
    1728             : // returns all key settings from the overrides
    1729           0 : - (NSDictionary *) loadKeySettings
    1730             : {
    1731             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    1732             :         return [defaults objectForKey:KEYCONFIG_OVERRIDES];
    1733             : }
    1734             : 
    1735             : 
    1736             : // reloads the main page at the appropriate page
    1737           0 : - (void) reloadPage
    1738             : {
    1739             :         // Update the GUI (this will refresh the function list).
    1740             :         unsigned skip;
    1741             :         if (selFunctionIdx < MAX_ROWS_KC_FUNCTIONS - 1)
    1742             :         {
    1743             :                 skip = 0;
    1744             :         }
    1745             :         else
    1746             :         {
    1747             :                 skip = ((selFunctionIdx - 1) / (MAX_ROWS_KC_FUNCTIONS - 2)) * (MAX_ROWS_KC_FUNCTIONS - 2) + 1;
    1748             :         }
    1749             :         
    1750             :         [self setGuiToKeyMapperScreen:skip];
    1751             : }
    1752             : 
    1753             : @end

Generated by: LCOV version 1.14