cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_uikitview.m (14222B)


      1 /*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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_keyboard_c.h"
     28#include "../../events/SDL_mouse_c.h"
     29#include "../../events/SDL_touch_c.h"
     30
     31#if SDL_IPHONE_KEYBOARD
     32#include "keyinfotable.h"
     33#endif
     34#include "SDL_uikitappdelegate.h"
     35#include "SDL_uikitmodes.h"
     36#include "SDL_uikitwindow.h"
     37
     38void _uikit_keyboard_init() ;
     39
     40@implementation SDL_uikitview
     41
     42- (void)dealloc
     43{
     44    [super dealloc];
     45}
     46
     47- (id)initWithFrame:(CGRect)frame
     48{
     49    self = [super initWithFrame: frame];
     50
     51#if SDL_IPHONE_KEYBOARD
     52    [self initializeKeyboard];
     53#endif
     54
     55    self.multipleTouchEnabled = YES;
     56
     57    touchId = 1;
     58    SDL_AddTouch(touchId, "");
     59
     60    return self;
     61
     62}
     63
     64- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
     65{
     66    CGPoint point = [touch locationInView: self];
     67
     68    /* Get the display scale and apply that to the input coordinates */
     69    SDL_Window *window = self->viewcontroller.window;
     70    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
     71    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
     72
     73    if (normalize) {
     74        CGRect bounds = [self bounds];
     75        point.x /= bounds.size.width;
     76        point.y /= bounds.size.height;
     77    } else {
     78        point.x *= displaymodedata->scale;
     79        point.y *= displaymodedata->scale;
     80    }
     81    return point;
     82}
     83
     84- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
     85{
     86    NSEnumerator *enumerator = [touches objectEnumerator];
     87    UITouch *touch = (UITouch*)[enumerator nextObject];
     88
     89    while (touch) {
     90        if (!leftFingerDown) {
     91            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
     92
     93            /* send moved event */
     94            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
     95
     96            /* send mouse down event */
     97            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
     98
     99            leftFingerDown = touch;
    100        }
    101
    102        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
    103#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
    104        /* FIXME: TODO: Using touch as the fingerId is potentially dangerous
    105         * It is also much more efficient than storing the UITouch pointer
    106         * and comparing it to the incoming event.
    107         */
    108        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
    109                      SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
    110#else
    111        int i;
    112        for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
    113            if (finger[i] == NULL) {
    114                finger[i] = touch;
    115                SDL_SendTouch(touchId, i,
    116                              SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
    117                break;
    118            }
    119        }
    120#endif
    121        touch = (UITouch*)[enumerator nextObject];
    122    }
    123}
    124
    125- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    126{
    127    NSEnumerator *enumerator = [touches objectEnumerator];
    128    UITouch *touch = (UITouch*)[enumerator nextObject];
    129
    130    while(touch) {
    131        if (touch == leftFingerDown) {
    132            /* send mouse up */
    133            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
    134            leftFingerDown = nil;
    135        }
    136
    137        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
    138#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
    139        SDL_SendTouch(touchId, (long)touch,
    140                      SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
    141#else
    142        int i;
    143        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
    144            if (finger[i] == touch) {
    145                SDL_SendTouch(touchId, i,
    146                              SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
    147                finger[i] = NULL;
    148                break;
    149            }
    150        }
    151#endif
    152        touch = (UITouch*)[enumerator nextObject];
    153    }
    154}
    155
    156- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    157{
    158    /*
    159        this can happen if the user puts more than 5 touches on the screen
    160        at once, or perhaps in other circumstances.  Usually (it seems)
    161        all active touches are canceled.
    162    */
    163    [self touchesEnded: touches withEvent: event];
    164}
    165
    166- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    167{
    168    NSEnumerator *enumerator = [touches objectEnumerator];
    169    UITouch *touch = (UITouch*)[enumerator nextObject];
    170
    171    while (touch) {
    172        if (touch == leftFingerDown) {
    173            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
    174
    175            /* send moved event */
    176            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
    177        }
    178
    179        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
    180#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
    181        SDL_SendTouchMotion(touchId, (long)touch,
    182                            locationInView.x, locationInView.y, 1.0f);
    183#else
    184        int i;
    185        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
    186            if (finger[i] == touch) {
    187                SDL_SendTouchMotion(touchId, i,
    188                                    locationInView.x, locationInView.y, 1.0f);
    189                break;
    190            }
    191        }
    192#endif
    193        touch = (UITouch*)[enumerator nextObject];
    194    }
    195}
    196
    197/*
    198    ---- Keyboard related functionality below this line ----
    199*/
    200#if SDL_IPHONE_KEYBOARD
    201
    202@synthesize textInputRect = textInputRect;
    203@synthesize keyboardHeight = keyboardHeight;
    204
    205/* Is the iPhone virtual keyboard visible onscreen? */
    206- (BOOL)keyboardVisible
    207{
    208    return keyboardVisible;
    209}
    210
    211/* Set ourselves up as a UITextFieldDelegate */
    212- (void)initializeKeyboard
    213{
    214    textField = [[UITextField alloc] initWithFrame: CGRectZero];
    215    textField.delegate = self;
    216    /* placeholder so there is something to delete! */
    217    textField.text = @" ";
    218
    219    /* set UITextInputTrait properties, mostly to defaults */
    220    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
    221    textField.autocorrectionType = UITextAutocorrectionTypeNo;
    222    textField.enablesReturnKeyAutomatically = NO;
    223    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
    224    textField.keyboardType = UIKeyboardTypeDefault;
    225    textField.returnKeyType = UIReturnKeyDefault;
    226    textField.secureTextEntry = NO;
    227
    228    textField.hidden = YES;
    229    keyboardVisible = NO;
    230    /* add the UITextField (hidden) to our view */
    231    [self addSubview: textField];
    232    [textField release];
    233    
    234    _uikit_keyboard_init();
    235}
    236
    237/* reveal onscreen virtual keyboard */
    238- (void)showKeyboard
    239{
    240    keyboardVisible = YES;
    241    [textField becomeFirstResponder];
    242}
    243
    244/* hide onscreen virtual keyboard */
    245- (void)hideKeyboard
    246{
    247    keyboardVisible = NO;
    248    [textField resignFirstResponder];
    249}
    250
    251/* UITextFieldDelegate method.  Invoked when user types something. */
    252- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    253{
    254    if ([string length] == 0) {
    255        /* it wants to replace text with nothing, ie a delete */
    256        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
    257        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
    258    }
    259    else {
    260        /* go through all the characters in the string we've been sent
    261           and convert them to key presses */
    262        int i;
    263        for (i = 0; i < [string length]; i++) {
    264
    265            unichar c = [string characterAtIndex: i];
    266
    267            Uint16 mod = 0;
    268            SDL_Scancode code;
    269
    270            if (c < 127) {
    271                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
    272                code = unicharToUIKeyInfoTable[c].code;
    273                mod  = unicharToUIKeyInfoTable[c].mod;
    274            }
    275            else {
    276                /* we only deal with ASCII right now */
    277                code = SDL_SCANCODE_UNKNOWN;
    278                mod = 0;
    279            }
    280
    281            if (mod & KMOD_SHIFT) {
    282                /* If character uses shift, press shift down */
    283                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
    284            }
    285            /* send a keydown and keyup even for the character */
    286            SDL_SendKeyboardKey(SDL_PRESSED, code);
    287            SDL_SendKeyboardKey(SDL_RELEASED, code);
    288            if (mod & KMOD_SHIFT) {
    289                /* If character uses shift, press shift back up */
    290                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
    291            }
    292        }
    293        SDL_SendKeyboardText([string UTF8String]);
    294    }
    295    return NO; /* don't allow the edit! (keep placeholder text there) */
    296}
    297
    298/* Terminates the editing session */
    299- (BOOL)textFieldShouldReturn:(UITextField*)_textField
    300{
    301    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
    302    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
    303    SDL_StopTextInput();
    304    return YES;
    305}
    306
    307#endif
    308
    309@end
    310
    311/* iPhone keyboard addition functions */
    312#if SDL_IPHONE_KEYBOARD
    313
    314static SDL_uikitview * getWindowView(SDL_Window * window)
    315{
    316    if (window == NULL) {
    317        SDL_SetError("Window does not exist");
    318        return nil;
    319    }
    320
    321    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    322    SDL_uikitview *view = data != NULL ? data->view : nil;
    323
    324    if (view == nil) {
    325        SDL_SetError("Window has no view");
    326    }
    327
    328    return view;
    329}
    330
    331SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
    332{
    333    return SDL_TRUE;
    334}
    335
    336void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
    337{
    338    SDL_uikitview *view = getWindowView(window);
    339    if (view != nil) {
    340        [view showKeyboard];
    341    }
    342}
    343
    344void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
    345{
    346    SDL_uikitview *view = getWindowView(window);
    347    if (view != nil) {
    348        [view hideKeyboard];
    349    }
    350}
    351
    352SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
    353{
    354    SDL_uikitview *view = getWindowView(window);
    355    if (view == nil) {
    356        return 0;
    357    }
    358
    359    return view.keyboardVisible;
    360}
    361
    362
    363void _uikit_keyboard_update() {
    364    SDL_Window *window = SDL_GetFocusWindow();
    365    if (!window) { return; }
    366    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    367    if (!data) { return; }
    368    SDL_uikitview *view = data->view;
    369    if (!view) { return; }
    370    
    371    SDL_Rect r = view.textInputRect;
    372    int height = view.keyboardHeight;
    373    int offsetx = 0;
    374    int offsety = 0;
    375    float scale = [UIScreen mainScreen].scale;
    376    if (height) {
    377        int sw,sh;
    378        SDL_GetWindowSize(window,&sw,&sh);
    379        int bottom = (r.y + r.h);
    380        int kbottom = sh - height;
    381        if (kbottom < bottom) {
    382            offsety = kbottom-bottom;
    383        }
    384    }
    385    UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
    386    if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
    387        int tmp = offsetx; offsetx = offsety; offsety = tmp;
    388    }
    389    if (ui_orient == UIInterfaceOrientationLandscapeRight) {
    390        offsety = -offsety;
    391        int tmp = offsetx; offsetx = offsety; offsety = tmp;
    392    }
    393    if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
    394        offsety = -offsety;
    395    }
    396
    397    offsetx /= scale;
    398    offsety /= scale;
    399
    400    view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
    401}
    402
    403void _uikit_keyboard_set_height(int height) {
    404    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
    405    if (view == nil) {
    406        return ;
    407    }
    408    
    409    view.keyboardHeight = height;
    410    _uikit_keyboard_update();
    411}
    412
    413void _uikit_keyboard_init() {
    414    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    415    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    416    [center addObserverForName:UIKeyboardWillShowNotification
    417                        object:nil
    418                         queue:queue
    419                    usingBlock:^(NSNotification *notification) {
    420                        int height = 0;
    421                        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    422                        height = keyboardSize.height;
    423                        UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
    424                        if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
    425                            height = keyboardSize.width;
    426                        }
    427                        height *= [UIScreen mainScreen].scale;
    428                        _uikit_keyboard_set_height(height);
    429                    }
    430     ];
    431    [center addObserverForName:UIKeyboardDidHideNotification
    432                        object:nil
    433                         queue:queue
    434                    usingBlock:^(NSNotification *notification) {
    435                        _uikit_keyboard_set_height(0);
    436                    }
    437     ];
    438}
    439
    440void
    441UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
    442{
    443    if (!rect) {
    444        SDL_InvalidParamError("rect");
    445        return;
    446    }
    447    
    448    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
    449    if (view == nil) {
    450        return ;
    451    }
    452
    453    view.textInputRect = *rect;
    454}
    455
    456
    457#endif /* SDL_IPHONE_KEYBOARD */
    458
    459#endif /* SDL_VIDEO_DRIVER_UIKIT */
    460
    461/* vi: set ts=4 sw=4 expandtab: */