src/joystick/iphoneos/SDL_sysjoystick.m
author Alex Szpakowski <slime73@gmail.com>
Tue, 29 Jul 2014 00:36:12 -0300
branchiOS-improvements
changeset 9506 18e3f94bd860
parent 9490 9eab796ea0b8
child 9510 e19faa3b5d88
permissions -rw-r--r--
Added missing autorelease pool blocks in UIKit backend code. Fixes memory leak issues, especially in SDL_video.
     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 /* This is the iOS implementation of the SDL joystick API */
    24 
    25 #include "SDL_joystick.h"
    26 #include "SDL_hints.h"
    27 #include "SDL_stdinc.h"
    28 #include "../SDL_sysjoystick.h"
    29 #include "../SDL_joystick_c.h"
    30 
    31 #import <CoreMotion/CoreMotion.h>
    32 
    33 /* needed for SDL_IPHONE_MAX_GFORCE macro */
    34 #import "SDL_config_iphoneos.h"
    35 
    36 const char *accelerometerName = "iOS Accelerometer";
    37 
    38 static CMMotionManager *motionManager = nil;
    39 static int numjoysticks = 0;
    40 
    41 /* Function to scan the system for joysticks.
    42  * This function should set SDL_numjoysticks to the number of available
    43  * joysticks.  Joystick 0 should be the system default joystick.
    44  * It should return 0, or -1 on an unrecoverable fatal error.
    45  */
    46 int
    47 SDL_SYS_JoystickInit(void)
    48 {
    49     const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
    50     if (!hint || SDL_atoi(hint)) {
    51         /* Default behavior, accelerometer as joystick */
    52         numjoysticks = 1;
    53     }
    54 
    55     return numjoysticks;
    56 }
    57 
    58 int SDL_SYS_NumJoysticks()
    59 {
    60     return numjoysticks;
    61 }
    62 
    63 void SDL_SYS_JoystickDetect()
    64 {
    65 }
    66 
    67 /* Function to get the device-dependent name of a joystick */
    68 const char *
    69 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
    70 {
    71     return accelerometerName;
    72 }
    73 
    74 /* Function to perform the mapping from device index to the instance id for this index */
    75 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
    76 {
    77     return device_index;
    78 }
    79 
    80 /* Function to open a joystick for use.
    81    The joystick to open is specified by the index field of the joystick.
    82    This should fill the nbuttons and naxes fields of the joystick structure.
    83    It returns 0, or -1 if there is an error.
    84  */
    85 int
    86 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
    87 {
    88     joystick->naxes = 3;
    89     joystick->nhats = 0;
    90     joystick->nballs = 0;
    91     joystick->nbuttons = 0;
    92 
    93     @autoreleasepool {
    94         if (motionManager == nil) {
    95             motionManager = [[CMMotionManager alloc] init];
    96         }
    97 
    98         /* Shorter times between updates can significantly increase CPU usage. */
    99         motionManager.accelerometerUpdateInterval = 0.1;
   100         [motionManager startAccelerometerUpdates];
   101     }
   102 
   103     return 0;
   104 }
   105 
   106 /* Function to determine is this joystick is attached to the system right now */
   107 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   108 {
   109     return SDL_TRUE;
   110 }
   111 
   112 static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
   113 {
   114     const float maxgforce = SDL_IPHONE_MAX_GFORCE;
   115     const SInt16 maxsint16 = 0x7FFF;
   116     CMAcceleration accel;
   117 
   118     @autoreleasepool {
   119         if (!motionManager.accelerometerActive) {
   120             return;
   121         }
   122 
   123         accel = motionManager.accelerometerData.acceleration;
   124     }
   125 
   126     /*
   127      Convert accelerometer data from floating point to Sint16, which is what
   128      the joystick system expects.
   129 
   130      To do the conversion, the data is first clamped onto the interval
   131      [-SDL_IPHONE_MAX_G_FORCE, SDL_IPHONE_MAX_G_FORCE], then the data is multiplied
   132      by MAX_SINT16 so that it is mapped to the full range of an Sint16.
   133 
   134      You can customize the clamped range of this function by modifying the
   135      SDL_IPHONE_MAX_GFORCE macro in SDL_config_iphoneos.h.
   136 
   137      Once converted to Sint16, the accelerometer data no longer has coherent
   138      units. You can convert the data back to units of g-force by multiplying
   139      it in your application's code by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
   140      */
   141 
   142     /* clamp the data */
   143     accel.x = SDL_min(SDL_max(accel.x, -maxgforce), maxgforce);
   144     accel.y = SDL_min(SDL_max(accel.y, -maxgforce), maxgforce);
   145     accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce);
   146 
   147     /* pass in data mapped to range of SInt16 */
   148     SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
   149     SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
   150     SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
   151 }
   152 
   153 /* Function to update the state of a joystick - called as a device poll.
   154  * This function shouldn't update the joystick structure directly,
   155  * but instead should call SDL_PrivateJoystick*() to deliver events
   156  * and update joystick device state.
   157  */
   158 void
   159 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   160 {
   161     SDL_SYS_AccelerometerUpdate(joystick);
   162 }
   163 
   164 /* Function to close a joystick after use */
   165 void
   166 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   167 {
   168     @autoreleasepool {
   169         [motionManager stopAccelerometerUpdates];
   170     }
   171     joystick->closed = 1;
   172 }
   173 
   174 /* Function to perform any system-specific joystick related cleanup */
   175 void
   176 SDL_SYS_JoystickQuit(void)
   177 {
   178     @autoreleasepool {
   179         if (motionManager != nil) {
   180             [motionManager release];
   181             motionManager = nil;
   182         }
   183     }
   184 
   185     numjoysticks = 0;
   186 }
   187 
   188 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   189 {
   190     SDL_JoystickGUID guid;
   191     /* the GUID is just the first 16 chars of the name for now */
   192     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   193     SDL_zero( guid );
   194     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   195     return guid;
   196 }
   197 
   198 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   199 {
   200     SDL_JoystickGUID guid;
   201     /* the GUID is just the first 16 chars of the name for now */
   202     const char *name = joystick->name;
   203     SDL_zero( guid );
   204     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   205     return guid;
   206 }
   207 
   208 /* vi: set ts=4 sw=4 expandtab: */