1/*
2  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
3
4  This software is provided 'as-is', without any express or implied
5  warranty.  In no event will the authors be held liable for any damages
6  arising from the use of this software.
7
8  Permission is granted to anyone to use this software for any purpose,
9  including commercial applications, and to alter it and redistribute it
10  freely.
11*/
12
13/* Simple program to test the SDL joystick routines */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include "SDL.h"
20
21#ifndef SDL_JOYSTICK_DISABLED
22
23#ifdef __IPHONEOS__
24#define SCREEN_WIDTH    320
25#define SCREEN_HEIGHT   480
26#else
27#define SCREEN_WIDTH    640
28#define SCREEN_HEIGHT   480
29#endif
30
31
32static void
33DrawRect(SDL_Renderer *r, const int x, const int y, const int w, const int h)
34{
35    const SDL_Rect area = { x, y, w, h };
36    SDL_RenderFillRect(r, &area);
37}
38
39static SDL_bool
40WatchJoystick(SDL_Joystick * joystick)
41{
42    SDL_Window *window = NULL;
43    SDL_Renderer *screen = NULL;
44    const char *name = NULL;
45    SDL_bool retval = SDL_FALSE;
46    SDL_bool done = SDL_FALSE;
47    SDL_Event event;
48    int i;
49
50    /* Create a window to display joystick axis position */
51    window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED,
52                              SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
53                              SCREEN_HEIGHT, 0);
54    if (window == NULL) {
55        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
56        return SDL_FALSE;
57    }
58
59    screen = SDL_CreateRenderer(window, -1, 0);
60    if (screen == NULL) {
61        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
62        SDL_DestroyWindow(window);
63        return SDL_FALSE;
64    }
65
66    SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
67    SDL_RenderClear(screen);
68    SDL_RenderPresent(screen);
69    SDL_RaiseWindow(window);
70
71    /* Print info about the joystick we are watching */
72    name = SDL_JoystickName(joystick);
73    SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
74           name ? name : "Unknown Joystick");
75    SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
76           SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
77           SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
78
79    /* Loop, getting joystick events! */
80    while (!done) {
81        /* blank screen, set up for drawing this frame. */
82        SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
83        SDL_RenderClear(screen);
84
85        while (SDL_PollEvent(&event)) {
86            switch (event.type) {
87            case SDL_JOYAXISMOTION:
88                SDL_Log("Joystick %d axis %d value: %d\n",
89                       event.jaxis.which,
90                       event.jaxis.axis, event.jaxis.value);
91                break;
92            case SDL_JOYHATMOTION:
93                SDL_Log("Joystick %d hat %d value:",
94                       event.jhat.which, event.jhat.hat);
95                if (event.jhat.value == SDL_HAT_CENTERED)
96                    SDL_Log(" centered");
97                if (event.jhat.value & SDL_HAT_UP)
98                    SDL_Log(" up");
99                if (event.jhat.value & SDL_HAT_RIGHT)
100                    SDL_Log(" right");
101                if (event.jhat.value & SDL_HAT_DOWN)
102                    SDL_Log(" down");
103                if (event.jhat.value & SDL_HAT_LEFT)
104                    SDL_Log(" left");
105                SDL_Log("\n");
106                break;
107            case SDL_JOYBALLMOTION:
108                SDL_Log("Joystick %d ball %d delta: (%d,%d)\n",
109                       event.jball.which,
110                       event.jball.ball, event.jball.xrel, event.jball.yrel);
111                break;
112            case SDL_JOYBUTTONDOWN:
113                SDL_Log("Joystick %d button %d down\n",
114                       event.jbutton.which, event.jbutton.button);
115                break;
116            case SDL_JOYBUTTONUP:
117                SDL_Log("Joystick %d button %d up\n",
118                       event.jbutton.which, event.jbutton.button);
119                break;
120            case SDL_KEYDOWN:
121                if ((event.key.keysym.sym != SDLK_ESCAPE) &&
122                    (event.key.keysym.sym != SDLK_AC_BACK)) {
123                    break;
124                }
125                /* Fall through to signal quit */
126            case SDL_FINGERDOWN:
127            case SDL_MOUSEBUTTONDOWN:
128            case SDL_QUIT:
129                done = SDL_TRUE;
130                break;
131            default:
132                break;
133            }
134        }
135        /* Update visual joystick state */
136        SDL_SetRenderDrawColor(screen, 0x00, 0xFF, 0x00, SDL_ALPHA_OPAQUE);
137        for (i = 0; i < SDL_JoystickNumButtons(joystick); ++i) {
138            if (SDL_JoystickGetButton(joystick, i) == SDL_PRESSED) {
139                DrawRect(screen, (i%20) * 34, SCREEN_HEIGHT - 68 + (i/20) * 34, 32, 32);
140            }
141        }
142
143        SDL_SetRenderDrawColor(screen, 0xFF, 0x00, 0x00, SDL_ALPHA_OPAQUE);
144        for (i = 0; i < SDL_JoystickNumAxes(joystick); ++i) {
145            /* Draw the X/Y axis */
146            int x, y;
147            x = (((int) SDL_JoystickGetAxis(joystick, i)) + 32768);
148            x *= SCREEN_WIDTH;
149            x /= 65535;
150            if (x < 0) {
151                x = 0;
152            } else if (x > (SCREEN_WIDTH - 16)) {
153                x = SCREEN_WIDTH - 16;
154            }
155            ++i;
156            if (i < SDL_JoystickNumAxes(joystick)) {
157                y = (((int) SDL_JoystickGetAxis(joystick, i)) + 32768);
158            } else {
159                y = 32768;
160            }
161            y *= SCREEN_HEIGHT;
162            y /= 65535;
163            if (y < 0) {
164                y = 0;
165            } else if (y > (SCREEN_HEIGHT - 16)) {
166                y = SCREEN_HEIGHT - 16;
167            }
168
169            DrawRect(screen, x, y, 16, 16);
170        }
171
172        SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0xFF, SDL_ALPHA_OPAQUE);
173        for (i = 0; i < SDL_JoystickNumHats(joystick); ++i) {
174            /* Derive the new position */
175            int x = SCREEN_WIDTH/2;
176            int y = SCREEN_HEIGHT/2;
177            const Uint8 hat_pos = SDL_JoystickGetHat(joystick, i);
178
179            if (hat_pos & SDL_HAT_UP) {
180                y = 0;
181            } else if (hat_pos & SDL_HAT_DOWN) {
182                y = SCREEN_HEIGHT-8;
183            }
184
185            if (hat_pos & SDL_HAT_LEFT) {
186                x = 0;
187            } else if (hat_pos & SDL_HAT_RIGHT) {
188                x = SCREEN_WIDTH-8;
189            }
190
191            DrawRect(screen, x, y, 8, 8);
192        }
193
194        SDL_RenderPresent(screen);
195
196        if (SDL_JoystickGetAttached( joystick ) == 0) {
197            done = SDL_TRUE;
198            retval = SDL_TRUE;  /* keep going, wait for reattach. */
199        }
200    }
201
202    SDL_DestroyRenderer(screen);
203    SDL_DestroyWindow(window);
204    return retval;
205}
206
207int
208main(int argc, char *argv[])
209{
210    const char *name;
211    int i;
212    SDL_Joystick *joystick;
213
214    /* Enable standard application logging */
215    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
216
217    /* Initialize SDL (Note: video is required to start event loop) */
218    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
219        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
220        exit(1);
221    }
222
223    /* Print information about the joysticks */
224    SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
225    for (i = 0; i < SDL_NumJoysticks(); ++i) {
226        name = SDL_JoystickNameForIndex(i);
227        SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
228        joystick = SDL_JoystickOpen(i);
229        if (joystick == NULL) {
230            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
231                    SDL_GetError());
232        } else {
233            char guid[64];
234            SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
235                                      guid, sizeof (guid));
236            SDL_Log("       axes: %d\n", SDL_JoystickNumAxes(joystick));
237            SDL_Log("      balls: %d\n", SDL_JoystickNumBalls(joystick));
238            SDL_Log("       hats: %d\n", SDL_JoystickNumHats(joystick));
239            SDL_Log("    buttons: %d\n", SDL_JoystickNumButtons(joystick));
240            SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
241            SDL_Log("       guid: %s\n", guid);
242            SDL_JoystickClose(joystick);
243        }
244    }
245
246#ifdef ANDROID
247    if (SDL_NumJoysticks() > 0) {
248#else
249    if (argv[1]) {
250#endif
251        SDL_bool reportederror = SDL_FALSE;
252        SDL_bool keepGoing = SDL_TRUE;
253        SDL_Event event;
254        int device;
255#ifdef ANDROID
256        device = 0;
257#else
258        device = atoi(argv[1]);
259#endif
260        joystick = SDL_JoystickOpen(device);
261
262        while ( keepGoing ) {
263            if (joystick == NULL) {
264                if ( !reportederror ) {
265                    SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
266                    keepGoing = SDL_FALSE;
267                    reportederror = SDL_TRUE;
268                }
269            } else {
270                reportederror = SDL_FALSE;
271                keepGoing = WatchJoystick(joystick);
272                SDL_JoystickClose(joystick);
273            }
274
275            joystick = NULL;
276            if (keepGoing) {
277                SDL_Log("Waiting for attach\n");
278            }
279            while (keepGoing) {
280                SDL_WaitEvent(&event);
281                if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN)
282                    || (event.type == SDL_MOUSEBUTTONDOWN)) {
283                    keepGoing = SDL_FALSE;
284                } else if (event.type == SDL_JOYDEVICEADDED) {
285                    joystick = SDL_JoystickOpen(device);
286                    break;
287                }
288            }
289        }
290    }
291    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
292
293    return 0;
294}
295
296#else
297
298int
299main(int argc, char *argv[])
300{
301    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
302    exit(1);
303}
304
305#endif
306