This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

source: ps/trunk/source/gui/ObjectTypes/CHotkeyPicker.cpp

Last change on this file was 27965, checked in by Vladislav Belov, 13 months ago

Revert non-ASCII characters from source and configuration files introduced in rP27786.

Fixes #6846

Differential Revision: https://code.wildfiregames.com/D5185

  • Property svn:eol-style set to native
File size: 5.7 KB
RevLine 
[25392]1/* Copyright (C) 2021 Wildfire Games.
[27965]2 * This file is part of 0 A.D.
[24215]3 *
[27965]4 * 0 A.D. is free software: you can redistribute it and/or modify
[24215]5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
[27965]9 * 0 A.D. is distributed in the hope that it will be useful,
[24215]10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
[27965]15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
[24215]16 */
17
18#include "precompiled.h"
19
20#include "CHotkeyPicker.h"
21
[24222]22#include "gui/ObjectBases/IGUIObject.h"
[24215]23#include "lib/timer.h"
[24222]24#include "ps/CLogger.h"
[24215]25#include "ps/Hotkey.h"
26#include "ps/KeyName.h"
27#include "scriptinterface/ScriptConversions.h"
28
[24222]29
[24215]30const CStr CHotkeyPicker::EventNameCombination = "Combination";
31const CStr CHotkeyPicker::EventNameKeyChange = "KeyChange";
32
33// Don't send the scancode, JS doesn't care.
[25428]34template<> void Script::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CHotkeyPicker::Key& val)
[24215]35{
[25428]36 Script::ToJSVal(rq, ret, val.scancodeName);
[24215]37}
38
39// Unused, but JSVAL_VECTOR requires it.
[25428]40template<> bool Script::FromJSVal(const ScriptRequest&, const JS::HandleValue, CHotkeyPicker::Key&)
[24215]41{
42 LOGWARNING("FromJSVal<CHotkeyPicker>: Not implemented");
43 return false;
44}
45
46JSVAL_VECTOR(CHotkeyPicker::Key);
47
[25392]48CHotkeyPicker::CHotkeyPicker(CGUI& pGUI) : IGUIObject(pGUI), m_TimeToCombination(this, "time_to_combination", 1.f)
[24215]49{
50 // 8 keys at the same time is probably more than we'll ever need.
51 m_KeysPressed.reserve(8);
52}
53
54CHotkeyPicker::~CHotkeyPicker()
55{
56}
57
58void CHotkeyPicker::FireEvent(const CStr& event)
59{
60 ScriptRequest rq(*m_pGUI.GetScriptInterface());
61
[24333]62 JS::RootedValueArray<1> args(rq.cx);
[24215]63 JS::RootedValue keys(rq.cx);
[25428]64 Script::ToJSVal(rq, &keys, m_KeysPressed);
[24215]65 args[0].set(keys);
66 ScriptEvent(event, args);
67}
68
69void CHotkeyPicker::Tick()
70{
71 if (m_KeysPressed.size() == 0)
72 return;
73
74 double time = timer_Time();
75 if (time - m_LastKeyChange < m_TimeToCombination)
76 return;
77
78 FireEvent(EventNameCombination);
79
80 return;
81}
82
83void CHotkeyPicker::HandleMessage(SGUIMessage& Message)
84{
85 IGUIObject::HandleMessage(Message);
86 switch (Message.type)
87 {
88 case GUIM_GOT_FOCUS:
89 case GUIM_LOST_FOCUS:
90 {
91 m_KeysPressed.clear();
92 m_LastKeyChange = timer_Time();
93 break;
94 }
95 default:
96 break;
97 }
98}
99
100InReaction CHotkeyPicker::PreemptEvent(const SDL_Event_* ev)
101{
102 switch (ev->ev.type)
103 {
104 // Handle the same mouse events that hotkeys handle
105 case SDL_MOUSEBUTTONDOWN:
106 case SDL_MOUSEBUTTONUP:
107 case SDL_MOUSEWHEEL:
108 {
109 SDL_Scancode scancode;
110
111 if (ev->ev.type != SDL_MOUSEWHEEL)
112 {
113 // Wait a little bit -> this gets triggered when clicking on a button,
114 // but after the button click is processed, thus immediately triggering...
115 if (timer_Time()-m_LastKeyChange < 0.2)
116 return IN_HANDLED;
117 // This is from hotkeyHandler - not sure what it does in all honesty.
118 if(ev->ev.button.button >= SDL_BUTTON_X1)
119 scancode = static_cast<SDL_Scancode>(MOUSE_BASE + (int)ev->ev.button.button + 2);
120 else
121 scancode = static_cast<SDL_Scancode>(MOUSE_BASE + (int)ev->ev.button.button);
122 }
123 else
124 {
125 if (ev->ev.wheel.y > 0)
126 scancode = static_cast<SDL_Scancode>(MOUSE_WHEELUP);
127 else if (ev->ev.wheel.y < 0)
128 scancode = static_cast<SDL_Scancode>(MOUSE_WHEELDOWN);
129 else if (ev->ev.wheel.x > 0)
130 scancode = static_cast<SDL_Scancode>(MOUSE_X2);
131 else if (ev->ev.wheel.x < 0)
132 scancode = static_cast<SDL_Scancode>(MOUSE_X1);
133 else
134 return IN_HANDLED;
135 }
136 // Don't handle keys and mouse together except for modifiers.
[24371]137 m_KeysPressed.erase(std::remove_if(m_KeysPressed.begin(), m_KeysPressed.end(), [](const Key& k) {
138 return static_cast<int>(k.code) < UNIFIED_SHIFT || static_cast<int>(k.code) >= UNIFIED_LAST; } ), m_KeysPressed.end());
[24215]139 m_KeysPressed.emplace_back(Key{scancode, FindScancodeName(scancode)});
140 // For mouse events, assume we immediately want to return.
141 FireEvent(EventNameCombination);
142
143 return IN_HANDLED;
144 }
145 case SDL_KEYDOWN:
146 case SDL_KEYUP:
147 {
148 SDL_Scancode scancode = ev->ev.key.keysym.scancode;
149
150 // Don't handle caps-lock, it doesn't really work in-game and it's a weird hotkey.
151 if (scancode == SDL_SCANCODE_CAPSLOCK)
152 return IN_PASS;
153
154 if (scancode == SDL_SCANCODE_LSHIFT || scancode == SDL_SCANCODE_RSHIFT)
155 scancode = static_cast<SDL_Scancode>(UNIFIED_SHIFT);
156 else if (scancode == SDL_SCANCODE_LCTRL || scancode == SDL_SCANCODE_RCTRL)
157 scancode = static_cast<SDL_Scancode>(UNIFIED_CTRL);
158 else if (scancode == SDL_SCANCODE_LALT || scancode == SDL_SCANCODE_RALT)
159 scancode = static_cast<SDL_Scancode>(UNIFIED_ALT);
160 else if (scancode == SDL_SCANCODE_LGUI || scancode == SDL_SCANCODE_RGUI)
161 scancode = static_cast<SDL_Scancode>(UNIFIED_SUPER);
162
163 if (ev->ev.type == SDL_KEYDOWN)
164 {
165 std::vector<Key>::const_iterator it = \
166 std::find_if(m_KeysPressed.begin(), m_KeysPressed.end(), [&scancode](Key& k) { return k.code == scancode; });
167 // Can happen if multiple keys are mapped the same.
168 if (it != m_KeysPressed.end())
169 return IN_HANDLED;
170 m_KeysPressed.emplace_back(Key{scancode, FindScancodeName(scancode)});
171 }
172 else
173 {
174 std::vector<Key>::const_iterator it = \
175 std::find_if(m_KeysPressed.begin(), m_KeysPressed.end(), [&scancode](Key& k) { return k.code == scancode; });
176 // Might happen if a key was down before this object is created.
177 if (it == m_KeysPressed.end())
178 return IN_HANDLED;
179 m_KeysPressed.erase(it);
180 }
181
182 FireEvent(EventNameKeyChange);
183
184 // Register after-JS in case this takes a while (probably not but it doesn't hurt).
185 m_LastKeyChange = timer_Time();
186 return IN_HANDLED;
187 }
188 default:
189 {
190 return IN_PASS;
191 }
192 }
193}
Note: See TracBrowser for help on using the repository browser.