# hotkeys.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    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
    00022 struct KeycodeNames {
    00023   const char *name;
    00024   WindowKeyCodes keycode;
    00025 };
    00026
    00028 static const KeycodeNames _keycode_to_name[] = {
    00029   {"SHIFT", WKC_SHIFT},
    00030   {"CTRL", WKC_CTRL},
    00031   {"ALT", WKC_ALT},
    00032   {"META", WKC_META},
    00033   {"GLOBAL", WKC_GLOBAL_HOTKEY},
    00034   {"ESC", WKC_ESC},
    00035   {"DEL", WKC_DELETE},
    00036   {"RETURN", WKC_RETURN},
    00037   {"BACKQUOTE", WKC_BACKQUOTE},
    00038   {"F1", WKC_F1},
    00039   {"F2", WKC_F2},
    00040   {"F3", WKC_F3},
    00041   {"F4", WKC_F4},
    00042   {"F5", WKC_F5},
    00043   {"F6", WKC_F6},
    00044   {"F7", WKC_F7},
    00045   {"F8", WKC_F8},
    00046   {"F9", WKC_F9},
    00047   {"F10", WKC_F10},
    00048   {"F11", WKC_F11},
    00049   {"F12", WKC_F12},
    00050   {"PAUSE", WKC_PAUSE},
    00051   {"PLUS", (WindowKeyCodes)'+'},
    00052   {"COMMA", (WindowKeyCodes)','},
    00053   {"NUM_PLUS", WKC_NUM_PLUS},
    00054   {"NUM_MINUS", WKC_NUM_MINUS},
    00055   {"=", WKC_EQUALS},
    00056   {"-", WKC_MINUS},
    00057 };
    00058
    00065 static uint16 ParseCode(const char *start, const char *end)
    00066 {
    00067   assert(start <= end);
    00068   while (start < end && *start == ' ') start++;
    00069   while (end > start && *end == ' ') end--;
    00070   for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
    00071     if (strlen(_keycode_to_name[i].name) == (size_t)(end - start) && strncasecmp(start, _keycode_to_name[i].name, end - start) == 0) {
    00072       return _keycode_to_name[i].keycode;
    00073     }
    00074   }
    00075   if (end - start == 1) {
    00076     if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A');
    00077     /* Ignore invalid keycodes */
    00078     if (*(uint8*)start < 128) return *start;
    00079   }
    00080   return 0;
    00081 }
    00082
    00089 static uint16 ParseKeycode(const char *start, const char *end)
    00090 {
    00091   assert(start <= end);
    00092   uint16 keycode = 0;
    00093   while (true) {
    00094     const char *cur = start;
    00095     while (*cur != '+' && cur != end) cur++;
    00096     uint16 code = ParseCode(start, cur);
    00097     if (code == 0) return 0;
    00098     if (code & WKC_SPECIAL_KEYS) {
    00099       /* Some completely wrong keycode we don't support. */
    00100       if (code & ~WKC_SPECIAL_KEYS) return 0;
    00101       keycode |= code;
    00102     } else {
    00103       /* Ignore the code if it has more then 1 letter. */
    00104       if (keycode & ~WKC_SPECIAL_KEYS) return 0;
    00105       keycode |= code;
    00106     }
    00107     if (cur == end) break;
    00108     assert(cur < end);
    00109     start = cur + 1;
    00110   }
    00111   return keycode;
    00112 }
    00113
    00119 template<class T>
    00120 static void ParseHotkeys(Hotkey<T> *hotkey, const char *value)
    00121 {
    00122   const char *start = value;
    00123   while (*start != '\0') {
    00124     const char *end = start;
    00125     while (*end != '\0' && *end != ',') end++;
    00126     uint16 keycode = ParseKeycode(start, end);
    00127     if (keycode != 0) hotkey->AddKeycode(keycode);
    00128     start = (*end == ',') ? end + 1: end;
    00129   }
    00130 }
    00131
    00141 static const char *KeycodeToString(uint16 keycode)
    00142 {
    00143   static char buf[32];
    00144   buf[0] = '\0';
    00145   bool first = true;
    00146   if (keycode & WKC_GLOBAL_HOTKEY) {
    00147     strecat(buf, "GLOBAL", lastof(buf));
    00148     first = false;
    00149   }
    00150   if (keycode & WKC_SHIFT) {
    00151     if (!first) strecat(buf, "+", lastof(buf));
    00152     strecat(buf, "SHIFT", lastof(buf));
    00153     first = false;
    00154   }
    00155   if (keycode & WKC_CTRL) {
    00156     if (!first) strecat(buf, "+", lastof(buf));
    00157     strecat(buf, "CTRL", lastof(buf));
    00158     first = false;
    00159   }
    00160   if (keycode & WKC_ALT) {
    00161     if (!first) strecat(buf, "+", lastof(buf));
    00162     strecat(buf, "ALT", lastof(buf));
    00163     first = false;
    00164   }
    00165   if (keycode & WKC_META) {
    00166     if (!first) strecat(buf, "+", lastof(buf));
    00167     strecat(buf, "META", lastof(buf));
    00168     first = false;
    00169   }
    00170   if (!first) strecat(buf, "+", lastof(buf));
    00171   keycode = keycode & ~WKC_SPECIAL_KEYS;
    00172
    00173   for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
    00174     if (_keycode_to_name[i].keycode == keycode) {
    00175       strecat(buf, _keycode_to_name[i].name, lastof(buf));
    00176       return buf;
    00177     }
    00178   }
    00179   assert(keycode < 128);
    00180   char key[2];
    00181   key[0] = keycode;
    00182   key[1] = '\0';
    00183   strecat(buf, key, lastof(buf));
    00184   return buf;
    00185 }
    00186
    00195 template<class T>
    00196 const char *SaveKeycodes(const Hotkey<T> *hotkey)
    00197 {
    00198   static char buf[128];
    00199   buf[0] = '\0';
    00200   for (uint i = 0; i < hotkey->keycodes.Length(); i++) {
    00201     const char *str = KeycodeToString(hotkey->keycodes[i]);
    00202     if (i > 0) strecat(buf, ",", lastof(buf));
    00203     strecat(buf, str, lastof(buf));
    00204   }
    00205   return buf;
    00206 }
    00207
    00208 template<class T>
    00209 void LoadHotkeyGroup(IniGroup *group, T *hotkey_list)
    00210 {
    00211   for (uint i = 0; hotkey_list[i].num != -1; i++) {
    00212     T *hotkey = &hotkey_list[i];
    00213     IniItem *item = group->GetItem(hotkey->name, false);
    00214     if (item != NULL) {
    00215       hotkey->keycodes.Clear();
    00216       if (item->value != NULL) ParseHotkeys(hotkey, item->value);
    00217     }
    00218   }
    00219 }
    00220
    00221 template<class T>
    00222 void SaveHotkeyGroup(IniGroup *group, T *hotkey_list)
    00223 {
    00224   for (uint i = 0; hotkey_list[i].num != -1; i++) {
    00225     T *hotkey = &hotkey_list[i];
    00226     IniItem *item = group->GetItem(hotkey->name, true);
    00227     item->SetValue(SaveKeycodes(hotkey));
    00228   }
    00229 }
    00230
    00231 template<class T>
    00232 void SaveLoadHotkeyGroup(IniGroup *group, T *hotkey_list, bool save)
    00233 {
    00234   if (save) {
    00235     SaveHotkeyGroup(group, hotkey_list);
    00236   } else {
    00237     LoadHotkeyGroup(group, hotkey_list);
    00238   }
    00239 }
    00240
    00241 struct MainWindow;
    00242 struct MainToolbarWindow;
    00243 struct ScenarioEditorToolbarWindow;
    00244 struct TerraformToolbarWindow;
    00245 struct ScenarioEditorLandscapeGenerationWindow;
    00246 struct OrdersWindow;
    00247 struct BuildAirToolbarWindow;
    00248 struct BuildDocksToolbarWindow;
    00249 struct BuildRailToolbarWindow;
    00250 struct BuildRoadToolbarWindow;
    00251 struct SignListWindow;
    00252
    00253 static void SaveLoadHotkeys(bool save)
    00254 {
    00255   IniFile *ini = new IniFile();
    00256   ini->LoadFromDisk(_hotkeys_file);
    00257
    00258   IniGroup *group;
    00259
    00260 #define SL_HOTKEYS(name, window_name) \
    00261   extern Hotkey<window_name> *_##name##_hotkeys;\
    00262   group = ini->GetGroup(#name);\
    00263   SaveLoadHotkeyGroup(group, _##name##_hotkeys, save);
    00264
    00265   SL_HOTKEYS(global, MainWindow);
    00266   SL_HOTKEYS(maintoolbar, MainToolbarWindow);
    00267   SL_HOTKEYS(scenedit_maintoolbar, ScenarioEditorToolbarWindow);
    00268   SL_HOTKEYS(terraform, TerraformToolbarWindow);
    00269   SL_HOTKEYS(terraform_editor, ScenarioEditorLandscapeGenerationWindow);
    00270   SL_HOTKEYS(order, OrdersWindow);
    00271   SL_HOTKEYS(airtoolbar, BuildAirToolbarWindow);
    00272   SL_HOTKEYS(dockstoolbar, BuildDocksToolbarWindow);
    00273   SL_HOTKEYS(railtoolbar, BuildRailToolbarWindow);
    00274   SL_HOTKEYS(roadtoolbar, BuildRoadToolbarWindow);
    00275   SL_HOTKEYS(signlist, SignListWindow);
    00276
    00277
    00278 #undef SL_HOTKEYS
    00279   if (save) ini->SaveToDisk(_hotkeys_file);
    00280   delete ini;
    00281 }
    00282
    00283
    00285 void LoadHotkeysFromConfig()
    00286 {
    00287   SaveLoadHotkeys(false);
    00288 }
    00289
    00291 void SaveHotkeysToConfig()
    00292 {
    00293   SaveLoadHotkeys(true);
    00294 }
    00295
    00296 typedef EventState GlobalHotkeyHandler(uint16, uint16);
    00297
    00298 GlobalHotkeyHandler RailToolbarGlobalHotkeys;
    00299 GlobalHotkeyHandler DockToolbarGlobalHotkeys;
    00300 GlobalHotkeyHandler AirportToolbarGlobalHotkeys;
    00301 GlobalHotkeyHandler TerraformToolbarGlobalHotkeys;
    00302 GlobalHotkeyHandler TerraformToolbarEditorGlobalHotkeys;
    00303 GlobalHotkeyHandler RoadToolbarGlobalHotkeys;
    00304 GlobalHotkeyHandler RoadToolbarEditorGlobalHotkeys;
    00305 GlobalHotkeyHandler SignListGlobalHotkeys;
    00306
    00307
    00308 GlobalHotkeyHandler *_global_hotkey_handlers[] = {
    00309   RailToolbarGlobalHotkeys,
    00310   DockToolbarGlobalHotkeys,
    00311   AirportToolbarGlobalHotkeys,
    00312   TerraformToolbarGlobalHotkeys,
    00313   RoadToolbarGlobalHotkeys,
    00314   SignListGlobalHotkeys,
    00315 };
    00316
    00317 GlobalHotkeyHandler *_global_hotkey_handlers_editor[] = {
    00318   TerraformToolbarEditorGlobalHotkeys,
    00319   RoadToolbarEditorGlobalHotkeys,
    00320 };
    00321
    00322
    00323 void HandleGlobalHotkeys(uint16 key, uint16 keycode)
    00324 {
    00325   if (_game_mode == GM_NORMAL) {
    00326     for (uint i = 0; i < lengthof(_global_hotkey_handlers); i++) {
    00327       if (_global_hotkey_handlers[i](key, keycode) == ES_HANDLED) return;
    00328     }
    00329   } else if (_game_mode == GM_EDITOR) {
    00330     for (uint i = 0; i < lengthof(_global_hotkey_handlers_editor); i++) {
    00331       if (_global_hotkey_handlers_editor[i](key, keycode) == ES_HANDLED) return;
    00332     }
    00333   }
    00334 }
    00335