SDL  2.0
SDL_uikitevents.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 "../../events/SDL_events_c.h"
26 
27 #include "SDL_uikitvideo.h"
28 #include "SDL_uikitevents.h"
29 #include "SDL_uikitopengles.h"
30 
31 #import <Foundation/Foundation.h>
32 
33 #if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 140000) || (__MAC_OS_VERSION_MAX_ALLOWED > 1500000)
34 #import <GameController/GameController.h>
35 
36 #define ENABLE_GCKEYBOARD
37 #define ENABLE_GCMOUSE
38 #endif
39 
40 static BOOL UIKit_EventPumpEnabled = YES;
41 
42 void
44 {
45  UIKit_EventPumpEnabled = enabled;
46 }
47 
48 void
50 {
51  if (!UIKit_EventPumpEnabled) {
52  return;
53  }
54 
55  /* Let the run loop run for a short amount of time: long enough for
56  touch events to get processed (which is important to get certain
57  elements of Game Center's GKLeaderboardViewController to respond
58  to touch input), but not long enough to introduce a significant
59  delay in the rest of the app.
60  */
61  const CFTimeInterval seconds = 0.000002;
62 
63  /* Pump most event types. */
64  SInt32 result;
65  do {
66  result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, TRUE);
67  } while (result == kCFRunLoopRunHandledSource);
68 
69  /* Make sure UIScrollView objects scroll properly. */
70  do {
71  result = CFRunLoopRunInMode((CFStringRef)UITrackingRunLoopMode, seconds, TRUE);
72  } while(result == kCFRunLoopRunHandledSource);
73 
74  /* See the comment in the function definition. */
75 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
76  UIKit_GL_RestoreCurrentContext();
77 #endif
78 }
79 
80 #ifdef ENABLE_GCKEYBOARD
81 
82 static SDL_bool keyboard_connected = SDL_FALSE;
83 static id keyboard_connect_observer = nil;
84 static id keyboard_disconnect_observer = nil;
85 
86 static void OnGCKeyboardConnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
87 {
88  keyboard_connected = SDL_TRUE;
89  keyboard.keyboardInput.keyChangedHandler = ^(GCKeyboardInput *keyboard, GCControllerButtonInput *key, GCKeyCode keyCode, BOOL pressed)
90  {
92  };
93 
94  dispatch_queue_t queue = dispatch_queue_create( "org.libsdl.input.keyboard", DISPATCH_QUEUE_SERIAL );
95  dispatch_set_target_queue( queue, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ) );
96  keyboard.handlerQueue = queue;
97 }
98 
99 static void OnGCKeyboardDisconnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
100 {
101  keyboard.keyboardInput.keyChangedHandler = nil;
102  keyboard_connected = SDL_FALSE;
103 }
104 
105 void SDL_InitGCKeyboard(void)
106 {
107  @autoreleasepool {
108  if (@available(iOS 14.0, tvOS 14.0, *)) {
109  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
110 
111  keyboard_connect_observer = [center addObserverForName:GCKeyboardDidConnectNotification
112  object:nil
113  queue:nil
114  usingBlock:^(NSNotification *note) {
115  GCKeyboard *keyboard = note.object;
116  OnGCKeyboardConnected(keyboard);
117  }];
118 
119  keyboard_disconnect_observer = [center addObserverForName:GCKeyboardDidDisconnectNotification
120  object:nil
121  queue:nil
122  usingBlock:^(NSNotification *note) {
123  GCKeyboard *keyboard = note.object;
124  OnGCKeyboardDisconnected(keyboard);
125  }];
126 
127  if (GCKeyboard.coalescedKeyboard != nil) {
128  OnGCKeyboardConnected(GCKeyboard.coalescedKeyboard);
129  }
130  }
131  }
132 }
133 
135 {
136  return keyboard_connected;
137 }
138 
139 void SDL_QuitGCKeyboard(void)
140 {
141  @autoreleasepool {
142  if (@available(iOS 14.0, tvOS 14.0, *)) {
143  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
144 
145  if (keyboard_connect_observer) {
146  [center removeObserver:keyboard_connect_observer name:GCKeyboardDidConnectNotification object:nil];
147  keyboard_connect_observer = nil;
148  }
149 
150  if (keyboard_disconnect_observer) {
151  [center removeObserver:keyboard_disconnect_observer name:GCKeyboardDidDisconnectNotification object:nil];
152  keyboard_disconnect_observer = nil;
153  }
154 
155  if (GCKeyboard.coalescedKeyboard != nil) {
156  OnGCKeyboardDisconnected(GCKeyboard.coalescedKeyboard);
157  }
158  }
159  }
160 }
161 
162 #else
163 
164 void SDL_InitGCKeyboard(void)
165 {
166 }
167 
169 {
170  return SDL_FALSE;
171 }
172 
173 void SDL_QuitGCKeyboard(void)
174 {
175 }
176 
177 #endif /* ENABLE_GCKEYBOARD */
178 
179 
180 #ifdef ENABLE_GCMOUSE
181 
182 static int mice_connected = 0;
183 static id mouse_connect_observer = nil;
184 static id mouse_disconnect_observer = nil;
185 
186 static int SetGCMouseRelativeMode(SDL_bool enabled)
187 {
188  /* We'll always send relative motion and we can't warp, so nothing to do here */
189  return 0;
190 }
191 
192 static void OnGCMouseButtonChanged(SDL_MouseID mouseID, Uint8 button, BOOL pressed)
193 {
195 }
196 
197 static void OnGCMouseConnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
198 {
199  SDL_MouseID mouseID = mice_connected;
200 
201  mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
202  {
203  OnGCMouseButtonChanged(mouseID, SDL_BUTTON_LEFT, pressed);
204  };
205  mouse.mouseInput.middleButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
206  {
207  OnGCMouseButtonChanged(mouseID, SDL_BUTTON_MIDDLE, pressed);
208  };
209  mouse.mouseInput.rightButton.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
210  {
211  OnGCMouseButtonChanged(mouseID, SDL_BUTTON_RIGHT, pressed);
212  };
213 
214  int auxiliary_button = SDL_BUTTON_X1;
215  for (GCControllerButtonInput *button in mouse.mouseInput.auxiliaryButtons) {
216  button.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed)
217  {
218  OnGCMouseButtonChanged(mouseID, auxiliary_button, pressed);
219  };
220  ++auxiliary_button;
221  }
222 
223  mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput *mouse, float deltaX, float deltaY)
224  {
225  SDL_SendMouseMotion(SDL_GetMouseFocus(), mouseID, SDL_TRUE, (int)deltaX, -(int)deltaY);
226  };
227 
228  dispatch_queue_t queue = dispatch_queue_create( "org.libsdl.input.mouse", DISPATCH_QUEUE_SERIAL );
229  dispatch_set_target_queue( queue, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ) );
230  mouse.handlerQueue = queue;
231 
232  ++mice_connected;
233 }
234 
235 static void OnGCMouseDisconnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
236 {
237  --mice_connected;
238 
239  mouse.mouseInput.mouseMovedHandler = nil;
240 
241  mouse.mouseInput.leftButton.pressedChangedHandler = nil;
242  mouse.mouseInput.middleButton.pressedChangedHandler = nil;
243  mouse.mouseInput.rightButton.pressedChangedHandler = nil;
244 
245  for (GCControllerButtonInput *button in mouse.mouseInput.auxiliaryButtons) {
246  button.pressedChangedHandler = nil;
247  }
248 }
249 
250 void SDL_InitGCMouse(void)
251 {
252  @autoreleasepool {
253  /* There is a bug where mouse accumulates duplicate deltas over time in iOS 14.0 */
254  if (@available(iOS 14.1, tvOS 14.1, *)) {
255  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
256 
257  mouse_connect_observer = [center addObserverForName:GCMouseDidConnectNotification
258  object:nil
259  queue:nil
260  usingBlock:^(NSNotification *note) {
261  GCMouse *mouse = note.object;
262  OnGCMouseConnected(mouse);
263  }];
264 
265  mouse_disconnect_observer = [center addObserverForName:GCMouseDidDisconnectNotification
266  object:nil
267  queue:nil
268  usingBlock:^(NSNotification *note) {
269  GCMouse *mouse = note.object;
270  OnGCMouseDisconnected(mouse);
271  }];
272 
273  for (GCMouse *mouse in [GCMouse mice]) {
274  OnGCMouseConnected(mouse);
275  }
276 
277  SDL_GetMouse()->SetRelativeMouseMode = SetGCMouseRelativeMode;
278  }
279  }
280 }
281 
283 {
284  return (mice_connected > 0);
285 }
286 
287 void SDL_QuitGCMouse(void)
288 {
289  @autoreleasepool {
290  if (@available(iOS 14.1, tvOS 14.1, *)) {
291  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
292 
293  if (mouse_connect_observer) {
294  [center removeObserver:mouse_connect_observer name:GCMouseDidConnectNotification object:nil];
295  mouse_connect_observer = nil;
296  }
297 
298  if (mouse_disconnect_observer) {
299  [center removeObserver:mouse_disconnect_observer name:GCMouseDidDisconnectNotification object:nil];
300  mouse_disconnect_observer = nil;
301  }
302 
303  for (GCMouse *mouse in [GCMouse mice]) {
304  OnGCMouseDisconnected(mouse);
305  }
306 
308  }
309  }
310 }
311 
312 #else
313 
314 void SDL_InitGCMouse(void)
315 {
316 }
317 
319 {
320  return SDL_FALSE;
321 }
322 
323 void SDL_QuitGCMouse(void)
324 {
325 }
326 
327 #endif /* ENABLE_GCMOUSE */
328 
329 #endif /* SDL_VIDEO_DRIVER_UIKIT */
330 
331 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_iPhoneSetEventPump
#define SDL_GetMouseFocus
#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:806
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:599
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:175
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:298
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
Uint32 SDL_MouseID
Definition: SDL_mouse_c.h:28
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint64EXT * result
GLuint in
GLsizei const GLfloat * value
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:44
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint8_t Uint8
Definition: SDL_stdinc.h:185
SDL_bool SDL_HasGCKeyboard(void)
void SDL_InitGCMouse(void)
SDL_bool SDL_HasGCMouse(void)
void SDL_InitGCKeyboard(void)
void UIKit_PumpEvents(_THIS)
void SDL_QuitGCKeyboard(void)
void SDL_QuitGCMouse(void)
#define NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
GLuint64 key
Definition: gl2ext.h:2192
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
SDL_Texture * button