SDL 2.0
SDL_uikitview.m
Go to the documentation of this file.
1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#if SDL_VIDEO_DRIVER_UIKIT
24
25#include "SDL_uikitview.h"
26
27#include "SDL_hints.h"
28#include "../../events/SDL_mouse_c.h"
29#include "../../events/SDL_touch_c.h"
30#include "../../events/SDL_events_c.h"
31
33#import "SDL_uikitmodes.h"
34#import "SDL_uikitwindow.h"
35
36/* This is defined in SDL_sysjoystick.m */
38
39@implementation SDL_uikitview {
40 SDL_Window *sdlwindow;
41
42 SDL_TouchID directTouchId;
43 SDL_TouchID indirectTouchId;
44}
45
46- (instancetype)initWithFrame:(CGRect)frame
47{
48 if ((self = [super initWithFrame:frame])) {
49#if TARGET_OS_TV
50 /* Apple TV Remote touchpad swipe gestures. */
51 UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
52 swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
53 [self addGestureRecognizer:swipeUp];
54
55 UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
56 swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
57 [self addGestureRecognizer:swipeDown];
58
59 UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
60 swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
61 [self addGestureRecognizer:swipeLeft];
62
63 UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
64 swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
65 [self addGestureRecognizer:swipeRight];
66#endif
67
68 self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
69 self.autoresizesSubviews = YES;
70
71 directTouchId = 1;
72 indirectTouchId = 2;
73
74#if !TARGET_OS_TV
75 self.multipleTouchEnabled = YES;
76 SDL_AddTouch(directTouchId, SDL_TOUCH_DEVICE_DIRECT, "");
77#endif
78 }
79
80 return self;
81}
82
83- (void)setSDLWindow:(SDL_Window *)window
84{
85 SDL_WindowData *data = nil;
86
87 if (window == sdlwindow) {
88 return;
89 }
90
91 /* Remove ourself from the old window. */
92 if (sdlwindow) {
93 SDL_uikitview *view = nil;
94 data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
95
96 [data.views removeObject:self];
97
98 [self removeFromSuperview];
99
100 /* Restore the next-oldest view in the old window. */
101 view = data.views.lastObject;
102
103 data.viewcontroller.view = view;
104
105 data.uiwindow.rootViewController = nil;
106 data.uiwindow.rootViewController = data.viewcontroller;
107
108 [data.uiwindow layoutIfNeeded];
109 }
110
111 /* Add ourself to the new window. */
112 if (window) {
113 data = (__bridge SDL_WindowData *) window->driverdata;
114
115 /* Make sure the SDL window has a strong reference to this view. */
116 [data.views addObject:self];
117
118 /* Replace the view controller's old view with this one. */
119 [data.viewcontroller.view removeFromSuperview];
120 data.viewcontroller.view = self;
121
122 /* The root view controller handles rotation and the status bar.
123 * Assigning it also adds the controller's view to the window. We
124 * explicitly re-set it to make sure the view is properly attached to
125 * the window. Just adding the sub-view if the root view controller is
126 * already correct causes orientation issues on iOS 7 and below. */
127 data.uiwindow.rootViewController = nil;
128 data.uiwindow.rootViewController = data.viewcontroller;
129
130 /* The view's bounds may not be correct until the next event cycle. That
131 * might happen after the current dimensions are queried, so we force a
132 * layout now to immediately update the bounds. */
133 [data.uiwindow layoutIfNeeded];
134 }
135
136 sdlwindow = window;
137}
138
139- (SDL_TouchDeviceType)touchTypeForTouch:(UITouch *)touch
140{
141#ifdef __IPHONE_9_0
142 if ([touch respondsToSelector:@selector((type))]) {
143 if (touch.type == UITouchTypeIndirect) {
145 }
146 }
147#endif
148
150}
151
152- (SDL_TouchID)touchIdForType:(SDL_TouchDeviceType)type
153{
154 switch (type) {
156 default:
157 return directTouchId;
159 return indirectTouchId;
160 }
161}
162
163- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
164{
165 CGPoint point = [touch locationInView:self];
166
167 if (normalize) {
168 CGRect bounds = self.bounds;
169 point.x /= bounds.size.width;
170 point.y /= bounds.size.height;
171 }
172
173 return point;
174}
175
176- (float)pressureForTouch:(UITouch *)touch
177{
178#ifdef __IPHONE_9_0
179 if ([touch respondsToSelector:@selector(force)]) {
180 return (float) touch.force;
181 }
182#endif
183
184 return 1.0f;
185}
186
187- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
188{
189 for (UITouch *touch in touches) {
190 SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch];
191 SDL_TouchID touchId = [self touchIdForType:touchType];
192 float pressure = [self pressureForTouch:touch];
193
194 if (SDL_AddTouch(touchId, touchType, "") < 0) {
195 continue;
196 }
197
198 /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */
199
200 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
201 SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
202 SDL_TRUE, locationInView.x, locationInView.y, pressure);
203 }
204}
205
206- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
207{
208 for (UITouch *touch in touches) {
209 SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch];
210 SDL_TouchID touchId = [self touchIdForType:touchType];
211 float pressure = [self pressureForTouch:touch];
212
213 if (SDL_AddTouch(touchId, touchType, "") < 0) {
214 continue;
215 }
216
217 /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */
218
219 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
220 SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
221 SDL_FALSE, locationInView.x, locationInView.y, pressure);
222 }
223}
224
225- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
226{
227 [self touchesEnded:touches withEvent:event];
228}
229
230- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
231{
232 for (UITouch *touch in touches) {
233 SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch];
234 SDL_TouchID touchId = [self touchIdForType:touchType];
235 float pressure = [self pressureForTouch:touch];
236
237 if (SDL_AddTouch(touchId, touchType, "") < 0) {
238 continue;
239 }
240
241 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
242 SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
243 locationInView.x, locationInView.y, pressure);
244 }
245}
246
247#if TARGET_OS_TV || defined(__IPHONE_9_1)
248- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype
249{
250 switch (presstype) {
251 case UIPressTypeUpArrow:
252 return SDL_SCANCODE_UP;
253 case UIPressTypeDownArrow:
254 return SDL_SCANCODE_DOWN;
255 case UIPressTypeLeftArrow:
256 return SDL_SCANCODE_LEFT;
257 case UIPressTypeRightArrow:
258 return SDL_SCANCODE_RIGHT;
259 case UIPressTypeSelect:
260 /* HIG says: "primary button behavior" */
261 return SDL_SCANCODE_RETURN;
262 case UIPressTypeMenu:
263 /* HIG says: "returns to previous screen" */
264 return SDL_SCANCODE_ESCAPE;
265 case UIPressTypePlayPause:
266 /* HIG says: "secondary button behavior" */
267 return SDL_SCANCODE_PAUSE;
268 default:
270 }
271}
272
273- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
274{
276 for (UIPress *press in presses) {
277 SDL_Scancode scancode = [self scancodeFromPressType:press.type];
279 }
280 }
281 [super pressesBegan:presses withEvent:event];
282}
283
284- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
285{
287 for (UIPress *press in presses) {
288 SDL_Scancode scancode = [self scancodeFromPressType:press.type];
290 }
291 }
292 [super pressesEnded:presses withEvent:event];
293}
294
295- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
296{
298 for (UIPress *press in presses) {
299 SDL_Scancode scancode = [self scancodeFromPressType:press.type];
301 }
302 }
303 [super pressesCancelled:presses withEvent:event];
304}
305
306- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
307{
308 /* This is only called when the force of a press changes. */
309 [super pressesChanged:presses withEvent:event];
310}
311#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */
312
313#if TARGET_OS_TV
314-(void)swipeGesture:(UISwipeGestureRecognizer *)gesture
315{
316 /* Swipe gestures don't trigger begin states. */
317 if (gesture.state == UIGestureRecognizerStateEnded) {
319 /* Send arrow key presses for now, as we don't have an external API
320 * which better maps to swipe gestures. */
321 switch (gesture.direction) {
322 case UISwipeGestureRecognizerDirectionUp:
325 break;
326 case UISwipeGestureRecognizerDirectionDown:
329 break;
330 case UISwipeGestureRecognizerDirectionLeft:
333 break;
334 case UISwipeGestureRecognizerDirectionRight:
337 break;
338 }
339 }
340 }
341}
342#endif /* TARGET_OS_TV */
343
344@end
345
346#endif /* SDL_VIDEO_DRIVER_UIKIT */
347
348/* vi: set ts=4 sw=4 expandtab: */
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLuint in
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:44
@ SDL_SCANCODE_ESCAPE
Definition: SDL_scancode.h:93
@ SDL_SCANCODE_PAUSE
Definition: SDL_scancode.h:168
@ SDL_SCANCODE_RETURN
Definition: SDL_scancode.h:92
@ SDL_SCANCODE_UNKNOWN
Definition: SDL_scancode.h:45
@ SDL_SCANCODE_DOWN
Definition: SDL_scancode.h:178
@ SDL_SCANCODE_RIGHT
Definition: SDL_scancode.h:176
@ SDL_SCANCODE_UP
Definition: SDL_scancode.h:179
@ SDL_SCANCODE_LEFT
Definition: SDL_scancode.h:177
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
int SDL_AppleTVRemoteOpenedAsJoystick
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:364
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
SDL_TouchDeviceType
Definition: SDL_touch.h:45
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
@ SDL_TOUCH_DEVICE_INDIRECT_RELATIVE
Definition: SDL_touch.h:49
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
The type used to identify a window.
Definition: SDL_sysvideo.h:74
int frame
Definition: teststreaming.c:60