SDL  2.0
SDL_uikitview.m
Go to the documentation of this file.
1  /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 "../../events/SDL_mouse_c.h"
28 #include "../../events/SDL_touch_c.h"
29 #include "../../events/SDL_events_c.h"
30 
31 #import "SDL_uikitappdelegate.h"
32 #import "SDL_uikitmodes.h"
33 #import "SDL_uikitwindow.h"
34 
35 @implementation SDL_uikitview {
36  SDL_Window *sdlwindow;
37 
38  SDL_TouchID touchId;
39  UITouch * __weak firstFingerDown;
40 }
41 
42 - (instancetype)initWithFrame:(CGRect)frame
43 {
44  if ((self = [super initWithFrame:frame])) {
45  self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
46  self.autoresizesSubviews = YES;
47 
48 #if !TARGET_OS_TV
49  self.multipleTouchEnabled = YES;
50 #endif
51 
52  touchId = 1;
53  SDL_AddTouch(touchId, "");
54  }
55 
56  return self;
57 }
58 
59 - (void)setSDLWindow:(SDL_Window *)window
60 {
61  SDL_WindowData *data = nil;
62 
63  if (window == sdlwindow) {
64  return;
65  }
66 
67  /* Remove ourself from the old window. */
68  if (sdlwindow) {
69  SDL_uikitview *view = nil;
70  data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
71 
72  [data.views removeObject:self];
73 
74  [self removeFromSuperview];
75 
76  /* Restore the next-oldest view in the old window. */
77  view = data.views.lastObject;
78 
79  data.viewcontroller.view = view;
80 
81  data.uiwindow.rootViewController = nil;
82  data.uiwindow.rootViewController = data.viewcontroller;
83 
84  [data.uiwindow layoutIfNeeded];
85  }
86 
87  /* Add ourself to the new window. */
88  if (window) {
89  data = (__bridge SDL_WindowData *) window->driverdata;
90 
91  /* Make sure the SDL window has a strong reference to this view. */
92  [data.views addObject:self];
93 
94  /* Replace the view controller's old view with this one. */
95  [data.viewcontroller.view removeFromSuperview];
96  data.viewcontroller.view = self;
97 
98  /* The root view controller handles rotation and the status bar.
99  * Assigning it also adds the controller's view to the window. We
100  * explicitly re-set it to make sure the view is properly attached to
101  * the window. Just adding the sub-view if the root view controller is
102  * already correct causes orientation issues on iOS 7 and below. */
103  data.uiwindow.rootViewController = nil;
104  data.uiwindow.rootViewController = data.viewcontroller;
105 
106  /* The view's bounds may not be correct until the next event cycle. That
107  * might happen after the current dimensions are queried, so we force a
108  * layout now to immediately update the bounds. */
109  [data.uiwindow layoutIfNeeded];
110  }
111 
112  sdlwindow = window;
113 }
114 
115 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
116 {
117  CGPoint point = [touch locationInView:self];
118 
119  if (normalize) {
120  CGRect bounds = self.bounds;
121  point.x /= bounds.size.width;
122  point.y /= bounds.size.height;
123  }
124 
125  return point;
126 }
127 
128 - (float)pressureForTouch:(UITouch *)touch
129 {
130 #ifdef __IPHONE_9_0
131  if ([touch respondsToSelector:@selector(force)]) {
132  return (float) touch.force;
133  }
134 #endif
135 
136  return 1.0f;
137 }
138 
139 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
140 {
141  for (UITouch *touch in touches) {
142  float pressure = [self pressureForTouch:touch];
143 
144  if (!firstFingerDown) {
145  CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
146  int clicks = (int) touch.tapCount;
147 
148  /* send mouse moved event */
149  SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
150 
151  /* send mouse down event */
153 
154  firstFingerDown = touch;
155  }
156 
157  CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
158  SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
159  SDL_TRUE, locationInView.x, locationInView.y, pressure);
160  }
161 }
162 
163 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
164 {
165  for (UITouch *touch in touches) {
166  float pressure = [self pressureForTouch:touch];
167 
168  if (touch == firstFingerDown) {
169  /* send mouse up */
170  int clicks = (int) touch.tapCount;
172  firstFingerDown = nil;
173  }
174 
175  CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
176  SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
177  SDL_FALSE, locationInView.x, locationInView.y, pressure);
178  }
179 }
180 
181 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
182 {
183  [self touchesEnded:touches withEvent:event];
184 }
185 
186 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
187 {
188  for (UITouch *touch in touches) {
189  float pressure = [self pressureForTouch:touch];
190 
191  if (touch == firstFingerDown) {
192  CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
193 
194  /* send moved event */
195  SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
196  }
197 
198  CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
199  SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
200  locationInView.x, locationInView.y, pressure);
201  }
202 }
203 
204 #if TARGET_OS_TV || defined(__IPHONE_9_1)
205 - (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype
206 {
207  switch (presstype) {
208  case UIPressTypeUpArrow:
209  return SDL_SCANCODE_UP;
210  case UIPressTypeDownArrow:
211  return SDL_SCANCODE_DOWN;
212  case UIPressTypeLeftArrow:
213  return SDL_SCANCODE_LEFT;
214  case UIPressTypeRightArrow:
215  return SDL_SCANCODE_RIGHT;
216  case UIPressTypeSelect:
217  /* HIG says: "primary button behavior" */
218  return SDL_SCANCODE_SELECT;
219  case UIPressTypeMenu:
220  /* HIG says: "returns to previous screen" */
221  return SDL_SCANCODE_MENU;
222  case UIPressTypePlayPause:
223  /* HIG says: "secondary button behavior" */
224  return SDL_SCANCODE_PAUSE;
225  default:
226  return SDL_SCANCODE_UNKNOWN;
227  }
228 }
229 
230 - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
231 {
232  for (UIPress *press in presses) {
233  SDL_Scancode scancode = [self scancodeFromPressType:press.type];
234  SDL_SendKeyboardKey(SDL_PRESSED, scancode);
235  }
236 
237  [super pressesBegan:presses withEvent:event];
238 }
239 
240 - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
241 {
242  for (UIPress *press in presses) {
243  SDL_Scancode scancode = [self scancodeFromPressType:press.type];
245  }
246 
247  [super pressesEnded:presses withEvent:event];
248 }
249 
250 - (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
251 {
252  for (UIPress *press in presses) {
253  SDL_Scancode scancode = [self scancodeFromPressType:press.type];
255  }
256 
257  [super pressesCancelled:presses withEvent:event];
258 }
259 
260 - (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
261 {
262  /* This is only called when the force of a press changes. */
263  [super pressesChanged:presses withEvent:event];
264 }
265 #endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */
266 
267 @end
268 
269 #endif /* SDL_VIDEO_DRIVER_UIKIT */
270 
271 /* vi: set ts=4 sw=4 expandtab: */
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
static SDL_Window * window
SDL_uikitviewcontroller * viewcontroller
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
int SDL_SendMouseButtonClicks(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
Definition: SDL_mouse.c:407
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:216
#define SDL_TOUCH_MOUSEID
Definition: SDL_touch.h:53
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:661
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:278
NSMutableArray * views
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
int frame
Definition: teststreaming.c:60
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:130
UIWindow * uiwindow
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
The type used to identify a window.
Definition: SDL_sysvideo.h:71
void * driverdata
Definition: SDL_sysvideo.h:109
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_RELEASED
Definition: SDL_events.h:49
GLuint in
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43