00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "hotkeys.h"
00015 #include "ini_type.h"
00016 #include "string_func.h"
00017 #include "window_gui.h"
00018
00019 char *_hotkeys_file;
00020
00025 static SmallVector<HotkeyList*, 16> *_hotkey_lists = NULL;
00026
00028 struct KeycodeNames {
00029 const char *name;
00030 WindowKeyCodes keycode;
00031 };
00032
00034 static const KeycodeNames _keycode_to_name[] = {
00035 {"SHIFT", WKC_SHIFT},
00036 {"CTRL", WKC_CTRL},
00037 {"ALT", WKC_ALT},
00038 {"META", WKC_META},
00039 {"GLOBAL", WKC_GLOBAL_HOTKEY},
00040 {"ESC", WKC_ESC},
00041 {"DEL", WKC_DELETE},
00042 {"RETURN", WKC_RETURN},
00043 {"BACKQUOTE", WKC_BACKQUOTE},
00044 {"F1", WKC_F1},
00045 {"F2", WKC_F2},
00046 {"F3", WKC_F3},
00047 {"F4", WKC_F4},
00048 {"F5", WKC_F5},
00049 {"F6", WKC_F6},
00050 {"F7", WKC_F7},
00051 {"F8", WKC_F8},
00052 {"F9", WKC_F9},
00053 {"F10", WKC_F10},
00054 {"F11", WKC_F11},
00055 {"F12", WKC_F12},
00056 {"PAUSE", WKC_PAUSE},
00057 {"COMMA", WKC_COMMA},
00058 {"NUM_PLUS", WKC_NUM_PLUS},
00059 {"NUM_MINUS", WKC_NUM_MINUS},
00060 {"=", WKC_EQUALS},
00061 {"-", WKC_MINUS},
00062 };
00063
00070 static uint16 ParseCode(const char *start, const char *end)
00071 {
00072 assert(start <= end);
00073 while (start < end && *start == ' ') start++;
00074 while (end > start && *end == ' ') end--;
00075 for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
00076 if (strlen(_keycode_to_name[i].name) == (size_t)(end - start) && strncasecmp(start, _keycode_to_name[i].name, end - start) == 0) {
00077 return _keycode_to_name[i].keycode;
00078 }
00079 }
00080 if (end - start == 1) {
00081 if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A');
00082
00083 if (*(const uint8 *)start < 128) return *start;
00084 }
00085 return 0;
00086 }
00087
00094 static uint16 ParseKeycode(const char *start, const char *end)
00095 {
00096 assert(start <= end);
00097 uint16 keycode = 0;
00098 for (;;) {
00099 const char *cur = start;
00100 while (*cur != '+' && cur != end) cur++;
00101 uint16 code = ParseCode(start, cur);
00102 if (code == 0) return 0;
00103 if (code & WKC_SPECIAL_KEYS) {
00104
00105 if (code & ~WKC_SPECIAL_KEYS) return 0;
00106 keycode |= code;
00107 } else {
00108
00109 if (keycode & ~WKC_SPECIAL_KEYS) return 0;
00110 keycode |= code;
00111 }
00112 if (cur == end) break;
00113 assert(cur < end);
00114 start = cur + 1;
00115 }
00116 return keycode;
00117 }
00118
00124 static void ParseHotkeys(Hotkey *hotkey, const char *value)
00125 {
00126 const char *start = value;
00127 while (*start != '\0') {
00128 const char *end = start;
00129 while (*end != '\0' && *end != ',') end++;
00130 uint16 keycode = ParseKeycode(start, end);
00131 if (keycode != 0) hotkey->AddKeycode(keycode);
00132 start = (*end == ',') ? end + 1: end;
00133 }
00134 }
00135
00145 static const char *KeycodeToString(uint16 keycode)
00146 {
00147 static char buf[32];
00148 buf[0] = '\0';
00149 bool first = true;
00150 if (keycode & WKC_GLOBAL_HOTKEY) {
00151 strecat(buf, "GLOBAL", lastof(buf));
00152 first = false;
00153 }
00154 if (keycode & WKC_SHIFT) {
00155 if (!first) strecat(buf, "+", lastof(buf));
00156 strecat(buf, "SHIFT", lastof(buf));
00157 first = false;
00158 }
00159 if (keycode & WKC_CTRL) {
00160 if (!first) strecat(buf, "+", lastof(buf));
00161 strecat(buf, "CTRL", lastof(buf));
00162 first = false;
00163 }
00164 if (keycode & WKC_ALT) {
00165 if (!first) strecat(buf, "+", lastof(buf));
00166 strecat(buf, "ALT", lastof(buf));
00167 first = false;
00168 }
00169 if (keycode & WKC_META) {
00170 if (!first) strecat(buf, "+", lastof(buf));
00171 strecat(buf, "META", lastof(buf));
00172 first = false;
00173 }
00174 if (!first) strecat(buf, "+", lastof(buf));
00175 keycode = keycode & ~WKC_SPECIAL_KEYS;
00176
00177 for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
00178 if (_keycode_to_name[i].keycode == keycode) {
00179 strecat(buf, _keycode_to_name[i].name, lastof(buf));
00180 return buf;
00181 }
00182 }
00183 assert(keycode < 128);
00184 char key[2];
00185 key[0] = keycode;
00186 key[1] = '\0';
00187 strecat(buf, key, lastof(buf));
00188 return buf;
00189 }
00190
00199 const char *SaveKeycodes(const Hotkey *hotkey)
00200 {
00201 static char buf[128];
00202 buf[0] = '\0';
00203 for (uint i = 0; i < hotkey->keycodes.Length(); i++) {
00204 const char *str = KeycodeToString(hotkey->keycodes[i]);
00205 if (i > 0) strecat(buf, ",", lastof(buf));
00206 strecat(buf, str, lastof(buf));
00207 }
00208 return buf;
00209 }
00210
00217 Hotkey::Hotkey(uint16 default_keycode, const char *name, int num) :
00218 name(name),
00219 num(num)
00220 {
00221 if (default_keycode != 0) this->AddKeycode(default_keycode);
00222 }
00223
00230 Hotkey::Hotkey(const uint16 *default_keycodes, const char *name, int num) :
00231 name(name),
00232 num(num)
00233 {
00234 const uint16 *keycode = default_keycodes;
00235 while (*keycode != 0) {
00236 this->AddKeycode(*keycode);
00237 keycode++;
00238 }
00239 }
00240
00246 void Hotkey::AddKeycode(uint16 keycode)
00247 {
00248 this->keycodes.Include(keycode);
00249 }
00250
00251 HotkeyList::HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler) :
00252 global_hotkey_handler(global_hotkey_handler), ini_group(ini_group), items(items)
00253 {
00254 if (_hotkey_lists == NULL) _hotkey_lists = new SmallVector<HotkeyList*, 16>();
00255 *_hotkey_lists->Append() = this;
00256 }
00257
00258 HotkeyList::~HotkeyList()
00259 {
00260 _hotkey_lists->Erase(_hotkey_lists->Find(this));
00261 }
00262
00267 void HotkeyList::Load(IniFile *ini)
00268 {
00269 IniGroup *group = ini->GetGroup(this->ini_group);
00270 for (Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) {
00271 IniItem *item = group->GetItem(hotkey->name, false);
00272 if (item != NULL) {
00273 hotkey->keycodes.Clear();
00274 if (item->value != NULL) ParseHotkeys(hotkey, item->value);
00275 }
00276 }
00277 }
00278
00283 void HotkeyList::Save(IniFile *ini) const
00284 {
00285 IniGroup *group = ini->GetGroup(this->ini_group);
00286 for (const Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) {
00287 IniItem *item = group->GetItem(hotkey->name, true);
00288 item->SetValue(SaveKeycodes(hotkey));
00289 }
00290 }
00291
00298 int HotkeyList::CheckMatch(uint16 keycode, bool global_only) const
00299 {
00300 for (const Hotkey *list = this->items; list->name != NULL; ++list) {
00301 if (list->keycodes.Contains(keycode | WKC_GLOBAL_HOTKEY) || (!global_only && list->keycodes.Contains(keycode))) {
00302 return list->num;
00303 }
00304 }
00305 return -1;
00306 }
00307
00308
00309 static void SaveLoadHotkeys(bool save)
00310 {
00311 IniFile *ini = new IniFile();
00312 ini->LoadFromDisk(_hotkeys_file, BASE_DIR);
00313
00314 for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) {
00315 if (save) {
00316 (*list)->Save(ini);
00317 } else {
00318 (*list)->Load(ini);
00319 }
00320 }
00321
00322 if (save) ini->SaveToDisk(_hotkeys_file);
00323 delete ini;
00324 }
00325
00326
00328 void LoadHotkeysFromConfig()
00329 {
00330 SaveLoadHotkeys(false);
00331 }
00332
00334 void SaveHotkeysToConfig()
00335 {
00336 SaveLoadHotkeys(true);
00337 }
00338
00339 void HandleGlobalHotkeys(WChar key, uint16 keycode)
00340 {
00341 for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) {
00342 if ((*list)->global_hotkey_handler == NULL) continue;
00343
00344 int hotkey = (*list)->CheckMatch(keycode, true);
00345 if (hotkey >= 0 && ((*list)->global_hotkey_handler(hotkey) == ES_HANDLED)) return;
00346 }
00347 }
00348