@@ -22,6 +22,7 @@ Config g_config;
22
22
#define C (x ) REMAP_SDL_KEYCODE(x) | kKeyMod_Ctrl
23
23
#define N 0
24
24
static const uint16 kDefaultKbdControls [kKeys_Total ] = {
25
+ 0 ,
25
26
// Controls
26
27
_ (SDLK_UP ), _ (SDLK_DOWN ), _ (SDLK_LEFT ), _ (SDLK_RIGHT ), _ (SDLK_RSHIFT ), _ (SDLK_RETURN ), _ (SDLK_x ), _ (SDLK_z ), _ (SDLK_s ), _ (SDLK_a ), _ (SDLK_c ), _ (SDLK_v ),
27
28
// LoadState
@@ -53,6 +54,7 @@ typedef struct KeyNameId {
53
54
#define M (n ) {#n, kKeys_##n, kKeys_##n##_Last - kKeys_##n + 1}
54
55
#define S (n ) {#n, kKeys_##n, 1}
55
56
static const KeyNameId kKeyNameId [] = {
57
+ {"Null" , kKeys_Null , 65535 },
56
58
M (Controls ), M (Load ), M (Save ), M (Replay ), M (LoadRef ), M (ReplayRef ),
57
59
S (CheatLife ), S (CheatKeys ), S (CheatEquipment ), S (CheatWalkThroughWalls ),
58
60
S (ClearKeyLog ), S (StopReplay ), S (Fullscreen ), S (Reset ),
@@ -69,7 +71,7 @@ static KeyMapHashEnt *keymap_hash;
69
71
static int keymap_hash_size ;
70
72
static bool has_keynameid [countof (kKeyNameId )];
71
73
72
- bool KeyMapHash_Add (uint16 key , uint16 cmd ) {
74
+ static bool KeyMapHash_Add (uint16 key , uint16 cmd ) {
73
75
if ((keymap_hash_size & 0xff ) == 0 ) {
74
76
if (keymap_hash_size > 10000 )
75
77
Die ("Too many keys" );
@@ -101,12 +103,12 @@ static int KeyMapHash_Find(uint16 key) {
101
103
return ent -> cmd ;
102
104
i = ent -> next ;
103
105
}
104
- return -1 ;
106
+ return 0 ;
105
107
}
106
108
107
109
int FindCmdForSdlKey (SDL_Keycode code , SDL_Keymod mod ) {
108
110
if (code & ~(SDLK_SCANCODE_MASK | 0x1ff ))
109
- return -1 ;
111
+ return 0 ;
110
112
int key = mod & KMOD_ALT ? kKeyMod_Alt : 0 ;
111
113
key |= mod & KMOD_CTRL ? kKeyMod_Ctrl : 0 ;
112
114
key |= mod & KMOD_SHIFT ? kKeyMod_Shift : 0 ;
@@ -117,7 +119,7 @@ int FindCmdForSdlKey(SDL_Keycode code, SDL_Keymod mod) {
117
119
static void ParseKeyArray (char * value , int cmd , int size ) {
118
120
char * s ;
119
121
int i = 0 ;
120
- for (; i < size && (s = NextDelim (& value , ',' )) != NULL ; i ++ , cmd ++ ) {
122
+ for (; i < size && (s = NextDelim (& value , ',' )) != NULL ; i ++ , cmd += ( cmd != 0 ) ) {
121
123
if (* s == 0 )
122
124
continue ;
123
125
int key_with_mod = 0 ;
@@ -142,14 +144,120 @@ static void ParseKeyArray(char *value, int cmd, int size) {
142
144
}
143
145
}
144
146
147
+ typedef struct GamepadMapEnt {
148
+ uint32 modifiers ;
149
+ uint16 cmd , next ;
150
+ } GamepadMapEnt ;
151
+
152
+ static uint16 joymap_first [kGamepadBtn_Count ];
153
+ static GamepadMapEnt * joymap_ents ;
154
+ static int joymap_size ;
155
+ static bool has_joypad_controls ;
156
+
157
+ static int CountBits32 (uint32 n ) {
158
+ int count = 0 ;
159
+ for (; n != 0 ; count ++ )
160
+ n &= (n - 1 );
161
+ return count ;
162
+ }
163
+
164
+ static void GamepadMap_Add (int button , uint32 modifiers , uint16 cmd ) {
165
+ if ((joymap_size & 0xff ) == 0 ) {
166
+ if (joymap_size > 1000 )
167
+ Die ("Too many joypad keys" );
168
+ joymap_ents = realloc (joymap_ents , sizeof (GamepadMapEnt ) * (joymap_size + 64 ));
169
+ if (!joymap_ents ) Die ("realloc failure" );
170
+ }
171
+ uint16 * p = & joymap_first [button ];
172
+ // Insert it as early as possible but before after any entry with more modifiers.
173
+ int cb = CountBits32 (modifiers );
174
+ while (* p && cb < CountBits32 (joymap_ents [* p - 1 ].modifiers ))
175
+ p = & joymap_ents [* p - 1 ].next ;
176
+ int i = joymap_size ++ ;
177
+ GamepadMapEnt * ent = & joymap_ents [i ];
178
+ ent -> modifiers = modifiers ;
179
+ ent -> cmd = cmd ;
180
+ ent -> next = * p ;
181
+ * p = i + 1 ;
182
+ }
183
+
184
+ int FindCmdForGamepadButton (int button , uint32 modifiers ) {
185
+ GamepadMapEnt * ent ;
186
+ for (int e = joymap_first [button ]; e != 0 ; e = ent -> next ) {
187
+ ent = & joymap_ents [e - 1 ];
188
+ if ((modifiers & ent -> modifiers ) == ent -> modifiers )
189
+ return ent -> cmd ;
190
+ }
191
+ return 0 ;
192
+ }
193
+
194
+ static int ParseGamepadButtonName (const char * * value ) {
195
+ const char * s = * value ;
196
+ // Longest substring first
197
+ static const char * const kGamepadKeyNames [] = {
198
+ "Back" , "Guide" , "Start" , "L3" , "R3" ,
199
+ "L1" , "R1" , "DpadUp" , "DpadDown" , "DpadLeft" , "DpadRight" , "L2" , "R2" ,
200
+ "Lb" , "Rb" , "A" , "B" , "X" , "Y"
201
+ };
202
+ static const uint8 kGamepadKeyIds [] = {
203
+ kGamepadBtn_Back , kGamepadBtn_Guide , kGamepadBtn_Start , kGamepadBtn_L3 , kGamepadBtn_R3 ,
204
+ kGamepadBtn_L1 , kGamepadBtn_R1 , kGamepadBtn_DpadUp , kGamepadBtn_DpadDown , kGamepadBtn_DpadLeft , kGamepadBtn_DpadRight , kGamepadBtn_L2 , kGamepadBtn_R2 ,
205
+ kGamepadBtn_L1 , kGamepadBtn_R1 , kGamepadBtn_A , kGamepadBtn_B , kGamepadBtn_X , kGamepadBtn_Y ,
206
+ };
207
+ for (size_t i = 0 ; i != countof (kGamepadKeyNames ); i ++ ) {
208
+ const char * r = StringStartsWithNoCase (s , kGamepadKeyNames [i ]);
209
+ if (r ) {
210
+ * value = r ;
211
+ return kGamepadKeyIds [i ];
212
+ }
213
+ }
214
+ return kGamepadBtn_Invalid ;
215
+ }
216
+
217
+ static const uint8 kDefaultGamepadCmds [] = {
218
+ kGamepadBtn_DpadUp , kGamepadBtn_DpadDown , kGamepadBtn_DpadLeft , kGamepadBtn_DpadRight , kGamepadBtn_Back , kGamepadBtn_Start ,
219
+ kGamepadBtn_B , kGamepadBtn_A , kGamepadBtn_Y , kGamepadBtn_X , kGamepadBtn_L1 , kGamepadBtn_R1 ,
220
+ };
221
+
222
+ static void ParseGamepadArray (char * value , int cmd , int size ) {
223
+ char * s ;
224
+ int i = 0 ;
225
+ for (; i < size && (s = NextDelim (& value , ',' )) != NULL ; i ++ , cmd += (cmd != 0 )) {
226
+ if (* s == 0 )
227
+ continue ;
228
+ uint32 modifiers = 0 ;
229
+ const char * ss = s ;
230
+ for (;;) {
231
+ int button = ParseGamepadButtonName (& ss );
232
+ if (button == kGamepadBtn_Invalid ) BAD : {
233
+ fprintf (stderr , "Unknown gamepad button: '%s'\n" , s );
234
+ break ;
235
+ }
236
+ while (* ss == ' ' || * ss == '\t' ) ss ++ ;
237
+ if (* ss == '+' ) {
238
+ ss ++ ;
239
+ modifiers |= 1 << button ;
240
+ } else if (* ss == 0 ) {
241
+ GamepadMap_Add (button , modifiers , cmd );
242
+ break ;
243
+ } else
244
+ goto BAD ;
245
+ }
246
+ }
247
+ }
248
+
145
249
static void RegisterDefaultKeys () {
146
- for (int i = 0 ; i < countof (kKeyNameId ); i ++ ) {
250
+ for (int i = 1 ; i < countof (kKeyNameId ); i ++ ) {
147
251
if (!has_keynameid [i ]) {
148
252
int size = kKeyNameId [i ].size , k = kKeyNameId [i ].id ;
149
253
for (int j = 0 ; j < size ; j ++ , k ++ )
150
254
KeyMapHash_Add (kDefaultKbdControls [k ], k );
151
255
}
152
256
}
257
+ if (!has_joypad_controls ) {
258
+ for (int i = 0 ; i < countof (kDefaultGamepadCmds ); i ++ )
259
+ GamepadMap_Add (kDefaultGamepadCmds [i ], 0 , kKeys_Controls + i );
260
+ }
153
261
}
154
262
155
263
static int GetIniSection (const char * s ) {
@@ -163,6 +271,8 @@ static int GetIniSection(const char *s) {
163
271
return 3 ;
164
272
if (StringEqualsNoCase (s , "[Features]" ))
165
273
return 4 ;
274
+ if (StringEqualsNoCase (s , "[GamepadMap]" ))
275
+ return 5 ;
166
276
return -1 ;
167
277
}
168
278
@@ -205,6 +315,15 @@ static bool HandleIniConfig(int section, const char *key, char *value) {
205
315
return true;
206
316
}
207
317
}
318
+ } else if (section == 5 ) {
319
+ for (int i = 0 ; i < countof (kKeyNameId ); i ++ ) {
320
+ if (StringEqualsNoCase (key , kKeyNameId [i ].name )) {
321
+ if (i == 1 )
322
+ has_joypad_controls = true;
323
+ ParseGamepadArray (value , kKeyNameId [i ].id , kKeyNameId [i ].size );
324
+ return true;
325
+ }
326
+ }
208
327
} else if (section == 1 ) {
209
328
if (StringEqualsNoCase (key , "WindowSize" )) {
210
329
char * s ;
0 commit comments