(svn r23005) -Fix (r23004): Of course there's still the 16-sprite version for shore...
[openttd/fttd.git] / src / hotkeys.cpp
blob674c10c73f22921162dc8c3b48451762b72ab71b
1 /* $Id$ */
3 /*
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/>.
8 */
10 /** @file hotkeys.cpp Implementation of hotkey related functions */
12 #include "stdafx.h"
13 #include "openttd.h"
14 #include "hotkeys.h"
15 #include "ini_type.h"
16 #include "string_func.h"
17 #include "window_gui.h"
19 char *_hotkeys_file;
21 /** String representation of a keycode */
22 struct KeycodeNames {
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[] = {
29 {"SHIFT", WKC_SHIFT},
30 {"CTRL", WKC_CTRL},
31 {"ALT", WKC_ALT},
32 {"META", WKC_META},
33 {"GLOBAL", WKC_GLOBAL_HOTKEY},
34 {"ESC", WKC_ESC},
35 {"DEL", WKC_DELETE},
36 {"RETURN", WKC_RETURN},
37 {"BACKQUOTE", WKC_BACKQUOTE},
38 {"F1", WKC_F1},
39 {"F2", WKC_F2},
40 {"F3", WKC_F3},
41 {"F4", WKC_F4},
42 {"F5", WKC_F5},
43 {"F6", WKC_F6},
44 {"F7", WKC_F7},
45 {"F8", WKC_F8},
46 {"F9", WKC_F9},
47 {"F10", WKC_F10},
48 {"F11", WKC_F11},
49 {"F12", WKC_F12},
50 {"PAUSE", WKC_PAUSE},
51 {"PLUS", (WindowKeyCodes)'+'},
52 {"COMMA", (WindowKeyCodes)','},
53 {"NUM_PLUS", WKC_NUM_PLUS},
54 {"NUM_MINUS", WKC_NUM_MINUS},
55 {"=", WKC_EQUALS},
56 {"-", WKC_MINUS},
59 /**
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)
67 assert(start <= 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;
80 return 0;
83 /**
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)
91 assert(start <= end);
92 uint16 keycode = 0;
93 for (;;) {
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;
101 keycode |= code;
102 } else {
103 /* Ignore the code if it has more then 1 letter. */
104 if (keycode & ~WKC_SPECIAL_KEYS) return 0;
105 keycode |= code;
107 if (cur == end) break;
108 assert(cur < end);
109 start = cur + 1;
111 return keycode;
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
119 template<class T>
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
135 * by a '+'.
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)
143 static char buf[32];
144 buf[0] = '\0';
145 bool first = true;
146 if (keycode & WKC_GLOBAL_HOTKEY) {
147 strecat(buf, "GLOBAL", lastof(buf));
148 first = false;
150 if (keycode & WKC_SHIFT) {
151 if (!first) strecat(buf, "+", lastof(buf));
152 strecat(buf, "SHIFT", lastof(buf));
153 first = false;
155 if (keycode & WKC_CTRL) {
156 if (!first) strecat(buf, "+", lastof(buf));
157 strecat(buf, "CTRL", lastof(buf));
158 first = false;
160 if (keycode & WKC_ALT) {
161 if (!first) strecat(buf, "+", lastof(buf));
162 strecat(buf, "ALT", lastof(buf));
163 first = false;
165 if (keycode & WKC_META) {
166 if (!first) strecat(buf, "+", lastof(buf));
167 strecat(buf, "META", lastof(buf));
168 first = false;
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));
176 return buf;
179 assert(keycode < 128);
180 char key[2];
181 key[0] = keycode;
182 key[1] = '\0';
183 strecat(buf, key, lastof(buf));
184 return 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.
195 template<class T>
196 const char *SaveKeycodes(const Hotkey<T> *hotkey)
198 static char buf[128];
199 buf[0] = '\0';
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));
205 return buf;
208 template<class T>
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);
214 if (item != NULL) {
215 hotkey->keycodes.Clear();
216 if (item->value != NULL) ParseHotkeys(hotkey, item->value);
221 template<class T>
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));
231 template<class T>
232 void SaveLoadHotkeyGroup(IniGroup *group, T *hotkey_list, bool save)
234 if (save) {
235 SaveHotkeyGroup(group, hotkey_list);
236 } else {
237 LoadHotkeyGroup(group, hotkey_list);
241 struct MainWindow;
242 struct MainToolbarWindow;
243 struct ScenarioEditorToolbarWindow;
244 struct TerraformToolbarWindow;
245 struct ScenarioEditorLandscapeGenerationWindow;
246 struct OrdersWindow;
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);
258 IniGroup *group;
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);
278 #undef SL_HOTKEYS
279 if (save) ini->SaveToDisk(_hotkeys_file);
280 delete ini;
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;