Translations update
[openttd/fttd.git] / src / hotkeys.cpp
blob134f8bfd75351c3c973e9e5c923fca95e35bb3a3
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.h"
17 #include "window_gui.h"
19 char *_hotkeys_file;
22 /** String representation of a keycode */
23 struct KeycodeName {
24 WindowKeyCodes keycode; ///< Keycode
25 uint namelen; ///< Length of keycode name
26 const char *name; ///< Name of keycode
29 /** Array of non-standard keys that can be used in the hotkeys config file. */
30 static const KeycodeName special_keys[] = {
31 #define DEFINE_HOTKEY(keycode,name) { keycode, sizeof name - 1, name }
32 DEFINE_HOTKEY (WKC_SHIFT, "SHIFT"),
33 DEFINE_HOTKEY (WKC_CTRL, "CTRL"),
34 DEFINE_HOTKEY (WKC_ALT, "ALT"),
35 DEFINE_HOTKEY (WKC_META, "META"),
36 DEFINE_HOTKEY (WKC_GLOBAL_HOTKEY, "GLOBAL"),
37 DEFINE_HOTKEY (WKC_ESC, "ESC"),
38 DEFINE_HOTKEY (WKC_DELETE, "DEL"),
39 DEFINE_HOTKEY (WKC_RETURN, "RETURN"),
40 DEFINE_HOTKEY (WKC_BACKQUOTE, "BACKQUOTE"),
41 DEFINE_HOTKEY (WKC_F1, "F1"),
42 DEFINE_HOTKEY (WKC_F2, "F2"),
43 DEFINE_HOTKEY (WKC_F3, "F3"),
44 DEFINE_HOTKEY (WKC_F4, "F4"),
45 DEFINE_HOTKEY (WKC_F5, "F5"),
46 DEFINE_HOTKEY (WKC_F6, "F6"),
47 DEFINE_HOTKEY (WKC_F7, "F7"),
48 DEFINE_HOTKEY (WKC_F8, "F8"),
49 DEFINE_HOTKEY (WKC_F9, "F9"),
50 DEFINE_HOTKEY (WKC_F10, "F10"),
51 DEFINE_HOTKEY (WKC_F11, "F11"),
52 DEFINE_HOTKEY (WKC_F12, "F12"),
53 DEFINE_HOTKEY (WKC_PAUSE, "PAUSE"),
54 DEFINE_HOTKEY (WKC_COMMA, "COMMA"),
55 DEFINE_HOTKEY (WKC_NUM_PLUS, "NUM_PLUS"),
56 DEFINE_HOTKEY (WKC_NUM_MINUS, "NUM_MINUS"),
57 DEFINE_HOTKEY (WKC_EQUALS, "="),
58 DEFINE_HOTKEY (WKC_MINUS, "-"),
59 #undef DEFINE_HOTKEY
62 static const KeycodeName *find_special_key_by_keycode (uint16 keycode)
64 for (uint i = 0; i < lengthof(special_keys); i++) {
65 if (special_keys[i].keycode == keycode) {
66 return &special_keys[i];
70 return NULL;
73 static const KeycodeName *find_special_key_by_name (const char *name, size_t len)
75 for (uint i = 0; i < lengthof(special_keys); i++) {
76 if (special_keys[i].namelen == len && strncasecmp (name, special_keys[i].name, len) == 0) {
77 return &special_keys[i];
81 return NULL;
85 /**
86 * Try to parse a single part of a keycode.
87 * @param start Start of the string to parse.
88 * @param end End of the string to parse.
89 * @return A keycode if a match is found or 0.
91 static uint16 ParseCode(const char *start, const char *end)
93 assert(start <= end);
94 while (start < end && *start == ' ') start++;
95 while (end > start && *end == ' ') end--;
96 size_t len = end - start;
98 const KeycodeName *key = find_special_key_by_name (start, len);
99 if (key != NULL) return key->keycode;
101 if (len == 1) {
102 if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A');
103 /* Ignore invalid keycodes */
104 if (*(const uint8 *)start < 128) return *start;
106 return 0;
110 * Parse a string representation of a keycode.
111 * @param start Start of the input.
112 * @param end End of the input.
113 * @return A valid keycode or 0.
115 static uint16 ParseKeycode(const char *start, const char *end)
117 assert(start <= end);
118 uint16 keycode = 0;
119 for (;;) {
120 const char *cur = start;
121 while (*cur != '+' && cur != end) cur++;
122 uint16 code = ParseCode(start, cur);
123 if (code == 0) return 0;
124 if (code & WKC_SPECIAL_KEYS) {
125 /* Some completely wrong keycode we don't support. */
126 if (code & ~WKC_SPECIAL_KEYS) return 0;
127 keycode |= code;
128 } else {
129 /* Ignore the code if it has more then 1 letter. */
130 if (keycode & ~WKC_SPECIAL_KEYS) return 0;
131 keycode |= code;
133 if (cur == end) break;
134 assert(cur < end);
135 start = cur + 1;
137 return keycode;
141 * Append the description of a keycode to a string.
142 * @param buf The buffer to append the description to.
143 * @param keycode The keycode whose description to append
145 static void AppendKeycodeDescription (stringb *buf, uint16 keycode)
147 if (keycode & WKC_GLOBAL_HOTKEY) buf->append ("GLOBAL+");
148 if (keycode & WKC_SHIFT) buf->append ("SHIFT+");
149 if (keycode & WKC_CTRL) buf->append ("CTRL+");
150 if (keycode & WKC_ALT) buf->append ("ALT+");
151 if (keycode & WKC_META) buf->append ("META+");
153 keycode &= ~WKC_SPECIAL_KEYS;
154 const KeycodeName *key = find_special_key_by_keycode (keycode);
155 if (key != NULL) {
156 buf->append (key->name);
157 } else {
158 assert (keycode < 128);
159 buf->append (keycode);
165 * List of all HotkeyLists.
166 * This is a pointer to ensure initialisation order with the various static HotkeyList instances.
168 static std::vector <HotkeyList *> *_hotkey_lists = NULL;
170 void HotkeyList::init (void)
172 if (_hotkey_lists == NULL) _hotkey_lists = new std::vector <HotkeyList *>;
173 _hotkey_lists->push_back (this);
176 HotkeyList::~HotkeyList()
178 std::vector<HotkeyList *>::iterator it = _hotkey_lists->begin();
179 for (;;) {
180 assert (it != _hotkey_lists->end());
181 if (*it == this) break;
182 it++;
184 _hotkey_lists->erase (it);
188 * Load HotkeyList from IniFile.
189 * @param ini IniFile to load from.
191 void HotkeyList::Load(IniFile *ini)
193 const IniGroup *group = ini->get_group (this->ini_group);
195 this->mappings.clear();
197 for (uint i = 0; i < this->ndescs; i++) {
198 const Hotkey *hotkey = &this->descs[i];
200 const IniItem *item = group->find (hotkey->name);
201 if (item == NULL) {
202 static const uint16 Hotkey::* const defaults [] = { &Hotkey::default0, &Hotkey::default1, &Hotkey::default2, &Hotkey::default3 };
203 for (uint i = 0; i < lengthof(defaults); i++) {
204 uint16 keycode = hotkey->*defaults[i];
205 if (keycode == 0) break;
206 this->push_mapping (keycode, hotkey->num);
208 } else if (item->value != NULL) {
209 const char *start = item->value;
210 while (*start != '\0') {
211 const char *end = start;
212 while (*end != '\0' && *end != ',') end++;
213 uint16 keycode = ParseKeycode (start, end);
214 if (keycode != 0) this->push_mapping (keycode, hotkey->num);
215 start = (*end == ',') ? end + 1: end;
222 * Save HotkeyList to IniFile.
223 * @param ini IniFile to save to.
225 void HotkeyList::Save(IniFile *ini) const
227 IniGroup *group = ini->get_group (this->ini_group);
229 for (uint i = 0; i < this->ndescs; i++) {
230 const Hotkey *hotkey = &this->descs[i];
232 sstring<128> buf;
233 std::vector<Mapping>::const_iterator it = this->mappings.begin();
234 for (; it != this->mappings.end(); it++) {
235 if (it->value == hotkey->num) {
236 if (!buf.empty()) buf.append (',');
237 AppendKeycodeDescription (&buf, it->keycode);
241 group->get_item(hotkey->name)->SetValue (buf.c_str());
246 * Check if a keycode is bound to something.
247 * @param keycode The keycode that was pressed
248 * @param global_only Limit the search to hotkeys defined as 'global'.
249 * @return The number of the matching hotkey or -1.
251 int HotkeyList::CheckMatch(uint16 keycode, bool global_only) const
253 std::vector<Mapping>::const_iterator it = this->mappings.begin();
254 for (; it != this->mappings.end(); it++) {
255 if ((it->keycode == (keycode | WKC_GLOBAL_HOTKEY)) || (!global_only && (it->keycode == keycode))) {
256 return it->value;
259 return -1;
263 /** Load the hotkeys from the config file */
264 void LoadHotkeysFromConfig()
266 IniFile ini (_hotkeys_file, BASE_DIR);
268 std::vector<HotkeyList *>::iterator it = _hotkey_lists->begin();
269 for (; it != _hotkey_lists->end(); it++) {
270 (*it)->Load (&ini);
274 /** Save the hotkeys to the config file */
275 void SaveHotkeysToConfig()
277 IniFile ini (_hotkeys_file, BASE_DIR);
279 std::vector<HotkeyList *>::const_iterator it = _hotkey_lists->begin();
280 for (; it != _hotkey_lists->end(); it++) {
281 (*it)->Save (&ini);
284 ini.SaveToDisk (_hotkeys_file);
287 void HandleGlobalHotkeys(WChar key, uint16 keycode)
289 std::vector<HotkeyList *>::const_iterator it = _hotkey_lists->begin();
290 for (; it != _hotkey_lists->end(); it++) {
291 const HotkeyList *list = *it;
292 if (list->global_hotkey_handler == NULL) continue;
294 int hotkey = list->CheckMatch (keycode, true);
295 if (hotkey >= 0 && (list->global_hotkey_handler(hotkey) == ES_HANDLED)) return;