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