src/joystick/iphoneos/SDL_sysjoystick.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 25 Jun 2014 00:20:21 -0700
changeset 8921 4a9feef61c85
parent 8860 c4133d635375
child 9311 a4b031e28de8
child 9489 6cd0275146b3
permissions -rw-r--r--
Fixed bug 2603 - iOS: update joystick accelerometer code to use CoreMotion instead of the deprecated UIAccelerometer

Alex Szpakowski

SDL's code for exposing the accelerometer as a joystick on iOS currently uses UIAccelerometer, which was superseded by the CoreMotion framework and deprecated since iOS 5.

The UIAccelerometer code still works (for now), but it also throws deprecation warnings whenever SDL is built for iOS, since SDL's deployment target is no longer below iOS 5.

I've created a patch which replaces the old UIAccelerometer code with a replacement based on the CoreMotion framework. It has identical functionality (to SDL users), however iOS apps are now required to link to the CoreMotion framework when using SDL.
slouken@2765
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@2765
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@2765
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@2765
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@2765
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@2765
    22
philipp@8138
    23
/* This is the iOS implementation of the SDL joystick API */
slouken@2765
    24
slouken@2765
    25
#include "SDL_joystick.h"
slouken@8921
    26
#include "SDL_stdinc.h"
slouken@2765
    27
#include "../SDL_sysjoystick.h"
slouken@2765
    28
#include "../SDL_joystick_c.h"
slouken@2765
    29
slouken@8921
    30
#import <CoreMotion/CoreMotion.h>
slouken@8921
    31
slouken@8921
    32
/* needed for SDL_IPHONE_MAX_GFORCE macro */
slouken@8921
    33
#import "SDL_config_iphoneos.h"
slouken@8921
    34
slouken@8921
    35
const char *accelerometerName = "iOS accelerometer";
slouken@8921
    36
slouken@8921
    37
static CMMotionManager *motionManager = nil;
slouken@2765
    38
slouken@2765
    39
/* Function to scan the system for joysticks.
slouken@2765
    40
 * This function should set SDL_numjoysticks to the number of available
slouken@2765
    41
 * joysticks.  Joystick 0 should be the system default joystick.
slouken@2765
    42
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@2765
    43
 */
slouken@2765
    44
int
slouken@2765
    45
SDL_SYS_JoystickInit(void)
slouken@2765
    46
{
slouken@2765
    47
    return (1);
slouken@2765
    48
}
slouken@2765
    49
slouken@6707
    50
int SDL_SYS_NumJoysticks()
slouken@6707
    51
{
slouken@6707
    52
    return 1;
slouken@6707
    53
}
slouken@6707
    54
slouken@6707
    55
void SDL_SYS_JoystickDetect()
slouken@6707
    56
{
slouken@6707
    57
}
slouken@6707
    58
slouken@2765
    59
/* Function to get the device-dependent name of a joystick */
slouken@2765
    60
const char *
slouken@6707
    61
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@2765
    62
{
slouken@6707
    63
    return accelerometerName;
slouken@6707
    64
}
slouken@6707
    65
slouken@6707
    66
/* Function to perform the mapping from device index to the instance id for this index */
slouken@6707
    67
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
    68
{
slouken@6707
    69
    return device_index;
slouken@2765
    70
}
slouken@2765
    71
slouken@2765
    72
/* Function to open a joystick for use.
slouken@2765
    73
   The joystick to open is specified by the index field of the joystick.
slouken@2765
    74
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@2765
    75
   It returns 0, or -1 if there is an error.
slouken@2765
    76
 */
slouken@2765
    77
int
slouken@6693
    78
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@2765
    79
{
slouken@6707
    80
    joystick->naxes = 3;
slouken@6707
    81
    joystick->nhats = 0;
slouken@6707
    82
    joystick->nballs = 0;
slouken@6707
    83
    joystick->nbuttons = 0;
slouken@8921
    84
slouken@8921
    85
    if (motionManager == nil) {
slouken@8921
    86
        motionManager = [[CMMotionManager alloc] init];
slouken@8921
    87
    }
slouken@8921
    88
slouken@8921
    89
    /* Shorter times between updates can significantly increase CPU usage. */
slouken@8921
    90
    motionManager.accelerometerUpdateInterval = 0.1;
slouken@8921
    91
    [motionManager startAccelerometerUpdates];
slouken@8921
    92
slouken@6707
    93
    return 0;
slouken@6707
    94
}
slouken@6707
    95
slouken@6707
    96
/* Function to determine is this joystick is attached to the system right now */
slouken@6707
    97
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
slouken@6707
    98
{
slouken@6707
    99
    return SDL_TRUE;
slouken@2765
   100
}
slouken@2765
   101
slouken@8921
   102
static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
slouken@8921
   103
{
slouken@8921
   104
    const float maxgforce = SDL_IPHONE_MAX_GFORCE;
slouken@8921
   105
    const SInt16 maxsint16 = 0x7FFF;
slouken@8921
   106
    CMAcceleration accel;
slouken@8921
   107
slouken@8921
   108
    if (!motionManager.accelerometerActive) {
slouken@8921
   109
        return;
slouken@8921
   110
    }
slouken@8921
   111
slouken@8921
   112
    accel = [[motionManager accelerometerData] acceleration];
slouken@8921
   113
slouken@8921
   114
    /*
slouken@8921
   115
     Convert accelerometer data from floating point to Sint16, which is what
slouken@8921
   116
     the joystick system expects.
slouken@8921
   117
slouken@8921
   118
     To do the conversion, the data is first clamped onto the interval
slouken@8921
   119
     [-SDL_IPHONE_MAX_G_FORCE, SDL_IPHONE_MAX_G_FORCE], then the data is multiplied
slouken@8921
   120
     by MAX_SINT16 so that it is mapped to the full range of an Sint16.
slouken@8921
   121
slouken@8921
   122
     You can customize the clamped range of this function by modifying the
slouken@8921
   123
     SDL_IPHONE_MAX_GFORCE macro in SDL_config_iphoneos.h.
slouken@8921
   124
slouken@8921
   125
     Once converted to Sint16, the accelerometer data no longer has coherent
slouken@8921
   126
     units. You can convert the data back to units of g-force by multiplying
slouken@8921
   127
     it in your application's code by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
slouken@8921
   128
     */
slouken@8921
   129
slouken@8921
   130
    /* clamp the data */
slouken@8921
   131
    accel.x = SDL_min(SDL_max(accel.x, -maxgforce), maxgforce);
slouken@8921
   132
    accel.y = SDL_min(SDL_max(accel.y, -maxgforce), maxgforce);
slouken@8921
   133
    accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce);
slouken@8921
   134
slouken@8921
   135
    /* pass in data mapped to range of SInt16 */
slouken@8921
   136
    SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
slouken@8921
   137
    SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
slouken@8921
   138
    SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
slouken@8921
   139
}
slouken@8921
   140
slouken@2765
   141
/* Function to update the state of a joystick - called as a device poll.
slouken@2765
   142
 * This function shouldn't update the joystick structure directly,
slouken@2765
   143
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@2765
   144
 * and update joystick device state.
slouken@2765
   145
 */
slouken@2765
   146
void
slouken@2765
   147
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@2765
   148
{
slouken@8921
   149
    SDL_SYS_AccelerometerUpdate(joystick);
slouken@2765
   150
}
slouken@2765
   151
slouken@2765
   152
/* Function to close a joystick after use */
slouken@2765
   153
void
slouken@2765
   154
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@2765
   155
{
slouken@8921
   156
    [motionManager stopAccelerometerUpdates];
slouken@8921
   157
    joystick->closed = 1;
slouken@2765
   158
}
slouken@2765
   159
slouken@2765
   160
/* Function to perform any system-specific joystick related cleanup */
slouken@2765
   161
void
slouken@2765
   162
SDL_SYS_JoystickQuit(void)
slouken@2765
   163
{
slouken@8921
   164
    if (motionManager != nil) {
slouken@8921
   165
        [motionManager release];
slouken@8921
   166
        motionManager = nil;
slouken@8921
   167
    }
slouken@2765
   168
}
slouken@6693
   169
slouken@6744
   170
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6693
   171
{
slouken@6744
   172
    SDL_JoystickGUID guid;
slouken@7191
   173
    /* the GUID is just the first 16 chars of the name for now */
slouken@6707
   174
    const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
slouken@6693
   175
    SDL_zero( guid );
slouken@6693
   176
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6693
   177
    return guid;
slouken@6693
   178
}
slouken@6693
   179
slouken@6744
   180
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6693
   181
{
slouken@6744
   182
    SDL_JoystickGUID guid;
slouken@7191
   183
    /* the GUID is just the first 16 chars of the name for now */
slouken@6693
   184
    const char *name = joystick->name;
slouken@6693
   185
    SDL_zero( guid );
slouken@6693
   186
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6693
   187
    return guid;
slouken@6693
   188
}
slouken@6693
   189
slouken@2765
   190
/* vi: set ts=4 sw=4 expandtab: */