SDL  2.0
SDL_uikitviewcontroller.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_video.h"
26 #include "SDL_assert.h"
27 #include "SDL_hints.h"
28 #include "../SDL_sysvideo.h"
29 #include "../../events/SDL_events_c.h"
30 
32 #import "SDL_uikitmessagebox.h"
33 #include "SDL_uikitvideo.h"
34 #include "SDL_uikitmodes.h"
35 #include "SDL_uikitwindow.h"
36 
37 #if SDL_IPHONE_KEYBOARD
38 #include "keyinfotable.h"
39 #endif
40 
41 @implementation SDL_uikitviewcontroller {
42  CADisplayLink *displayLink;
43  int animationInterval;
44  void (*animationCallback)(void*);
45  void *animationCallbackParam;
46 
47 #if SDL_IPHONE_KEYBOARD
48  UITextField *textField;
49 #endif
50 }
51 
52 @synthesize window;
53 
54 - (instancetype)initWithSDLWindow:(SDL_Window *)_window
55 {
56  if (self = [super initWithNibName:nil bundle:nil]) {
57  self.window = _window;
58 
59 #if SDL_IPHONE_KEYBOARD
60  [self initKeyboard];
61 #endif
62  }
63  return self;
64 }
65 
66 - (void)dealloc
67 {
68 #if SDL_IPHONE_KEYBOARD
69  [self deinitKeyboard];
70 #endif
71 }
72 
73 - (void)setAnimationCallback:(int)interval
74  callback:(void (*)(void*))callback
75  callbackParam:(void*)callbackParam
76 {
77  [self stopAnimation];
78 
79  animationInterval = interval;
80  animationCallback = callback;
81  animationCallbackParam = callbackParam;
82 
83  if (animationCallback) {
84  [self startAnimation];
85  }
86 }
87 
89 {
90  displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
91  [displayLink setFrameInterval:animationInterval];
92  [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
93 }
94 
96 {
97  [displayLink invalidate];
98  displayLink = nil;
99 }
100 
101 - (void)doLoop:(CADisplayLink*)sender
102 {
103  /* Don't run the game loop while a messagebox is up */
104  if (!UIKit_ShowingMessageBox()) {
105  animationCallback(animationCallbackParam);
106  }
107 }
108 
109 - (void)loadView
110 {
111  /* Do nothing. */
112 }
113 
115 {
116  const CGSize size = self.view.bounds.size;
117  int w = (int) size.width;
118  int h = (int) size.height;
119 
121 }
122 
123 - (NSUInteger)supportedInterfaceOrientations
124 {
126 }
127 
128 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
129 {
130  return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
131 }
132 
134 {
136 }
137 
138 /*
139  ---- Keyboard related functionality below this line ----
140  */
141 #if SDL_IPHONE_KEYBOARD
142 
143 @synthesize textInputRect;
144 @synthesize keyboardHeight;
145 @synthesize keyboardVisible;
146 
147 /* Set ourselves up as a UITextFieldDelegate */
148 - (void)initKeyboard
149 {
150  textField = [[UITextField alloc] initWithFrame:CGRectZero];
151  textField.delegate = self;
152  /* placeholder so there is something to delete! */
153  textField.text = @" ";
154 
155  /* set UITextInputTrait properties, mostly to defaults */
156  textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
157  textField.autocorrectionType = UITextAutocorrectionTypeNo;
158  textField.enablesReturnKeyAutomatically = NO;
159  textField.keyboardAppearance = UIKeyboardAppearanceDefault;
160  textField.keyboardType = UIKeyboardTypeDefault;
161  textField.returnKeyType = UIReturnKeyDefault;
162  textField.secureTextEntry = NO;
163 
164  textField.hidden = YES;
165  keyboardVisible = NO;
166 
167  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
168  [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
169  [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
170 }
171 
172 - (void)setView:(UIView *)view
173 {
174  [super setView:view];
175 
176  [view addSubview:textField];
177 
178  if (keyboardVisible) {
179  [self showKeyboard];
180  }
181 }
182 
183 - (void)deinitKeyboard
184 {
185  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
186  [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
187  [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
188 }
189 
190 /* reveal onscreen virtual keyboard */
191 - (void)showKeyboard
192 {
193  keyboardVisible = YES;
194  if (textField.window) {
195  [textField becomeFirstResponder];
196  }
197 }
198 
199 /* hide onscreen virtual keyboard */
200 - (void)hideKeyboard
201 {
202  keyboardVisible = NO;
203  [textField resignFirstResponder];
204 }
205 
206 - (void)keyboardWillShow:(NSNotification *)notification
207 {
208  CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
209 
210  /* The keyboard rect is in the coordinate space of the screen/window, but we
211  * want its height in the coordinate space of the view. */
212  kbrect = [self.view convertRect:kbrect fromView:nil];
213 
214  [self setKeyboardHeight:(int)kbrect.size.height];
215 }
216 
217 - (void)keyboardWillHide:(NSNotification *)notification
218 {
219  [self setKeyboardHeight:0];
220 }
221 
222 - (void)updateKeyboard
223 {
224  CGAffineTransform t = self.view.transform;
225  CGPoint offset = CGPointMake(0.0, 0.0);
226  CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen);
227 
228  if (self.keyboardHeight) {
229  int rectbottom = self.textInputRect.y + self.textInputRect.h;
230  int keybottom = self.view.bounds.size.height - self.keyboardHeight;
231  if (keybottom < rectbottom) {
232  offset.y = keybottom - rectbottom;
233  }
234  }
235 
236  /* Apply this view's transform (except any translation) to the offset, in
237  * order to orient it correctly relative to the frame's coordinate space. */
238  t.tx = 0.0;
239  t.ty = 0.0;
240  offset = CGPointApplyAffineTransform(offset, t);
241 
242  /* Apply the updated offset to the view's frame. */
243  frame.origin.x += offset.x;
244  frame.origin.y += offset.y;
245 
246  self.view.frame = frame;
247 }
248 
249 - (void)setKeyboardHeight:(int)height
250 {
251  keyboardVisible = height > 0;
252  keyboardHeight = height;
253  [self updateKeyboard];
254 }
255 
256 /* UITextFieldDelegate method. Invoked when user types something. */
257 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
258 {
259  NSUInteger len = string.length;
260 
261  if (len == 0) {
262  /* it wants to replace text with nothing, ie a delete */
265  } else {
266  /* go through all the characters in the string we've been sent and
267  * convert them to key presses */
268  int i;
269  for (i = 0; i < len; i++) {
270  unichar c = [string characterAtIndex:i];
271  Uint16 mod = 0;
272  SDL_Scancode code;
273 
274  if (c < 127) {
275  /* figure out the SDL_Scancode and SDL_keymod for this unichar */
276  code = unicharToUIKeyInfoTable[c].code;
277  mod = unicharToUIKeyInfoTable[c].mod;
278  } else {
279  /* we only deal with ASCII right now */
280  code = SDL_SCANCODE_UNKNOWN;
281  mod = 0;
282  }
283 
284  if (mod & KMOD_SHIFT) {
285  /* If character uses shift, press shift down */
287  }
288 
289  /* send a keydown and keyup even for the character */
292 
293  if (mod & KMOD_SHIFT) {
294  /* If character uses shift, press shift back up */
296  }
297  }
298 
299  SDL_SendKeyboardText([string UTF8String]);
300  }
301 
302  return NO; /* don't allow the edit! (keep placeholder text there) */
303 }
304 
305 /* Terminates the editing session */
306 - (BOOL)textFieldShouldReturn:(UITextField*)_textField
307 {
311  return YES;
312 }
313 
314 #endif
315 
316 @end
317 
318 /* iPhone keyboard addition functions */
319 #if SDL_IPHONE_KEYBOARD
320 
322 GetWindowViewController(SDL_Window * window)
323 {
324  if (!window || !window->driverdata) {
325  SDL_SetError("Invalid window");
326  return nil;
327  }
328 
329  SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
330 
331  return data.viewcontroller;
332 }
333 
334 SDL_bool
335 UIKit_HasScreenKeyboardSupport(_THIS)
336 {
337  return SDL_TRUE;
338 }
339 
340 void
341 UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
342 {
343  @autoreleasepool {
344  SDL_uikitviewcontroller *vc = GetWindowViewController(window);
345  [vc showKeyboard];
346  }
347 }
348 
349 void
350 UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
351 {
352  @autoreleasepool {
353  SDL_uikitviewcontroller *vc = GetWindowViewController(window);
354  [vc hideKeyboard];
355  }
356 }
357 
358 SDL_bool
359 UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
360 {
361  @autoreleasepool {
362  SDL_uikitviewcontroller *vc = GetWindowViewController(window);
363  if (vc != nil) {
364  return vc.isKeyboardVisible;
365  }
366  return SDL_FALSE;
367  }
368 }
369 
370 void
371 UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
372 {
373  if (!rect) {
374  SDL_InvalidParamError("rect");
375  return;
376  }
377 
378  @autoreleasepool {
379  SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
380  if (vc != nil) {
381  vc.textInputRect = *rect;
382 
383  if (vc.keyboardVisible) {
384  [vc updateKeyboard];
385  }
386  }
387  }
388 }
389 
390 
391 #endif /* SDL_IPHONE_KEYBOARD */
392 
393 #endif /* SDL_VIDEO_DRIVER_UIKIT */
394 
395 /* vi: set ts=4 sw=4 expandtab: */
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
GLsizei const GLchar *const * string
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Rect rect
Definition: testrelative.c:27
SDL_uikitviewcontroller * viewcontroller
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_Scancode code
Definition: keyinfotable.h:36
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
NSUInteger UIKit_GetSupportedOrientations(SDL_Window *window)
GLsizeiptr size
GLenum GLsizei len
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:661
SDL_bool
Definition: SDL_stdinc.h:126
#define SDL_StopTextInput
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
#define KMOD_SHIFT
Definition: SDL_keycode.h:335
static UIKitKeyInfo unicharToUIKeyInfoTable[]
Definition: keyinfotable.h:41
#define _THIS
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
int frame
Definition: teststreaming.c:60
SDL_Window * SDL_GetFocusWindow(void)
Definition: SDL_video.c:2403
const GLubyte * c
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
GLintptr offset
#define SDL_SetError
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
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
GLubyte GLubyte GLubyte GLubyte w
void * driverdata
Definition: SDL_sysvideo.h:106
#define SDL_PRESSED
Definition: SDL_events.h:50
Uint32 flags
Definition: SDL_sysvideo.h:81
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
GLfloat GLfloat GLfloat GLfloat h
GLdouble GLdouble t
Definition: SDL_opengl.h:2064
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
NSUInteger supportedInterfaceOrientations()