1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 // Disable symbol overrides so that we can use system headers.
24 #define FORBIDDEN_SYMBOL_ALLOW_ALL
25 
26 #include "gui/message.h"
27 #include "common/translation.h"
28 
29 #include "backends/platform/ios7/ios7_osys_main.h"
30 
31 static const int kQueuedInputEventDelay = 50;
32 
pollEvent(Common::Event & event)33 bool OSystem_iOS7::pollEvent(Common::Event &event) {
34 	//printf("pollEvent()\n");
35 
36 	long curTime = getMillis();
37 
38 	if (_timerCallback && (curTime >= _timerCallbackNext)) {
39 		_timerCallback(_timerCallbackTimer);
40 		_timerCallbackNext = curTime + _timerCallbackTimer;
41 	}
42 
43 	if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) {
44 		event = _queuedInputEvent;
45 		_queuedInputEvent.type = Common::EVENT_INVALID;
46 		return true;
47 	}
48 
49 	InternalEvent internalEvent;
50 
51 	if (iOS7_fetchEvent(&internalEvent)) {
52 		switch (internalEvent.type) {
53 		case kInputMouseDown:
54 			if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2))
55 				return false;
56 			break;
57 
58 		case kInputMouseUp:
59 			if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2))
60 				return false;
61 			break;
62 
63 		case kInputMouseDragged:
64 			if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2))
65 				return false;
66 			break;
67 
68 		case kInputOrientationChanged:
69 			handleEvent_orientationChanged(internalEvent.value1);
70 			return false;
71 
72 		case kInputApplicationSuspended:
73 			handleEvent_applicationSuspended();
74 			return false;
75 
76 		case kInputApplicationResumed:
77 			handleEvent_applicationResumed();
78 			return false;
79 
80 		case kInputApplicationSaveState:
81 			handleEvent_applicationSaveState();
82 			return false;
83 
84 		case kInputApplicationRestoreState:
85 			handleEvent_applicationRestoreState();
86 			return false;
87 
88 		case kInputApplicationClearState:
89 			handleEvent_applicationClearState();
90 			return false;
91 
92 		case kInputMouseSecondDragged:
93 			if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2))
94 				return false;
95 			break;
96 		case kInputMouseSecondDown:
97 			_secondaryTapped = true;
98 			if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2))
99 				return false;
100 			break;
101 		case kInputMouseSecondUp:
102 			_secondaryTapped = false;
103 			if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2))
104 				return false;
105 			break;
106 
107 		case kInputKeyPressed:
108 			handleEvent_keyPressed(event, internalEvent.value1);
109 			break;
110 
111 		case kInputSwipe:
112 			if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2))
113 				return false;
114 			break;
115 
116 		case kInputTap:
117 			if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2))
118 				return false;
119 			break;
120 
121 		case kInputMainMenu:
122 			event.type = Common::EVENT_MAINMENU;
123 			_queuedInputEvent.type = Common::EVENT_INVALID;
124 			_queuedEventTime = getMillis() + kQueuedInputEventDelay;
125 			break;
126 
127 		default:
128 			break;
129 		}
130 
131 		return true;
132 	}
133 	return false;
134 }
135 
handleEvent_mouseDown(Common::Event & event,int x,int y)136 bool OSystem_iOS7::handleEvent_mouseDown(Common::Event &event, int x, int y) {
137 	//printf("Mouse down at (%u, %u)\n", x, y);
138 
139 	// Workaround: kInputMouseSecondToggled isn't always sent when the
140 	// secondary finger is lifted. Need to make sure we get out of that mode.
141 	_secondaryTapped = false;
142 
143 	if (_touchpadModeEnabled) {
144 		_lastPadX = x;
145 		_lastPadY = y;
146 	} else
147 		warpMouse(x, y);
148 
149 	if (_mouseClickAndDragEnabled) {
150 		event.type = Common::EVENT_LBUTTONDOWN;
151 		event.mouse.x = _videoContext->mouseX;
152 		event.mouse.y = _videoContext->mouseY;
153 		return true;
154 	} else {
155 		_lastMouseDown = getMillis();
156 	}
157 	return false;
158 }
159 
handleEvent_mouseUp(Common::Event & event,int x,int y)160 bool OSystem_iOS7::handleEvent_mouseUp(Common::Event &event, int x, int y) {
161 	//printf("Mouse up at (%u, %u)\n", x, y);
162 
163 	if (_secondaryTapped) {
164 		_secondaryTapped = false;
165 		if (!handleEvent_secondMouseUp(event, x, y))
166 			return false;
167 	} else if (_mouseClickAndDragEnabled) {
168 		event.type = Common::EVENT_LBUTTONUP;
169 		event.mouse.x = _videoContext->mouseX;
170 		event.mouse.y = _videoContext->mouseY;
171 	} else {
172 		if (getMillis() - _lastMouseDown < 250) {
173 			event.type = Common::EVENT_LBUTTONDOWN;
174 			event.mouse.x = _videoContext->mouseX;
175 			event.mouse.y = _videoContext->mouseY;
176 
177 			_queuedInputEvent.type = Common::EVENT_LBUTTONUP;
178 			_queuedInputEvent.mouse.x = _videoContext->mouseX;
179 			_queuedInputEvent.mouse.y = _videoContext->mouseY;
180 			_lastMouseTap = getMillis();
181 			_queuedEventTime = _lastMouseTap + kQueuedInputEventDelay;
182 		} else
183 			return false;
184 	}
185 
186 	return true;
187 }
188 
handleEvent_secondMouseDown(Common::Event & event,int x,int y)189 bool OSystem_iOS7::handleEvent_secondMouseDown(Common::Event &event, int x, int y) {
190 	_lastSecondaryDown = getMillis();
191 	_gestureStartX = x;
192 	_gestureStartY = y;
193 
194 	if (_mouseClickAndDragEnabled) {
195 		event.type = Common::EVENT_LBUTTONUP;
196 		event.mouse.x = _videoContext->mouseX;
197 		event.mouse.y = _videoContext->mouseY;
198 
199 		_queuedInputEvent.type = Common::EVENT_RBUTTONDOWN;
200 		_queuedInputEvent.mouse.x = _videoContext->mouseX;
201 		_queuedInputEvent.mouse.y = _videoContext->mouseY;
202 	} else
203 		return false;
204 
205 	return true;
206 }
207 
handleEvent_secondMouseUp(Common::Event & event,int x,int y)208 bool OSystem_iOS7::handleEvent_secondMouseUp(Common::Event &event, int x, int y) {
209 	int curTime = getMillis();
210 
211 	if (curTime - _lastSecondaryDown < 400) {
212 		//printf("Right tap!\n");
213 		if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) {
214 			//printf("Right escape!\n");
215 			event.type = Common::EVENT_KEYDOWN;
216 			_queuedInputEvent.type = Common::EVENT_KEYUP;
217 
218 			event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
219 			event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
220 			event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
221 			_queuedEventTime = curTime + kQueuedInputEventDelay;
222 			_lastSecondaryTap = 0;
223 		} else if (!_mouseClickAndDragEnabled) {
224 			//printf("Rightclick!\n");
225 			event.type = Common::EVENT_RBUTTONDOWN;
226 			event.mouse.x = _videoContext->mouseX;
227 			event.mouse.y = _videoContext->mouseY;
228 			_queuedInputEvent.type = Common::EVENT_RBUTTONUP;
229 			_queuedInputEvent.mouse.x = _videoContext->mouseX;
230 			_queuedInputEvent.mouse.y = _videoContext->mouseY;
231 			_lastSecondaryTap = curTime;
232 			_queuedEventTime = curTime + kQueuedInputEventDelay;
233 		} else {
234 			//printf("Right nothing!\n");
235 			return false;
236 		}
237 	}
238 	if (_mouseClickAndDragEnabled) {
239 		event.type = Common::EVENT_RBUTTONUP;
240 		event.mouse.x = _videoContext->mouseX;
241 		event.mouse.y = _videoContext->mouseY;
242 	}
243 
244 	return true;
245 }
246 
handleEvent_mouseDragged(Common::Event & event,int x,int y)247 bool OSystem_iOS7::handleEvent_mouseDragged(Common::Event &event, int x, int y) {
248 	if (_lastDragPosX == x && _lastDragPosY == y)
249 		return false;
250 
251 	_lastDragPosX = x;
252 	_lastDragPosY = y;
253 
254 	//printf("Mouse dragged at (%u, %u)\n", x, y);
255 	int mouseNewPosX;
256 	int mouseNewPosY;
257 	if (_touchpadModeEnabled) {
258 		int deltaX = _lastPadX - x;
259 		int deltaY = _lastPadY - y;
260 		_lastPadX = x;
261 		_lastPadY = y;
262 
263 		mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f);
264 		mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f);
265 
266 		int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth;
267 		int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight;
268 
269 		if (mouseNewPosX < 0)
270 			mouseNewPosX = 0;
271 		else if (mouseNewPosX > widthCap)
272 			mouseNewPosX = widthCap;
273 
274 		if (mouseNewPosY < 0)
275 			mouseNewPosY = 0;
276 		else if (mouseNewPosY > heightCap)
277 			mouseNewPosY = heightCap;
278 
279 	} else {
280 		mouseNewPosX = x;
281 		mouseNewPosY = y;
282 	}
283 
284 	event.type = Common::EVENT_MOUSEMOVE;
285 	event.mouse.x = mouseNewPosX;
286 	event.mouse.y = mouseNewPosY;
287 	warpMouse(mouseNewPosX, mouseNewPosY);
288 
289 	return true;
290 }
291 
handleEvent_mouseSecondDragged(Common::Event & event,int x,int y)292 bool OSystem_iOS7::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) {
293 	if (_gestureStartX == -1 || _gestureStartY == -1) {
294 		return false;
295 	}
296 
297 	static const int kNeededLength = 100;
298 	static const int kMaxDeviation = 20;
299 
300 	int vecX = (x - _gestureStartX);
301 	int vecY = (y - _gestureStartY);
302 
303 	int absX = abs(vecX);
304 	int absY = abs(vecY);
305 
306 	//printf("(%d, %d)\n", vecX, vecY);
307 
308 	if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon.
309 		_gestureStartX = -1;
310 		_gestureStartY = -1;
311 
312 		if (absX < kMaxDeviation && vecY >= kNeededLength) {
313 			// Swipe down
314 			event.type = Common::EVENT_MAINMENU;
315 			_queuedInputEvent.type = Common::EVENT_INVALID;
316 
317 			_queuedEventTime = getMillis() + kQueuedInputEventDelay;
318 			return true;
319 		}
320 
321 		if (absX < kMaxDeviation && -vecY >= kNeededLength) {
322 			// Swipe up
323 			_mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
324 			Common::U32String dialogMsg;
325 			if (_mouseClickAndDragEnabled) {
326 				_touchpadModeEnabled = false;
327 				dialogMsg = _("Mouse-click-and-drag mode enabled.");
328 			} else
329 				dialogMsg = _("Mouse-click-and-drag mode disabled.");
330 			GUI::TimedMessageDialog dialog(dialogMsg, 1500);
331 			dialog.runModal();
332 			return false;
333 		}
334 
335 		if (absY < kMaxDeviation && vecX >= kNeededLength) {
336 			// Swipe right
337 			_touchpadModeEnabled = !_touchpadModeEnabled;
338 			Common::U32String dialogMsg;
339 			if (_touchpadModeEnabled)
340 				dialogMsg = _("Touchpad mode enabled.");
341 			else
342 				dialogMsg = _("Touchpad mode disabled.");
343 			GUI::TimedMessageDialog dialog(dialogMsg, 1500);
344 			dialog.runModal();
345 			return false;
346 
347 		}
348 
349 		if (absY < kMaxDeviation && -vecX >= kNeededLength) {
350 			// Swipe left
351 			return false;
352 		}
353 	}
354 
355 	return false;
356 }
357 
handleEvent_orientationChanged(int orientation)358 void  OSystem_iOS7::handleEvent_orientationChanged(int orientation) {
359 	//printf("Orientation: %i\n", orientation);
360 
361 	ScreenOrientation newOrientation;
362 	switch (orientation) {
363 	case 1:
364 		newOrientation = kScreenOrientationPortrait;
365 		break;
366 	case 2:
367 		newOrientation = kScreenOrientationFlippedPortrait;
368 		break;
369 	case 3:
370 		newOrientation = kScreenOrientationLandscape;
371 		break;
372 	case 4:
373 		newOrientation = kScreenOrientationFlippedLandscape;
374 		break;
375 	default:
376 		return;
377 	}
378 
379 	if (_screenOrientation != newOrientation) {
380 		_screenOrientation = newOrientation;
381 		rebuildSurface();
382 	}
383 }
384 
rebuildSurface()385 void OSystem_iOS7::rebuildSurface() {
386 	updateOutputSurface();
387 
388 	dirtyFullScreen();
389 	if (_videoContext->overlayVisible) {
390 			dirtyFullOverlayScreen();
391 		}
392 	updateScreen();
393 }
394 
handleEvent_applicationSuspended()395 void OSystem_iOS7::handleEvent_applicationSuspended() {
396 	suspendLoop();
397 }
398 
handleEvent_applicationResumed()399 void OSystem_iOS7::handleEvent_applicationResumed() {
400 	rebuildSurface();
401 }
402 
handleEvent_keyPressed(Common::Event & event,int keyPressed)403 void  OSystem_iOS7::handleEvent_keyPressed(Common::Event &event, int keyPressed) {
404 	int ascii = keyPressed;
405 	//printf("key: %i\n", keyPressed);
406 
407 	// Map LF character to Return key/CR character
408 	if (keyPressed == 10) {
409 		keyPressed = Common::KEYCODE_RETURN;
410 		ascii = Common::ASCII_RETURN;
411 	}
412 
413 	event.type = Common::EVENT_KEYDOWN;
414 	_queuedInputEvent.type = Common::EVENT_KEYUP;
415 
416 	event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
417 	event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed;
418 	event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii;
419 	_queuedEventTime = getMillis() + kQueuedInputEventDelay;
420 }
421 
handleEvent_swipe(Common::Event & event,int direction,int touches)422 bool OSystem_iOS7::handleEvent_swipe(Common::Event &event, int direction, int touches) {
423 	if (touches == 3) {
424 		Common::KeyCode keycode = Common::KEYCODE_INVALID;
425 		switch ((UIViewSwipeDirection)direction) {
426 			case kUIViewSwipeUp:
427 				keycode = Common::KEYCODE_UP;
428 				break;
429 			case kUIViewSwipeDown:
430 				keycode = Common::KEYCODE_DOWN;
431 				break;
432 			case kUIViewSwipeLeft:
433 				keycode = Common::KEYCODE_LEFT;
434 				break;
435 			case kUIViewSwipeRight:
436 				keycode = Common::KEYCODE_RIGHT;
437 				break;
438 			default:
439 				return false;
440 		}
441 
442 		event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode;
443 		event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0;
444 		event.type = Common::EVENT_KEYDOWN;
445 		_queuedInputEvent.type = Common::EVENT_KEYUP;
446 		event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
447 		_queuedEventTime = getMillis() + kQueuedInputEventDelay;
448 
449 		return true;
450 	}
451 	else if (touches == 2) {
452 		switch ((UIViewSwipeDirection)direction) {
453 		case kUIViewSwipeUp: {
454 			_mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
455 			Common::U32String dialogMsg;
456 			if (_mouseClickAndDragEnabled) {
457 				_touchpadModeEnabled = false;
458 				dialogMsg = _("Mouse-click-and-drag mode enabled.");
459 			} else
460 				dialogMsg = _("Mouse-click-and-drag mode disabled.");
461 			GUI::TimedMessageDialog dialog(dialogMsg, 1500);
462 			dialog.runModal();
463 			return false;
464 		}
465 
466 		case kUIViewSwipeDown: {
467 			// Swipe down
468 			event.type = Common::EVENT_MAINMENU;
469 			_queuedInputEvent.type = Common::EVENT_INVALID;
470 			_queuedEventTime = getMillis() + kQueuedInputEventDelay;
471 			return true;
472 		}
473 
474 		case kUIViewSwipeRight: {
475 			// Swipe right
476 			_touchpadModeEnabled = !_touchpadModeEnabled;
477 			Common::U32String dialogMsg;
478 			if (_touchpadModeEnabled)
479 				dialogMsg = _("Touchpad mode enabled.");
480 			else
481 				dialogMsg = _("Touchpad mode disabled.");
482 			GUI::TimedMessageDialog dialog(dialogMsg, 1500);
483 			dialog.runModal();
484 			return false;
485 		}
486 
487 		default:
488 			break;
489 		}
490 	}
491 	return false;
492 }
493 
handleEvent_tap(Common::Event & event,UIViewTapDescription type,int touches)494 bool OSystem_iOS7::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) {
495 	if (touches == 1) {
496 		if (type == kUIViewTapDouble) {
497 			event.type = Common::EVENT_RBUTTONDOWN;
498 			_queuedInputEvent.type = Common::EVENT_RBUTTONUP;
499 			_queuedEventTime = getMillis() + kQueuedInputEventDelay;
500 			return true;
501 		}
502 	}
503 	else if (touches == 2) {
504 		if (type == kUIViewTapDouble) {
505 			event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
506 			event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
507 			event.type = Common::EVENT_KEYDOWN;
508 			_queuedInputEvent.type = Common::EVENT_KEYUP;
509 			event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
510 			_queuedEventTime = getMillis() + kQueuedInputEventDelay;
511 			return true;
512 		}
513 	}
514 	return false;
515 }
516