1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3  *  Copyright (C) 2011-2017 - Daniel De Matteis
4  *  Copyright (C) 2012-2015 - Michael Lelli
5  *  Copyright (C) 2013-2014 - Steven Crowe
6  *
7  *  RetroArch is free software: you can redistribute it and/or modify it under the terms *  of the GNU General Public License as published by the Free Software Found-
8  *  ation, either version 3 of the License, or (at your option) any later version.
9  *
10  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  *  PURPOSE.  See the GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along with RetroArch.
15  *  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "../../config.def.h"
19 
20 #include "../input_driver.h"
21 #include "../drivers_keyboard/keyboard_event_android.h"
22 
android_joypad_name(unsigned pad)23 static const char *android_joypad_name(unsigned pad)
24 {
25    return input_config_get_device_name(pad);
26 }
27 
android_joypad_init(void * data)28 static void *android_joypad_init(void *data) { return (void*)-1; }
29 
android_joypad_button_state(struct android_app * android_app,uint8_t * buf,unsigned port,uint16_t joykey)30 static int16_t android_joypad_button_state(
31       struct android_app *android_app,
32       uint8_t *buf,
33       unsigned port, uint16_t joykey)
34 {
35    unsigned hat_dir = GET_HAT_DIR(joykey);
36 
37    if (hat_dir)
38    {
39       unsigned h = GET_HAT(joykey);
40       if (h > 0)
41          return 0;
42 
43       switch (hat_dir)
44       {
45          case HAT_LEFT_MASK:
46             return (android_app->hat_state[port][0] == -1);
47          case HAT_RIGHT_MASK:
48             return (android_app->hat_state[port][0] ==  1);
49          case HAT_UP_MASK:
50             return (android_app->hat_state[port][1] == -1);
51          case HAT_DOWN_MASK:
52             return (android_app->hat_state[port][1] ==  1);
53          default:
54             break;
55       }
56       /* hat requested and no hat button down */
57    }
58    else if (joykey < LAST_KEYCODE)
59       return BIT_GET(buf, joykey);
60    return 0;
61 }
62 
android_joypad_button(unsigned port,uint16_t joykey)63 static int16_t android_joypad_button(unsigned port, uint16_t joykey)
64 {
65    struct android_app *android_app = (struct android_app*)g_android;
66    uint8_t *buf                    = android_keyboard_state_get(port);
67 
68    if (port >= DEFAULT_MAX_PADS)
69       return 0;
70 
71    return android_joypad_button_state(android_app, buf, port, joykey);
72 }
73 
android_joypad_axis_state(struct android_app * android_app,unsigned port,uint32_t joyaxis)74 static int16_t android_joypad_axis_state(
75       struct android_app *android_app,
76       unsigned port, uint32_t joyaxis)
77 {
78    if (AXIS_NEG_GET(joyaxis) < MAX_AXIS)
79    {
80       int val = android_app->analog_state[port][AXIS_NEG_GET(joyaxis)];
81       if (val < 0)
82          return val;
83    }
84    else if (AXIS_POS_GET(joyaxis) < MAX_AXIS)
85    {
86       int val = android_app->analog_state[port][AXIS_POS_GET(joyaxis)];
87       if (val > 0)
88          return val;
89    }
90 
91    return 0;
92 }
93 
android_joypad_axis(unsigned port,uint32_t joyaxis)94 static int16_t android_joypad_axis(unsigned port, uint32_t joyaxis)
95 {
96    struct android_app *android_app = (struct android_app*)g_android;
97    return android_joypad_axis_state(android_app, port, joyaxis);
98 }
99 
android_joypad_state(rarch_joypad_info_t * joypad_info,const struct retro_keybind * binds,unsigned port)100 static int16_t android_joypad_state(
101       rarch_joypad_info_t *joypad_info,
102       const struct retro_keybind *binds,
103       unsigned port)
104 {
105    unsigned i;
106    int16_t ret                          = 0;
107    struct android_app *android_app      = (struct android_app*)g_android;
108    uint8_t *buf                         = android_keyboard_state_get(port);
109    uint16_t port_idx                    = joypad_info->joy_idx;
110 
111    if (port_idx >= DEFAULT_MAX_PADS)
112       return 0;
113 
114    for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
115    {
116       /* Auto-binds are per joypad, not per user. */
117       const uint64_t joykey  = (binds[i].joykey != NO_BTN)
118          ? binds[i].joykey  : joypad_info->auto_binds[i].joykey;
119       const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE)
120          ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis;
121       if ((uint16_t)joykey != NO_BTN
122             && android_joypad_button_state(
123                android_app,
124                buf,
125                port_idx, (uint16_t)joykey))
126          ret |= ( 1 << i);
127       else if (joyaxis != AXIS_NONE &&
128             ((float)abs(android_joypad_axis_state(
129                   android_app, port_idx, joyaxis))
130              / 0x8000) > joypad_info->axis_threshold)
131          ret |= (1 << i);
132    }
133 
134    return ret;
135 }
136 
android_joypad_poll(void)137 static void android_joypad_poll(void) { }
138 
android_joypad_query_pad(unsigned pad)139 static bool android_joypad_query_pad(unsigned pad)
140 {
141    return (pad < MAX_USERS);
142 }
143 
android_joypad_destroy(void)144 static void android_joypad_destroy(void)
145 {
146    unsigned i, j;
147    struct android_app *android_app = (struct android_app*)g_android;
148 
149    for (i = 0; i < DEFAULT_MAX_PADS; i++)
150    {
151       for (j = 0; j < 2; j++)
152          android_app->hat_state[i][j]    = 0;
153       for (j = 0; j < MAX_AXIS; j++)
154          android_app->analog_state[i][j] = 0;
155    }
156 
157    for (i = 0; i < MAX_USERS; i++)
158    {
159       android_app->rumble_last_strength_strong[i] = 0;
160       android_app->rumble_last_strength_weak  [i] = 0;
161       android_app->rumble_last_strength       [i] = 0;
162       android_app->id                         [i] = 0;
163    }
164 }
165 
android_input_set_rumble_internal(uint16_t strength,uint16_t * last_strength_strong,uint16_t * last_strength_weak,uint16_t * last_strength,int8_t id,enum retro_rumble_effect effect)166 static void android_input_set_rumble_internal(
167       uint16_t strength,
168       uint16_t *last_strength_strong,
169       uint16_t *last_strength_weak,
170       uint16_t *last_strength,
171       int8_t   id,
172       enum retro_rumble_effect effect
173       )
174 {
175    JNIEnv *env           = (JNIEnv*)jni_thread_getenv();
176    uint16_t new_strength = 0;
177 
178    if (!env)
179       return;
180 
181    if (effect == RETRO_RUMBLE_STRONG)
182    {
183       new_strength          = strength | *last_strength_weak;
184       *last_strength_strong = strength;
185    }
186    else if (effect == RETRO_RUMBLE_WEAK)
187    {
188       new_strength         = strength | *last_strength_strong;
189       *last_strength_weak  = strength;
190    }
191 
192    if (new_strength != *last_strength)
193    {
194       /* trying to send this value as a JNI param without
195        * storing it first was causing 0 to be seen on the other side ?? */
196       int strength_final   = (255.0f / 65535.0f) * (float)new_strength;
197 
198       CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz,
199             g_android->doVibrate, (jint)id, (jint)RETRO_RUMBLE_STRONG, (jint)strength_final, (jint)0);
200 
201       *last_strength = new_strength;
202    }
203 }
204 
android_joypad_rumble(unsigned port,enum retro_rumble_effect type,uint16_t strength)205 static bool android_joypad_rumble(unsigned port,
206       enum retro_rumble_effect type, uint16_t strength)
207 {
208    settings_t *settings            = config_get_ptr();
209    struct android_app *android_app = (struct android_app*)g_android;
210    bool enable_device_vibration    = settings->bools.enable_device_vibration;
211 
212    if (!android_app || !android_app->doVibrate)
213       return false;
214 
215    if (enable_device_vibration)
216    {
217       static uint16_t last_strength_strong = 0;
218       static uint16_t last_strength_weak   = 0;
219       static uint16_t last_strength        = 0;
220 
221       if (port != 0)
222          return false;
223 
224       android_input_set_rumble_internal(
225             strength,
226             &last_strength_strong,
227             &last_strength_weak,
228             &last_strength,
229             -1,
230             type);
231    }
232    else
233    {
234       android_input_set_rumble_internal(
235             strength,
236             &android_app->rumble_last_strength_strong[port],
237             &android_app->rumble_last_strength_weak[port],
238             &android_app->rumble_last_strength[port],
239             android_app->id[port],
240             type);
241    }
242 
243    return true;
244 }
245 
246 input_device_driver_t android_joypad = {
247    android_joypad_init,
248    android_joypad_query_pad,
249    android_joypad_destroy,
250    android_joypad_button,
251    android_joypad_state,
252    NULL,
253    android_joypad_axis,
254    android_joypad_poll,
255    android_joypad_rumble,
256    android_joypad_name,
257    "android",
258 };
259