diff options
| author | chai <chaifix@163.com> | 2019-05-11 22:54:56 +0800 | 
|---|---|---|
| committer | chai <chaifix@163.com> | 2019-05-11 22:54:56 +0800 | 
| commit | 9645be0af1b1d5cb0ad5892d5464e1b23c51b550 (patch) | |
| tree | 129c716bed8e93312421c3adb2f8e7c4f811602d /source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m | |
Diffstat (limited to 'source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m')
| -rw-r--r-- | source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m | 553 | 
1 files changed, 553 insertions, 0 deletions
| diff --git a/source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m b/source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m new file mode 100644 index 0000000..49a39b6 --- /dev/null +++ b/source/3rd-party/SDL2/src/video/uikit/SDL_uikitviewcontroller.m @@ -0,0 +1,553 @@ +/* +  Simple DirectMedia Layer +  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + +  This software is provided 'as-is', without any express or implied +  warranty.  In no event will the authors be held liable for any damages +  arising from the use of this software. + +  Permission is granted to anyone to use this software for any purpose, +  including commercial applications, and to alter it and redistribute it +  freely, subject to the following restrictions: + +  1. The origin of this software must not be misrepresented; you must not +     claim that you wrote the original software. If you use this software +     in a product, an acknowledgment in the product documentation would be +     appreciated but is not required. +  2. Altered source versions must be plainly marked as such, and must not be +     misrepresented as being the original software. +  3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_UIKIT + +#include "SDL_video.h" +#include "SDL_assert.h" +#include "SDL_hints.h" +#include "../SDL_sysvideo.h" +#include "../../events/SDL_events_c.h" + +#import "SDL_uikitviewcontroller.h" +#import "SDL_uikitmessagebox.h" +#include "SDL_uikitvideo.h" +#include "SDL_uikitmodes.h" +#include "SDL_uikitwindow.h" +#include "SDL_uikitopengles.h" + +#if SDL_IPHONE_KEYBOARD +#include "keyinfotable.h" +#endif + +#if TARGET_OS_TV +static void SDLCALL +SDL_AppleTVControllerUIHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ +    @autoreleasepool { +        SDL_uikitviewcontroller *viewcontroller = (__bridge SDL_uikitviewcontroller *) userdata; +        viewcontroller.controllerUserInteractionEnabled = hint && (*hint != '0'); +    } +} +#endif + +#if !TARGET_OS_TV +static void SDLCALL +SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ +    @autoreleasepool { +        SDL_uikitviewcontroller *viewcontroller = (__bridge SDL_uikitviewcontroller *) userdata; +        viewcontroller.homeIndicatorHidden = (hint && *hint) ? SDL_atoi(hint) : -1; +        if (@available(iOS 11.0, *)) { +            [viewcontroller setNeedsUpdateOfHomeIndicatorAutoHidden]; +            [viewcontroller setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; +        } +    } +} +#endif + +@implementation SDL_uikitviewcontroller { +    CADisplayLink *displayLink; +    int animationInterval; +    void (*animationCallback)(void*); +    void *animationCallbackParam; + +#if SDL_IPHONE_KEYBOARD +    UITextField *textField; +    BOOL rotatingOrientation; +    NSString *changeText; +    NSString *obligateForBackspace; +#endif +} + +@synthesize window; + +- (instancetype)initWithSDLWindow:(SDL_Window *)_window +{ +    if (self = [super initWithNibName:nil bundle:nil]) { +        self.window = _window; + +#if SDL_IPHONE_KEYBOARD +        [self initKeyboard]; +        rotatingOrientation = FALSE; +#endif + +#if TARGET_OS_TV +        SDL_AddHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS, +                            SDL_AppleTVControllerUIHintChanged, +                            (__bridge void *) self); +#endif + +#if !TARGET_OS_TV +        SDL_AddHintCallback(SDL_HINT_IOS_HIDE_HOME_INDICATOR, +                            SDL_HideHomeIndicatorHintChanged, +                            (__bridge void *) self); +#endif +    } +    return self; +} + +- (void)dealloc +{ +#if SDL_IPHONE_KEYBOARD +    [self deinitKeyboard]; +#endif + +#if TARGET_OS_TV +    SDL_DelHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS, +                        SDL_AppleTVControllerUIHintChanged, +                        (__bridge void *) self); +#endif + +#if !TARGET_OS_TV +    SDL_DelHintCallback(SDL_HINT_IOS_HIDE_HOME_INDICATOR, +                        SDL_HideHomeIndicatorHintChanged, +                        (__bridge void *) self); +#endif +} + +- (void)setAnimationCallback:(int)interval +                    callback:(void (*)(void*))callback +               callbackParam:(void*)callbackParam +{ +    [self stopAnimation]; + +    animationInterval = interval; +    animationCallback = callback; +    animationCallbackParam = callbackParam; + +    if (animationCallback) { +        [self startAnimation]; +    } +} + +- (void)startAnimation +{ +    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; + +#ifdef __IPHONE_10_3 +    SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + +    if ([displayLink respondsToSelector:@selector(preferredFramesPerSecond)] +        && data != nil && data.uiwindow != nil +        && [data.uiwindow.screen respondsToSelector:@selector(maximumFramesPerSecond)]) { +        displayLink.preferredFramesPerSecond = data.uiwindow.screen.maximumFramesPerSecond / animationInterval; +    } else +#endif +    { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 100300 +        [displayLink setFrameInterval:animationInterval]; +#endif +    } + +    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; +} + +- (void)stopAnimation +{ +    [displayLink invalidate]; +    displayLink = nil; +} + +- (void)doLoop:(CADisplayLink*)sender +{ +    /* Don't run the game loop while a messagebox is up */ +    if (!UIKit_ShowingMessageBox()) { +        /* See the comment in the function definition. */ +        UIKit_GL_RestoreCurrentContext(); + +        animationCallback(animationCallbackParam); +    } +} + +- (void)loadView +{ +    /* Do nothing. */ +} + +- (void)viewDidLayoutSubviews +{ +    const CGSize size = self.view.bounds.size; +    int w = (int) size.width; +    int h = (int) size.height; + +    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); +} + +#if !TARGET_OS_TV +- (NSUInteger)supportedInterfaceOrientations +{ +    return UIKit_GetSupportedOrientations(window); +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient +{ +    return ([self supportedInterfaceOrientations] & (1 << orient)) != 0; +} +#endif + +- (BOOL)prefersStatusBarHidden +{ +    BOOL hidden = (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0; +    return hidden; +} + +- (BOOL)prefersHomeIndicatorAutoHidden +{ +    BOOL hidden = NO; +    if (self.homeIndicatorHidden == 1) { +        hidden = YES; +    } +    return hidden; +} + +- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures +{ +    if (self.homeIndicatorHidden >= 0) { +        if (self.homeIndicatorHidden == 2) { +            return UIRectEdgeAll; +        } else { +            return UIRectEdgeNone; +        } +    } + +    /* By default, fullscreen and borderless windows get all screen gestures */ +    if ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0) { +        return UIRectEdgeAll; +    } else { +        return UIRectEdgeNone; +    } +} +#endif + +/* + ---- Keyboard related functionality below this line ---- + */ +#if SDL_IPHONE_KEYBOARD + +@synthesize textInputRect; +@synthesize keyboardHeight; +@synthesize keyboardVisible; + +/* Set ourselves up as a UITextFieldDelegate */ +- (void)initKeyboard +{ +    changeText = nil; +    obligateForBackspace = @"                                                                "; /* 64 space */ +    textField = [[UITextField alloc] initWithFrame:CGRectZero]; +    textField.delegate = self; +    /* placeholder so there is something to delete! */ +    textField.text = obligateForBackspace; + +    /* set UITextInputTrait properties, mostly to defaults */ +    textField.autocapitalizationType = UITextAutocapitalizationTypeNone; +    textField.autocorrectionType = UITextAutocorrectionTypeNo; +    textField.enablesReturnKeyAutomatically = NO; +    textField.keyboardAppearance = UIKeyboardAppearanceDefault; +    textField.keyboardType = UIKeyboardTypeDefault; +    textField.returnKeyType = UIReturnKeyDefault; +    textField.secureTextEntry = NO; + +    textField.hidden = YES; +    keyboardVisible = NO; + +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; +#if !TARGET_OS_TV +    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; +    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; +#endif +    [center addObserver:self selector:@selector(textFieldTextDidChange:) name:UITextFieldTextDidChangeNotification object:nil]; +} + +- (void)setView:(UIView *)view +{ +    [super setView:view]; + +    [view addSubview:textField]; + +    if (keyboardVisible) { +        [self showKeyboard]; +    } +} + +/* willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation are deprecated in iOS 8+ in favor of viewWillTransitionToSize */ +#if TARGET_OS_TV || __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000 +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator +{ +    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; +    rotatingOrientation = TRUE; +    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {} +                                 completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { +                                     rotatingOrientation = FALSE; +                                 }]; +} +#else +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { +    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; +    rotatingOrientation = TRUE; +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { +    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; +    rotatingOrientation = FALSE; +} +#endif /* TARGET_OS_TV || __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000 */ + +- (void)deinitKeyboard +{ +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; +#if !TARGET_OS_TV +    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil]; +    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +#endif +    [center removeObserver:self name:UITextFieldTextDidChangeNotification object:nil]; +} + +/* reveal onscreen virtual keyboard */ +- (void)showKeyboard +{ +    keyboardVisible = YES; +    if (textField.window) { +        [textField becomeFirstResponder]; +    } +} + +/* hide onscreen virtual keyboard */ +- (void)hideKeyboard +{ +    keyboardVisible = NO; +    [textField resignFirstResponder]; +} + +- (void)keyboardWillShow:(NSNotification *)notification +{ +#if !TARGET_OS_TV +    CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue]; + +    /* The keyboard rect is in the coordinate space of the screen/window, but we +     * want its height in the coordinate space of the view. */ +    kbrect = [self.view convertRect:kbrect fromView:nil]; + +    [self setKeyboardHeight:(int)kbrect.size.height]; +#endif +} + +- (void)keyboardWillHide:(NSNotification *)notification +{ +    if (!rotatingOrientation) { +        SDL_StopTextInput(); +    } +    [self setKeyboardHeight:0]; +} + +- (void)textFieldTextDidChange:(NSNotification *)notification +{ +    if (changeText!=nil && textField.markedTextRange == nil) +    { +        NSUInteger len = changeText.length; +        if (len > 0) { +            /* Go through all the characters in the string we've been sent and +             * convert them to key presses */ +            int i; +            for (i = 0; i < len; i++) { +                unichar c = [changeText characterAtIndex:i]; +                SDL_Scancode code; +                Uint16 mod; + +                if (c < 127) { +                    /* Figure out the SDL_Scancode and SDL_keymod for this unichar */ +                    code = unicharToUIKeyInfoTable[c].code; +                    mod  = unicharToUIKeyInfoTable[c].mod; +                } else { +                    /* We only deal with ASCII right now */ +                    code = SDL_SCANCODE_UNKNOWN; +                    mod = 0; +                } + +                if (mod & KMOD_SHIFT) { +                    /* If character uses shift, press shift down */ +                    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT); +                } + +                /* send a keydown and keyup even for the character */ +                SDL_SendKeyboardKey(SDL_PRESSED, code); +                SDL_SendKeyboardKey(SDL_RELEASED, code); + +                if (mod & KMOD_SHIFT) { +                    /* If character uses shift, press shift back up */ +                    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT); +                } +            } +            SDL_SendKeyboardText([changeText UTF8String]); +        } +        changeText = nil; +    } +} + +- (void)updateKeyboard +{ +    CGAffineTransform t = self.view.transform; +    CGPoint offset = CGPointMake(0.0, 0.0); +    CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen); + +    if (self.keyboardHeight) { +        int rectbottom = self.textInputRect.y + self.textInputRect.h; +        int keybottom = self.view.bounds.size.height - self.keyboardHeight; +        if (keybottom < rectbottom) { +            offset.y = keybottom - rectbottom; +        } +    } + +    /* Apply this view's transform (except any translation) to the offset, in +     * order to orient it correctly relative to the frame's coordinate space. */ +    t.tx = 0.0; +    t.ty = 0.0; +    offset = CGPointApplyAffineTransform(offset, t); + +    /* Apply the updated offset to the view's frame. */ +    frame.origin.x += offset.x; +    frame.origin.y += offset.y; + +    self.view.frame = frame; +} + +- (void)setKeyboardHeight:(int)height +{ +    keyboardVisible = height > 0; +    keyboardHeight = height; +    [self updateKeyboard]; +} + +/* UITextFieldDelegate method.  Invoked when user types something. */ +- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string +{ +    NSUInteger len = string.length; +    if (len == 0) { +        changeText = nil; +        if (textField.markedTextRange == nil) { +            /* it wants to replace text with nothing, ie a delete */ +            SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE); +            SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE); +        } +        if (textField.text.length < 16) { +            textField.text = obligateForBackspace; +        } +    } else { +        changeText = string; +    } +    return YES; +} + +/* Terminates the editing session */ +- (BOOL)textFieldShouldReturn:(UITextField*)_textField +{ +    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN); +    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN); +    if (SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE)) { +         SDL_StopTextInput(); +    } +    return YES; +} + +#endif + +@end + +/* iPhone keyboard addition functions */ +#if SDL_IPHONE_KEYBOARD + +static SDL_uikitviewcontroller * +GetWindowViewController(SDL_Window * window) +{ +    if (!window || !window->driverdata) { +        SDL_SetError("Invalid window"); +        return nil; +    } + +    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + +    return data.viewcontroller; +} + +SDL_bool +UIKit_HasScreenKeyboardSupport(_THIS) +{ +    return SDL_TRUE; +} + +void +UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window) +{ +    @autoreleasepool { +        SDL_uikitviewcontroller *vc = GetWindowViewController(window); +        [vc showKeyboard]; +    } +} + +void +UIKit_HideScreenKeyboard(_THIS, SDL_Window *window) +{ +    @autoreleasepool { +        SDL_uikitviewcontroller *vc = GetWindowViewController(window); +        [vc hideKeyboard]; +    } +} + +SDL_bool +UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window) +{ +    @autoreleasepool { +        SDL_uikitviewcontroller *vc = GetWindowViewController(window); +        if (vc != nil) { +            return vc.keyboardVisible; +        } +        return SDL_FALSE; +    } +} + +void +UIKit_SetTextInputRect(_THIS, SDL_Rect *rect) +{ +    if (!rect) { +        SDL_InvalidParamError("rect"); +        return; +    } + +    @autoreleasepool { +        SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow()); +        if (vc != nil) { +            vc.textInputRect = *rect; + +            if (vc.keyboardVisible) { +                [vc updateKeyboard]; +            } +        } +    } +} + + +#endif /* SDL_IPHONE_KEYBOARD */ + +#endif /* SDL_VIDEO_DRIVER_UIKIT */ + +/* vi: set ts=4 sw=4 expandtab: */ | 
