1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
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
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 #include "GUI/EventMgr.h"
22 #include "Interface.h"
23 #include "Video.h"
24
25 #include "globals.h"
26
27 namespace GemRB {
28
29 unsigned long EventMgr::DCDelay = 250;
30 unsigned long EventMgr::DPDelay = 250;
31 bool EventMgr::TouchInputEnabled = false;
32
33 EventMgr::buttonbits EventMgr::mouseButtonFlags;
34 EventMgr::buttonbits EventMgr::modKeys;
35 Point EventMgr::mousePos;
36 std::map<uint64_t, TouchEvent::Finger> EventMgr::fingerStates;
37 EventMgr::buttonbits EventMgr::controllerButtonStates;
38
39 EventMgr::KeyMap EventMgr::HotKeys = KeyMap();
40 EventMgr::EventTaps EventMgr::Taps = EventTaps();
41
MouseEventFromTouch(const TouchEvent & te,bool down)42 MouseEvent MouseEventFromTouch(const TouchEvent& te, bool down)
43 {
44 MouseEvent me {};
45 me.x = te.x;
46 me.y = te.y;
47 me.deltaX = te.deltaX;
48 me.deltaY = te.deltaY;
49
50 me.buttonStates = (down) ? GEM_MB_ACTION : 0;
51 me.button = GEM_MB_ACTION;
52 me.repeats = 1;
53
54 return me;
55 }
56
MouseEventFromController(const ControllerEvent & ce,bool down)57 MouseEvent MouseEventFromController(const ControllerEvent& ce, bool down)
58 {
59 Point p = EventMgr::MousePos();
60
61 MouseEvent me {};
62 me.x = p.x;
63 me.y = p.y;
64
65 if (ce.axis % 2) {
66 me.deltaX = ce.axisDelta;
67 me.deltaY = 0;
68 } else {
69 me.deltaX = 0;
70 me.deltaY = ce.axisDelta;
71 }
72
73 EventButton btn = 0;
74 switch (ce.button) {
75 case CONTROLLER_BUTTON_A:
76 btn = GEM_MB_ACTION;
77 break;
78 case CONTROLLER_BUTTON_B:
79 btn = GEM_MB_MENU;
80 break;
81 case CONTROLLER_BUTTON_LEFTSTICK:
82 btn = GEM_MB_MIDDLE;
83 break;
84 }
85
86 me.buttonStates = (down) ? btn : 0;
87 me.button = btn;
88
89 return me;
90 }
91
KeyEventFromController(const ControllerEvent & ce)92 KeyboardEvent KeyEventFromController(const ControllerEvent& ce)
93 {
94 KeyboardEvent ke{};
95
96 // TODO: probably want more than the DPad
97 switch (ce.button) {
98 case CONTROLLER_BUTTON_DPAD_UP:
99 ke.keycode = GEM_UP;
100 break;
101 case CONTROLLER_BUTTON_DPAD_DOWN:
102 ke.keycode = GEM_DOWN;
103 break;
104 case CONTROLLER_BUTTON_DPAD_LEFT:
105 ke.keycode = GEM_LEFT;
106 break;
107 case CONTROLLER_BUTTON_DPAD_RIGHT:
108 ke.keycode = GEM_RIGHT;
109 break;
110 default:
111 ke.keycode = 0;
112 break;
113 }
114
115 return ke;
116 }
117
ModState(unsigned short mod)118 bool EventMgr::ModState(unsigned short mod)
119 {
120 return (modKeys & buttonbits(mod)).any();
121 }
122
MouseButtonState(EventButton btn)123 bool EventMgr::MouseButtonState(EventButton btn)
124 {
125 return (mouseButtonFlags & buttonbits(btn)).any();
126 }
127
MouseDown()128 bool EventMgr::MouseDown()
129 {
130 return mouseButtonFlags.any();
131 }
132
FingerDown()133 bool EventMgr::FingerDown()
134 {
135 return !fingerStates.empty();
136 }
137
ControllerButtonState(EventButton btn)138 bool EventMgr::ControllerButtonState(EventButton btn)
139 {
140 return (controllerButtonStates & buttonbits(btn)).any();
141 }
142
DispatchEvent(Event && e)143 void EventMgr::DispatchEvent(Event&& e)
144 {
145 if (TouchInputEnabled == false && e.EventMaskFromType(e.type) & Event::AllTouchMask) {
146 return;
147 }
148
149 Video* video = core->GetVideoDriver();
150
151 e.time = GetTicks();
152
153 if (e.type == Event::TextInput) {
154 if (e.text.text.length() == 0) {
155 return;
156 }
157 } else if (e.EventMaskFromType(e.type) & Event::AllKeyMask) {
158 // first check for hot key listeners
159 static unsigned long lastKeyDown = 0;
160 static unsigned char repeatCount = 0;
161 static KeyboardKey repeatKey = 0;
162
163 if (e.type == Event::KeyDown) {
164 if (e.keyboard.keycode == repeatKey && e.time <= lastKeyDown + DPDelay) {
165 repeatCount++;
166 } else {
167 repeatCount = 1;
168 }
169 repeatKey = e.keyboard.keycode;
170 lastKeyDown = GetTicks();
171 }
172
173 e.keyboard.repeats = repeatCount;
174
175 int flags = e.mod << 16;
176 flags |= e.keyboard.keycode;
177 modKeys = e.mod;
178
179 KeyMap::const_iterator hit = HotKeys.find(flags);
180 if (hit != HotKeys.end()) {
181 assert(hit->second.size() > 0);
182 KeyMap::value_type::second_type list = hit->second;
183 EventCallback cb = hit->second.front();
184 if (cb(e)) {
185 return;
186 }
187 }
188 } else if (e.EventMaskFromType(e.type) & Event::ControllerAxisMask) {
189 // only the left stick moves the cursor
190 if (e.controller.axis == AXIS_LEFT_X) {
191 mousePos.x += e.controller.axisDelta;
192 } else if (e.controller.axis == AXIS_LEFT_Y) {
193 mousePos.y += e.controller.axisDelta;
194 }
195 } else if (e.EventMaskFromType(e.type) & (Event::ControllerButtonUpMask | Event::ControllerButtonDownMask)) {
196 controllerButtonStates = e.controller.buttonStates;
197 } else if (e.isScreen) {
198 if (e.EventMaskFromType(e.type) & (Event::MouseUpMask | Event::MouseDownMask
199 | Event::TouchUpMask | Event::TouchDownMask)
200 ) {
201 // WARNING: these are shared between mouse and touch
202 // it is assumed we wont be using both simultaniously
203 static unsigned long lastMouseDown = 0;
204 static unsigned char repeatCount = 0;
205 static EventButton repeatButton = 0;
206 static Point repeatPos;
207
208 ScreenEvent& se = (e.type == Event::MouseDown) ? static_cast<ScreenEvent&>(e.mouse) : static_cast<ScreenEvent&>(e.touch);
209 EventButton btn = (e.type == Event::MouseDown) ? e.mouse.button : 0;
210
211 if (e.type == Event::MouseDown || e.type == Event::TouchDown) {
212 core->GetVideoDriver()->CaptureMouse(true);
213 if (video->InTextInput())
214 video->StopTextInput();
215
216 if (btn == repeatButton
217 && e.time <= lastMouseDown + DCDelay
218 && repeatPos.isWithinRadius(mouseClickRadius, se.Pos())
219 ) {
220 repeatCount++;
221 } else {
222 repeatCount = 1;
223 }
224 repeatPos = se.Pos();
225 repeatButton = btn;
226 lastMouseDown = GetTicks();
227 } else if (e.type == Event::MouseUp && e.mouse.buttonStates == 0) {
228 core->GetVideoDriver()->CaptureMouse(false);
229 }
230
231 se.repeats = repeatCount;
232 }
233
234 if (e.EventMaskFromType(e.type) & (Event::AllMouseMask)) {
235 // set/clear the appropriate buttons
236 mouseButtonFlags = e.mouse.buttonStates;
237 mousePos = e.mouse.Pos();
238 } else { // touch
239 TouchEvent& te = (e.type == Event::TouchGesture) ? static_cast<TouchEvent&>(e.gesture) : static_cast<TouchEvent&>(e.touch);
240 uint64_t id = te.fingers[0].id;
241
242 switch (e.type) {
243 case Event::TouchDown:
244 fingerStates[id] = te.fingers[0];
245 break;
246
247 case Event::TouchUp:
248 fingerStates.erase(id);
249 break;
250
251 case Event::TouchGesture:
252 fingerStates.clear();
253 for (int i = 0; i < te.numFingers; ++i) {
254 id = te.fingers[i].id;
255 fingerStates[id] = te.fingers[i];
256 }
257 break;
258
259 default:
260 break;
261 }
262
263 if (te.numFingers == 1) {
264 mousePos = e.touch.Pos();
265 }
266 }
267 } else {
268 if (video->InTextInput())
269 video->StopTextInput();
270 }
271
272 // no hot keys or their listeners refused the event...
273 EventTaps tapsCopy = Taps; // copy this because its possible things get unregistered as a result of the event
274 EventTaps::iterator it = tapsCopy.begin();
275 for (; it != tapsCopy.end(); ++it) {
276 const std::pair<Event::EventTypeMask, EventCallback>& pair = it->second;
277 if (pair.first & e.EventMaskFromType(e.type)) {
278 // all matching taps get a copy of the event
279 pair.second(e);
280 }
281 }
282 }
283
RegisterHotKeyCallback(EventCallback cb,KeyboardKey key,short mod)284 bool EventMgr::RegisterHotKeyCallback(EventCallback cb, KeyboardKey key, short mod)
285 {
286 if (key < ' ') { // allowing certain non printables (eg 'F' keys)
287 return false;
288 }
289
290 int flags = mod << 16;
291 flags |= key;
292
293 KeyMap::iterator it = HotKeys.find(flags);
294 if (it != HotKeys.end()) {
295 it->second.push_front(cb);
296 } else {
297 HotKeys.insert(std::make_pair(flags, std::list<EventCallback>(1, cb)));
298 }
299
300 return true;
301 }
302
UnRegisterHotKeyCallback(EventCallback cb,KeyboardKey key,short mod)303 void EventMgr::UnRegisterHotKeyCallback(EventCallback cb, KeyboardKey key, short mod)
304 {
305 int flags = mod << 16;
306 flags |= key;
307
308 KeyMap::iterator it = HotKeys.find(flags);
309 if (it != HotKeys.end()) {
310 KeyMap::value_type::second_type::iterator cbit;
311 cbit = std::find_if(it->second.begin(), it->second.end(), [&cb](const decltype(cb)& item) {
312 return FunctionTargetsEqual(cb, item);
313 });
314 if (cbit != it->second.end()) {
315 it->second.erase(cbit);
316 if (it->second.empty()) {
317 HotKeys.erase(it);
318 }
319 }
320 }
321 }
322
RegisterEventMonitor(EventCallback cb,Event::EventTypeMask mask)323 EventMgr::TapMonitorId EventMgr::RegisterEventMonitor(EventCallback cb, Event::EventTypeMask mask)
324 {
325 static size_t id = 0;
326 Taps[id] = std::make_pair(mask, cb);
327 // return the "id" of the inserted tap so it could be unregistered later on
328 return id++;
329 }
330
UnRegisterEventMonitor(TapMonitorId monitor)331 void EventMgr::UnRegisterEventMonitor(TapMonitorId monitor)
332 {
333 Taps.erase(monitor);
334 }
335
CreateMouseBtnEvent(const Point & pos,EventButton btn,bool down,int mod)336 Event EventMgr::CreateMouseBtnEvent(const Point& pos, EventButton btn, bool down, int mod)
337 {
338 assert(btn);
339
340 Event e = CreateMouseMotionEvent(pos, mod);
341
342 if (down) {
343 e.type = Event::MouseDown;
344 e.mouse.buttonStates |= btn;
345 } else {
346 e.type = Event::MouseUp;
347 e.mouse.buttonStates &= ~btn;
348 }
349 e.mouse.button = btn;
350
351 return e;
352 }
353
CreateMouseMotionEvent(const Point & pos,int mod)354 Event EventMgr::CreateMouseMotionEvent(const Point& pos, int mod)
355 {
356 Event e = {}; // initialize all members to 0
357 e.mod = mod;
358 e.type = Event::MouseMove;
359 e.mouse.buttonStates = mouseButtonFlags.to_ulong();
360
361 e.mouse.x = pos.x;
362 e.mouse.y = pos.y;
363
364 Point delta = MousePos() - pos;
365 e.mouse.deltaX = delta.x;
366 e.mouse.deltaY = delta.y;
367
368 e.isScreen = true;
369
370 return e;
371 }
372
CreateMouseWheelEvent(const Point & vec,int mod)373 Event EventMgr::CreateMouseWheelEvent(const Point& vec, int mod)
374 {
375 Event e = CreateMouseMotionEvent(MousePos(), mod);
376 e.type = Event::MouseScroll;
377 e.mouse.deltaX = vec.x;
378 e.mouse.deltaY = vec.y;
379 return e;
380 }
381
CreateKeyEvent(KeyboardKey key,bool down,int mod)382 Event EventMgr::CreateKeyEvent(KeyboardKey key, bool down, int mod)
383 {
384 Event e = {}; // initialize all members to 0
385 e.mod = mod;
386 e.type = (down) ? Event::KeyDown : Event::KeyUp;
387 e.keyboard.keycode = key;
388 e.isScreen = false;
389
390 KeyboardKey character = 0;
391 if (key >= ' ' && key < GEM_LEFT) { // if printable
392 // FIXME: need to translate the keycode for e.keyboard.character
393 // probably need to lookup what encoding we are currently using
394 character = key;
395 if (mod & GEM_MOD_SHIFT) {
396 character = toupper(character);
397 }
398 }
399 e.keyboard.character = character;
400 return e;
401 }
402
CreateTouchEvent(const TouchEvent::Finger fingers[],int numFingers,bool down,float pressure)403 Event EventMgr::CreateTouchEvent(const TouchEvent::Finger fingers[], int numFingers, bool down, float pressure)
404 {
405 if (numFingers > FINGER_MAX) {
406 Log(ERROR, "EventManager", "cannot create a touch event with %d fingers; max is %d.", numFingers, FINGER_MAX);
407 return Event();
408 }
409
410 Event e = {};
411 e.isScreen = true;
412 e.mod = 0;
413 e.type = (down) ? Event::TouchDown : Event::TouchUp;
414
415 if (numFingers) {
416 for (int i = 0; i < numFingers; ++i) {
417 e.touch.x += fingers[i].x;
418 e.touch.y += fingers[i].y;
419 if (abs(fingers[i].deltaX) > abs(e.touch.deltaX)) {
420 e.touch.deltaX = fingers[i].deltaX;
421 }
422 if (abs(fingers[i].deltaY) > abs(e.touch.deltaY)) {
423 e.touch.deltaY = fingers[i].deltaY;
424 }
425 e.touch.fingers[i] = fingers[i];
426 }
427
428 e.touch.x /= numFingers;
429 e.touch.y /= numFingers;
430 }
431
432 e.touch.numFingers = numFingers;
433 e.touch.pressure = pressure;
434
435 return e;
436 }
437
CreateTouchGesture(const TouchEvent & touch,float rotation,float pinch)438 Event EventMgr::CreateTouchGesture(const TouchEvent& touch, float rotation, float pinch)
439 {
440 Event e = {};
441 e.isScreen = true;
442 e.mod = 0;
443 e.type = Event::TouchGesture;
444 e.touch = touch;
445 e.gesture.dTheta = rotation;
446 e.gesture.dDist = pinch;
447
448 return e;
449 }
450
CreateTextEvent(const char * text)451 Event EventMgr::CreateTextEvent(const char* text)
452 {
453 Event e = {};
454 char *str = ConvertCharEncoding(text, "UTF-8", core->TLKEncoding.encoding.c_str());
455 String* string = StringFromCString(str);
456
457 if (string) {
458 e = EventMgr::CreateTextEvent(*string);
459 }
460 delete string;
461 free(str);
462
463 return e;
464 }
465
CreateTextEvent(const String & text)466 Event EventMgr::CreateTextEvent(const String& text)
467 {
468 Event e = {};
469 e.type = Event::TextInput;
470 e.text.text = text;
471
472 return e;
473 }
474
CreateControllerAxisEvent(InputAxis axis,int delta,float pct)475 Event EventMgr::CreateControllerAxisEvent(InputAxis axis, int delta, float pct)
476 {
477 Event e = {};
478 e.type = Event::ControllerAxis;
479 e.controller.axis = axis;
480 e.controller.axisPct = pct;
481 e.controller.axisDelta = delta;
482 e.isScreen = true;
483 return e;
484 }
485
CreateControllerButtonEvent(EventButton btn,bool down)486 Event EventMgr::CreateControllerButtonEvent(EventButton btn, bool down)
487 {
488 Event e = {};
489 e.controller.buttonStates = controllerButtonStates.to_ulong();
490
491 if (down) {
492 e.type = Event::ControllerButtonDown;
493 e.controller.buttonStates |= btn;
494 } else {
495 e.type = Event::ControllerButtonUp;
496 e.controller.buttonStates &= ~btn;
497 }
498 e.controller.button = btn;
499
500 return e;
501 }
502
503 }
504