Index: binaries/data/mods/public/gui/common/tab_buttons.xml =================================================================== --- binaries/data/mods/public/gui/common/tab_buttons.xml +++ binaries/data/mods/public/gui/common/tab_buttons.xml @@ -1,11 +1,11 @@ - selectNextTab(1); + selectNextTab(1); - selectNextTab(-1); + selectNextTab(-1); Index: binaries/data/mods/public/gui/session/hotkeys/misc.xml =================================================================== --- binaries/data/mods/public/gui/session/hotkeys/misc.xml +++ binaries/data/mods/public/gui/session/hotkeys/misc.xml @@ -76,11 +76,11 @@ - unloadAll(); + unloadAll(); - stopUnits(g_Selection.toList()); + stopUnits(g_Selection.toList()); @@ -106,11 +106,11 @@ - findIdleUnit(g_MilitaryTypes); + findIdleUnit(g_MilitaryTypes); - findIdleUnit(["!Domestic"]); + findIdleUnit(["!Domestic"]); Index: binaries/data/mods/public/gui/session/hotkeys/training.xml =================================================================== --- binaries/data/mods/public/gui/session/hotkeys/training.xml +++ binaries/data/mods/public/gui/session/hotkeys/training.xml @@ -2,36 +2,36 @@ - addTrainingByPosition(0); + addTrainingByPosition(0); - addTrainingByPosition(1); + addTrainingByPosition(1); - addTrainingByPosition(2); + addTrainingByPosition(2); - addTrainingByPosition(3); + addTrainingByPosition(3); - addTrainingByPosition(4); + addTrainingByPosition(4); - addTrainingByPosition(5); + addTrainingByPosition(5); - addTrainingByPosition(6); + addTrainingByPosition(6); Index: binaries/data/mods/public/gui/session/minimap_panel.xml =================================================================== --- binaries/data/mods/public/gui/session/minimap_panel.xml +++ binaries/data/mods/public/gui/session/minimap_panel.xml @@ -27,7 +27,7 @@ sprite_over="stretched:session/minimap-idle-highlight.png" sprite_disabled="stretched:session/minimap-idle-disabled.png" > - findIdleUnit(g_WorkerTypes); + findIdleUnit(g_WorkerTypes); Index: binaries/data/mods/public/gui/summary/summary.xml =================================================================== --- binaries/data/mods/public/gui/summary/summary.xml +++ binaries/data/mods/public/gui/summary/summary.xml @@ -17,11 +17,11 @@ - selectNextTab(1); + selectNextTab(1); - selectNextTab(-1); + selectNextTab(-1); Index: source/gui/CGUI.cpp =================================================================== --- source/gui/CGUI.cpp +++ source/gui/CGUI.cpp @@ -68,7 +68,7 @@ { InReaction ret = IN_PASS; - if (ev->ev.type == SDL_HOTKEYDOWN || ev->ev.type == SDL_HOTKEYUP) + if (ev->ev.type == SDL_HOTKEYDOWN || ev->ev.type == SDL_HOTKEYPRESS || ev->ev.type == SDL_HOTKEYUP) { const char* hotkey = static_cast(ev->ev.user.data1); @@ -81,8 +81,12 @@ HotkeyInputHandler(ev); ret = IN_HANDLED; - if (ev->ev.type == SDL_HOTKEYDOWN) + // On keydown send 1 or 2 messages depending on repeat flag. This does not work on linux + // for special keys (shift, alt, ctrl), since the linux keyboard event manager sends the KEYDOWN only once. + if (ev->ev.type == SDL_HOTKEYPRESS) obj->SendEvent(GUIM_PRESSED, "press"); + else if (ev->ev.type == SDL_HOTKEYDOWN) + obj->SendEvent(GUIM_PRESSED, "keydown"); else obj->SendEvent(GUIM_RELEASED, "release"); } Index: source/gui/scripting/GuiScriptConversions.cpp =================================================================== --- source/gui/scripting/GuiScriptConversions.cpp +++ source/gui/scripting/GuiScriptConversions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -105,6 +105,7 @@ SET(obj, "clicks", (int)val.ev.button.clicks); break; } + case SDL_HOTKEYPRESS: case SDL_HOTKEYDOWN: case SDL_HOTKEYUP: { Index: source/main.cpp =================================================================== --- source/main.cpp +++ source/main.cpp @@ -130,7 +130,7 @@ kill_mainloop(); break; - case SDL_HOTKEYDOWN: + case SDL_HOTKEYPRESS: std::string hotkey = static_cast(ev->ev.user.data1); if (hotkey == "exit") { Index: source/ps/CConsole.cpp =================================================================== --- source/ps/CConsole.cpp +++ source/ps/CConsole.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -634,7 +634,7 @@ InReaction conInputHandler(const SDL_Event_* ev) { - if ((int)ev->ev.type == SDL_HOTKEYDOWN) + if ((int)ev->ev.type == SDL_HOTKEYPRESS) { std::string hotkey = static_cast(ev->ev.user.data1); Index: source/ps/Hotkey.h =================================================================== --- source/ps/Hotkey.h +++ source/ps/Hotkey.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,9 +25,9 @@ * Hotkeys consist of a name (an arbitrary string), and a key mapping. * The names and mappings are loaded from the config system (any * config setting with the name prefix "hotkey."). - * When a hotkey is pressed or released, SDL_HOTKEYDOWN and SDL_HOTKEYUP - * events are triggered, with the hotkey name stored in ev.user.data1 - * as a const char*. + * When a hotkey is pressed one SDL_HOTKEYPRESS and repeated SDL_HOTKEYDOWN events + * are triggered. When a hotkey is released an SDL_HOTKEYUP event is triggered. All + * with the hotkey name stored in ev.user.data1 as a const char*. */ #include "CStr.h" @@ -38,8 +38,9 @@ // required for our HOTKEY event type definition. this is OK since // hotkey.h is not included from any headers. -const int SDL_HOTKEYDOWN = SDL_USEREVENT; -const int SDL_HOTKEYUP = SDL_USEREVENT + 1; +const int SDL_HOTKEYPRESS = SDL_USEREVENT; +const int SDL_HOTKEYDOWN = SDL_USEREVENT + 1; +const int SDL_HOTKEYUP = SDL_USEREVENT + 2; extern void LoadHotkeys(); extern void UnloadHotkeys(); Index: source/ps/Hotkey.cpp =================================================================== --- source/ps/Hotkey.cpp +++ source/ps/Hotkey.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -196,6 +196,7 @@ } return IN_PASS; + case SDL_HOTKEYPRESS: case SDL_HOTKEYDOWN: g_HotkeyStatus[static_cast(ev->ev.user.data1)] = true; return IN_PASS; @@ -214,6 +215,9 @@ SDL_Event_ phantom; phantom.ev.type = ((ev->ev.type == SDL_KEYDOWN) || (ev->ev.type == SDL_MOUSEBUTTONDOWN)) ? SDL_KEYDOWN : SDL_KEYUP; + if (phantom.ev.type == SDL_KEYDOWN) + phantom.ev.key.repeat = ev->ev.type == SDL_KEYDOWN ? ev->ev.key.repeat : 0; + if ((keycode == SDLK_LSHIFT) || (keycode == SDLK_RSHIFT)) { phantom.ev.key.keysym.sym = (SDL_Keycode)UNIFIED_SHIFT; @@ -257,7 +261,7 @@ // To avoid this, set the modifier keys for /all/ events this key would trigger // (Ctrl, for example, is both group-save and bookmark-save) - // but only send a HotkeyDown event for the event with bindings most precisely + // but only send a HoteyPress/HotkeyDown event for the event with bindings most precisely // matching the conditions (i.e. the event with the highest number of auxiliary // keys, providing they're all down) @@ -304,10 +308,18 @@ for (size_t i = 0; i < closestMapNames.size(); ++i) { - SDL_Event_ hotkeyNotification; - hotkeyNotification.ev.type = SDL_HOTKEYDOWN; - hotkeyNotification.ev.user.data1 = const_cast(closestMapNames[i]); - in_push_priority_event(&hotkeyNotification); + if (ev->ev.type == SDL_KEYDOWN && ev->ev.key.repeat == 0) + { + SDL_Event_ hotkeyPressNotification; + hotkeyPressNotification.ev.type = SDL_HOTKEYPRESS; + hotkeyPressNotification.ev.user.data1 = const_cast(closestMapNames[i]); + in_push_priority_event(&hotkeyPressNotification); + } + + SDL_Event_ hotkeyDownNotification; + hotkeyDownNotification.ev.type = SDL_HOTKEYDOWN; + hotkeyDownNotification.ev.user.data1 = const_cast(closestMapNames[i]); + in_push_priority_event(&hotkeyDownNotification); } // -- KEYUP SECTION -- Index: source/ps/ProfileViewer.cpp =================================================================== --- source/ps/ProfileViewer.cpp +++ source/ps/ProfileViewer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -335,7 +335,7 @@ } break; } - case SDL_HOTKEYDOWN: + case SDL_HOTKEYPRESS: std::string hotkey = static_cast(ev->ev.user.data1); if( hotkey == "profile.toggle" )