1 #include "allegro5/allegro.h"
2 #include "allegro5/internal/aintern.h"
3 #include "allegro5/internal/aintern_events.h"
4 #include "allegro5/internal/aintern_joystick.h"
5 #include "allegro5/internal/aintern_android.h"
6 
7 ALLEGRO_DEBUG_CHANNEL("android")
8 
9 typedef struct ALLEGRO_JOYSTICK_ANDROID {
10    ALLEGRO_JOYSTICK parent;
11    ALLEGRO_JOYSTICK_STATE joystate;
12    const char *name;
13 } ALLEGRO_JOYSTICK_ANDROID;
14 
15 static _AL_VECTOR joysticks = _AL_VECTOR_INITIALIZER(ALLEGRO_JOYSTICK_ANDROID *);
16 static bool initialized;
17 
android_init_joysticks(int num)18 static void android_init_joysticks(int num)
19 {
20     int i, j;
21 
22     for (i = 0; i < num; i++) {
23        ALLEGRO_JOYSTICK_ANDROID *stick = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_ANDROID));
24        ALLEGRO_JOYSTICK_ANDROID **ptr;
25        ALLEGRO_JOYSTICK *joy;
26 
27        joy = (void *)stick;
28        stick->name = "Android Joystick";
29 
30        /* Fill in the joystick information fields. */
31        joy->info.num_sticks = 2;
32        joy->info.num_buttons = 11;
33        joy->info.stick[0].name = "Stick 1";
34        joy->info.stick[0].num_axes = 2;
35        joy->info.stick[0].axis[0].name = "X";
36        joy->info.stick[0].axis[1].name = "Y";
37        joy->info.stick[0].flags = ALLEGRO_JOYFLAG_ANALOGUE;
38        joy->info.stick[1].name = "Stick 2";
39        joy->info.stick[1].num_axes = 2;
40        joy->info.stick[1].axis[0].name = "X";
41        joy->info.stick[1].axis[1].name = "Y";
42        joy->info.stick[1].flags = ALLEGRO_JOYFLAG_ANALOGUE;
43 
44        for (j = 0; j < joy->info.num_buttons; j++) {
45            joy->info.button[j].name = "";
46        }
47 
48        ptr = _al_vector_alloc_back(&joysticks);
49        *ptr = stick;
50     }
51 }
52 
andjoy_init_joystick(void)53 static bool andjoy_init_joystick(void)
54 {
55     ALLEGRO_JOYSTICK_ANDROID *accel = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_ANDROID));
56     ALLEGRO_JOYSTICK_ANDROID **ptr;
57     ALLEGRO_JOYSTICK *joy;
58     int num;
59 
60     accel->name = "Accelerometer";
61 
62     joy = (void *)accel;
63 
64     /* Fill in the joystick information fields. */
65     joy->info.num_sticks = 1;
66     joy->info.num_buttons = 0;
67     joy->info.stick[0].name = "Accelerometer";
68     joy->info.stick[0].num_axes = 3;
69     joy->info.stick[0].axis[0].name = "X";
70     joy->info.stick[0].axis[1].name = "Y";
71     joy->info.stick[0].axis[2].name = "Z";
72     joy->info.stick[0].flags = ALLEGRO_JOYFLAG_ANALOGUE;
73 
74     ptr = _al_vector_alloc_back(&joysticks);
75     *ptr = accel;
76 
77     num = _jni_callIntMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "getNumJoysticks", "()I");
78 
79     android_init_joysticks(num);
80 
81     initialized = true;
82 
83     _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "setJoystickActive");
84 
85     return true;
86 }
87 
andjoy_exit_joystick(void)88 static void andjoy_exit_joystick(void)
89 {
90     initialized = false;
91 }
92 
andjoy_reconfigure_joysticks(void)93 static bool andjoy_reconfigure_joysticks(void)
94 {
95     int i;
96     int sz;
97     int num;
98 
99     sz = _al_vector_size(&joysticks);
100 
101     for (i = 1; i < sz; i++) {
102         al_free(*((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 1)));
103         _al_vector_delete_at(&joysticks, 1);
104     }
105 
106     _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "reconfigureJoysticks");
107 
108     num = _jni_callIntMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "getNumJoysticks", "()I");
109 
110     android_init_joysticks(num);
111 
112     return true;
113 }
114 
andjoy_num_joysticks(void)115 static int andjoy_num_joysticks(void)
116 {
117     return _al_vector_size(&joysticks);
118 }
119 
andjoy_get_joystick(int num)120 static ALLEGRO_JOYSTICK *andjoy_get_joystick(int num)
121 {
122     ALLEGRO_JOYSTICK_ANDROID *andjoy;
123     ALLEGRO_JOYSTICK *joy;
124 
125     if (num >= andjoy_num_joysticks())
126        return NULL;
127 
128     andjoy = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, num));
129     joy = &andjoy->parent;
130 
131     return joy;
132 }
133 
andjoy_release_joystick(ALLEGRO_JOYSTICK * joy)134 static void andjoy_release_joystick(ALLEGRO_JOYSTICK *joy)
135 {
136     int i;
137     int sz;
138     (void)joy;
139 
140     sz = _al_vector_size(&joysticks);
141 
142     for (i = 0; i < sz; i++) {
143         al_free(*((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 0)));
144         _al_vector_delete_at(&joysticks, 0);
145     }
146 
147     _jni_callVoidMethod(_al_android_get_jnienv(), _al_android_activity_object(), "setJoystickInactive");
148 
149     ALLEGRO_DEBUG("Joystick released.\n");
150     initialized = false;
151 }
152 
andjoy_get_joystick_state(ALLEGRO_JOYSTICK * joy,ALLEGRO_JOYSTICK_STATE * ret_state)153 static void andjoy_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state)
154 {
155     ALLEGRO_JOYSTICK_ANDROID *andjoy = (void *)joy;
156     ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source();
157     int i;
158     bool found = false;
159 
160     for (i = 0; i < (int)_al_vector_size(&joysticks); i++) {
161         ALLEGRO_JOYSTICK_ANDROID **ptr = _al_vector_ref(&joysticks, i);
162         ALLEGRO_JOYSTICK_ANDROID *thisjoy = *ptr;
163         if (andjoy == thisjoy) {
164             found = true;
165             break;
166         }
167     }
168 
169     if (!found) {
170         memset(ret_state, 0, sizeof(*ret_state));
171         return;
172     }
173 
174     _al_event_source_lock(es);
175     *ret_state = andjoy->joystate;
176     _al_event_source_unlock(es);
177 }
178 
_al_android_generate_accelerometer_event(float x,float y,float z)179 void _al_android_generate_accelerometer_event(float x, float y, float z)
180 {
181     if (!initialized)
182        return;
183 
184     /* Android reports accelerometer data in the approximate range
185      * -9.81 -> 9.81, but can be higher or lower. Allegro joysticks
186      * use -1 -> 1. Also, the axis' are all reversed on Android,
187      * hence the negative division.
188      */
189     x /= -9.81f;
190     if (x < -1) x = -1;
191     if (x > 1) x = 1;
192     y /= -9.81f;
193     if (y < -1) y = -1;
194     if (y > 1) y = 1;
195     z /= -9.81f;
196     if (z < -1) z = -1;
197     if (z > 1) z = 1;
198 
199     ALLEGRO_JOYSTICK_ANDROID *accel = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, 0));
200     ALLEGRO_JOYSTICK *joy = &accel->parent;
201 
202     ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source();
203 
204     ALLEGRO_EVENT event;
205 
206     _al_event_source_lock(es);
207 
208     if (_al_event_source_needs_to_generate_event(es)) {
209         float pos[] = {x, y, z};
210         int i;
211         for (i = 0; i < 3; i++) {
212             event.joystick.id = joy;
213             event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS;
214             event.joystick.timestamp = al_get_time();
215             event.joystick.stick = 0;
216             event.joystick.axis = i;
217             event.joystick.pos = pos[i];
218             event.joystick.button = 0;
219 
220             accel->joystate.stick[0].axis[i] = pos[i];
221 
222             _al_event_source_emit_event(es, &event);
223         }
224     }
225 
226     _al_event_source_unlock(es);
227 }
228 
_al_android_generate_joystick_axis_event(int index,int stick,int axis,float value)229 void _al_android_generate_joystick_axis_event(int index, int stick, int axis, float value)
230 {
231     if (!initialized || index >= andjoy_num_joysticks())
232         return;
233 
234     ALLEGRO_JOYSTICK_ANDROID *joystick = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, index));
235     ALLEGRO_JOYSTICK *joy = &joystick->parent;
236 
237     ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source();
238 
239     ALLEGRO_EVENT event;
240 
241     _al_event_source_lock(es);
242 
243     if (_al_event_source_needs_to_generate_event(es)) {
244         event.joystick.id = joy;
245         event.joystick.type = ALLEGRO_EVENT_JOYSTICK_AXIS;
246         event.joystick.timestamp = al_get_time();
247         event.joystick.stick = stick;
248         event.joystick.axis = axis;
249         event.joystick.pos = value;
250         event.joystick.button = 0;
251 
252         joystick->joystate.stick[stick].axis[axis] = value;
253 
254         _al_event_source_emit_event(es, &event);
255     }
256     _al_event_source_unlock(es);
257 }
258 
_al_android_generate_joystick_button_event(int index,int button,bool down)259 void _al_android_generate_joystick_button_event(int index, int button, bool down)
260 {
261     int type;
262 
263     if (!initialized || index >= andjoy_num_joysticks())
264         return;
265 
266     ALLEGRO_JOYSTICK_ANDROID *joystick = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, index));
267     ALLEGRO_JOYSTICK *joy = &joystick->parent;
268 
269     ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source();
270 
271     ALLEGRO_EVENT event;
272 
273     _al_event_source_lock(es);
274 
275     if (down)
276         type = ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN;
277     else
278         type = ALLEGRO_EVENT_JOYSTICK_BUTTON_UP;
279 
280     if (_al_event_source_needs_to_generate_event(es)) {
281         event.joystick.id = joy;
282         event.joystick.type = type;
283         event.joystick.timestamp = al_get_time();
284         event.joystick.stick = 0;
285         event.joystick.axis = 0;
286         event.joystick.pos = 0;
287         event.joystick.button = button;
288 
289         joystick->joystate.button[button] = type == ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN ? 1 : 0;
290 
291         _al_event_source_emit_event(es, &event);
292     }
293     _al_event_source_unlock(es);
294 }
295 
andjoy_get_name(ALLEGRO_JOYSTICK * joy)296 static char const *andjoy_get_name(ALLEGRO_JOYSTICK *joy)
297 {
298     int i;
299     (void)joy;
300 
301     for (i = 0; i < (int)_al_vector_size(&joysticks); i++) {
302         ALLEGRO_JOYSTICK_ANDROID *andjoy = *((ALLEGRO_JOYSTICK_ANDROID **)_al_vector_ref(&joysticks, i));
303         if ((ALLEGRO_JOYSTICK *)andjoy == joy)
304             return andjoy->name;
305     }
306 
307     return "";
308 }
309 
andjoy_get_active(ALLEGRO_JOYSTICK * joy)310 static bool andjoy_get_active(ALLEGRO_JOYSTICK *joy)
311 {
312     (void)joy;
313     return true;
314 }
315 
316 ALLEGRO_JOYSTICK_DRIVER _al_android_joystick_driver = {
317    AL_ID('A', 'N', 'D', 'R'),
318    "",
319    "",
320    "android joystick",
321     andjoy_init_joystick,
322     andjoy_exit_joystick,
323     andjoy_reconfigure_joysticks,
324     andjoy_num_joysticks,
325     andjoy_get_joystick,
326     andjoy_release_joystick,
327     andjoy_get_joystick_state,
328     andjoy_get_name,
329     andjoy_get_active
330 };
331