4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file hotkeys.cpp Implementation of hotkey related functions */
16 #include "string_func.h"
17 #include "window_gui.h"
21 /** String representation of a keycode */
23 const char *name
; ///< Name of the keycode
24 WindowKeyCodes keycode
; ///< The keycode
27 /** Array of non-standard keycodes that can be used in the hotkeys config file. */
28 static const KeycodeNames _keycode_to_name
[] = {
33 {"GLOBAL", WKC_GLOBAL_HOTKEY
},
36 {"RETURN", WKC_RETURN
},
37 {"BACKQUOTE", WKC_BACKQUOTE
},
51 {"PLUS", (WindowKeyCodes
)'+'},
52 {"COMMA", (WindowKeyCodes
)','},
53 {"NUM_PLUS", WKC_NUM_PLUS
},
54 {"NUM_MINUS", WKC_NUM_MINUS
},
60 * Try to parse a single part of a keycode.
61 * @param start Start of the string to parse.
62 * @param end End of the string to parse.
63 * @return A keycode if a match is found or 0.
65 static uint16
ParseCode(const char *start
, const char *end
)
68 while (start
< end
&& *start
== ' ') start
++;
69 while (end
> start
&& *end
== ' ') end
--;
70 for (uint i
= 0; i
< lengthof(_keycode_to_name
); i
++) {
71 if (strlen(_keycode_to_name
[i
].name
) == (size_t)(end
- start
) && strncasecmp(start
, _keycode_to_name
[i
].name
, end
- start
) == 0) {
72 return _keycode_to_name
[i
].keycode
;
75 if (end
- start
== 1) {
76 if (*start
>= 'a' && *start
<= 'z') return *start
- ('a'-'A');
77 /* Ignore invalid keycodes */
78 if (*(uint8
*)start
< 128) return *start
;
84 * Parse a string representation of a keycode.
85 * @param start Start of the input.
86 * @param end End of the input.
87 * @return A valid keycode or 0.
89 static uint16
ParseKeycode(const char *start
, const char *end
)
94 const char *cur
= start
;
95 while (*cur
!= '+' && cur
!= end
) cur
++;
96 uint16 code
= ParseCode(start
, cur
);
97 if (code
== 0) return 0;
98 if (code
& WKC_SPECIAL_KEYS
) {
99 /* Some completely wrong keycode we don't support. */
100 if (code
& ~WKC_SPECIAL_KEYS
) return 0;
103 /* Ignore the code if it has more then 1 letter. */
104 if (keycode
& ~WKC_SPECIAL_KEYS
) return 0;
107 if (cur
== end
) break;
115 * Parse a string to the keycodes it represents
116 * @param hotkey The hotkey object to add the keycodes to
117 * @param value The string to parse
120 static void ParseHotkeys(Hotkey
<T
> *hotkey
, const char *value
)
122 const char *start
= value
;
123 while (*start
!= '\0') {
124 const char *end
= start
;
125 while (*end
!= '\0' && *end
!= ',') end
++;
126 uint16 keycode
= ParseKeycode(start
, end
);
127 if (keycode
!= 0) hotkey
->AddKeycode(keycode
);
128 start
= (*end
== ',') ? end
+ 1: end
;
133 * Convert a hotkey to it's string representation so it can be written to the
134 * config file. Seperate parts of the keycode (like "CTRL" and "F1" are split
136 * @param keycode The keycode to convert to a string.
137 * @return A string representation of this keycode.
138 * @note The return value is a static buffer, strdup the result before calling
139 * this function again.
141 static const char *KeycodeToString(uint16 keycode
)
146 if (keycode
& WKC_GLOBAL_HOTKEY
) {
147 strecat(buf
, "GLOBAL", lastof(buf
));
150 if (keycode
& WKC_SHIFT
) {
151 if (!first
) strecat(buf
, "+", lastof(buf
));
152 strecat(buf
, "SHIFT", lastof(buf
));
155 if (keycode
& WKC_CTRL
) {
156 if (!first
) strecat(buf
, "+", lastof(buf
));
157 strecat(buf
, "CTRL", lastof(buf
));
160 if (keycode
& WKC_ALT
) {
161 if (!first
) strecat(buf
, "+", lastof(buf
));
162 strecat(buf
, "ALT", lastof(buf
));
165 if (keycode
& WKC_META
) {
166 if (!first
) strecat(buf
, "+", lastof(buf
));
167 strecat(buf
, "META", lastof(buf
));
170 if (!first
) strecat(buf
, "+", lastof(buf
));
171 keycode
= keycode
& ~WKC_SPECIAL_KEYS
;
173 for (uint i
= 0; i
< lengthof(_keycode_to_name
); i
++) {
174 if (_keycode_to_name
[i
].keycode
== keycode
) {
175 strecat(buf
, _keycode_to_name
[i
].name
, lastof(buf
));
179 assert(keycode
< 128);
183 strecat(buf
, key
, lastof(buf
));
188 * Convert all keycodes attached to a hotkey to a single string. If multiple
189 * keycodes are attached to the hotkey they are split by a comma.
190 * @param hotkey The keycodes of this hotkey need to be converted to a string.
191 * @return A string representation of all keycodes.
192 * @note The return value is a static buffer, strdup the result before calling
193 * this function again.
196 const char *SaveKeycodes(const Hotkey
<T
> *hotkey
)
198 static char buf
[128];
200 for (uint i
= 0; i
< hotkey
->keycodes
.Length(); i
++) {
201 const char *str
= KeycodeToString(hotkey
->keycodes
[i
]);
202 if (i
> 0) strecat(buf
, ",", lastof(buf
));
203 strecat(buf
, str
, lastof(buf
));
209 void LoadHotkeyGroup(IniGroup
*group
, T
*hotkey_list
)
211 for (uint i
= 0; hotkey_list
[i
].num
!= -1; i
++) {
212 T
*hotkey
= &hotkey_list
[i
];
213 IniItem
*item
= group
->GetItem(hotkey
->name
, false);
215 hotkey
->keycodes
.Clear();
216 if (item
->value
!= NULL
) ParseHotkeys(hotkey
, item
->value
);
222 void SaveHotkeyGroup(IniGroup
*group
, T
*hotkey_list
)
224 for (uint i
= 0; hotkey_list
[i
].num
!= -1; i
++) {
225 T
*hotkey
= &hotkey_list
[i
];
226 IniItem
*item
= group
->GetItem(hotkey
->name
, true);
227 item
->SetValue(SaveKeycodes(hotkey
));
232 void SaveLoadHotkeyGroup(IniGroup
*group
, T
*hotkey_list
, bool save
)
235 SaveHotkeyGroup(group
, hotkey_list
);
237 LoadHotkeyGroup(group
, hotkey_list
);
242 struct MainToolbarWindow
;
243 struct ScenarioEditorToolbarWindow
;
244 struct TerraformToolbarWindow
;
245 struct ScenarioEditorLandscapeGenerationWindow
;
247 struct BuildAirToolbarWindow
;
248 struct BuildDocksToolbarWindow
;
249 struct BuildRailToolbarWindow
;
250 struct BuildRoadToolbarWindow
;
251 struct SignListWindow
;
253 static void SaveLoadHotkeys(bool save
)
255 IniFile
*ini
= new IniFile();
256 ini
->LoadFromDisk(_hotkeys_file
, BASE_DIR
);
260 #define SL_HOTKEYS(name, window_name) \
261 extern Hotkey<window_name> *_##name##_hotkeys;\
262 group = ini->GetGroup(#name);\
263 SaveLoadHotkeyGroup(group, _##name##_hotkeys, save);
265 SL_HOTKEYS(global
, MainWindow
);
266 SL_HOTKEYS(maintoolbar
, MainToolbarWindow
);
267 SL_HOTKEYS(scenedit_maintoolbar
, ScenarioEditorToolbarWindow
);
268 SL_HOTKEYS(terraform
, TerraformToolbarWindow
);
269 SL_HOTKEYS(terraform_editor
, ScenarioEditorLandscapeGenerationWindow
);
270 SL_HOTKEYS(order
, OrdersWindow
);
271 SL_HOTKEYS(airtoolbar
, BuildAirToolbarWindow
);
272 SL_HOTKEYS(dockstoolbar
, BuildDocksToolbarWindow
);
273 SL_HOTKEYS(railtoolbar
, BuildRailToolbarWindow
);
274 SL_HOTKEYS(roadtoolbar
, BuildRoadToolbarWindow
);
275 SL_HOTKEYS(signlist
, SignListWindow
);
279 if (save
) ini
->SaveToDisk(_hotkeys_file
);
284 /** Load the hotkeys from the config file */
285 void LoadHotkeysFromConfig()
287 SaveLoadHotkeys(false);
290 /** Save the hotkeys to the config file */
291 void SaveHotkeysToConfig()
293 SaveLoadHotkeys(true);
296 typedef EventState
GlobalHotkeyHandler(uint16
, uint16
);
298 GlobalHotkeyHandler RailToolbarGlobalHotkeys
;
299 GlobalHotkeyHandler DockToolbarGlobalHotkeys
;
300 GlobalHotkeyHandler AirportToolbarGlobalHotkeys
;
301 GlobalHotkeyHandler TerraformToolbarGlobalHotkeys
;
302 GlobalHotkeyHandler TerraformToolbarEditorGlobalHotkeys
;
303 GlobalHotkeyHandler RoadToolbarGlobalHotkeys
;
304 GlobalHotkeyHandler RoadToolbarEditorGlobalHotkeys
;
305 GlobalHotkeyHandler SignListGlobalHotkeys
;
308 GlobalHotkeyHandler
*_global_hotkey_handlers
[] = {
309 RailToolbarGlobalHotkeys
,
310 DockToolbarGlobalHotkeys
,
311 AirportToolbarGlobalHotkeys
,
312 TerraformToolbarGlobalHotkeys
,
313 RoadToolbarGlobalHotkeys
,
314 SignListGlobalHotkeys
,
317 GlobalHotkeyHandler
*_global_hotkey_handlers_editor
[] = {
318 TerraformToolbarEditorGlobalHotkeys
,
319 RoadToolbarEditorGlobalHotkeys
,
323 void HandleGlobalHotkeys(uint16 key
, uint16 keycode
)
325 if (_game_mode
== GM_NORMAL
) {
326 for (uint i
= 0; i
< lengthof(_global_hotkey_handlers
); i
++) {
327 if (_global_hotkey_handlers
[i
](key
, keycode
) == ES_HANDLED
) return;
329 } else if (_game_mode
== GM_EDITOR
) {
330 for (uint i
= 0; i
< lengthof(_global_hotkey_handlers_editor
); i
++) {
331 if (_global_hotkey_handlers_editor
[i
](key
, keycode
) == ES_HANDLED
) return;