1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include <jni.h>
23 #include <android/log.h>
24 #include <sys/time.h>
25 #include <time.h>
26 #include <stdint.h>
27 #include <math.h>
28 #include <string.h> // for memset()
29 #include <GLES/gl.h>
30 #include <GLES/glext.h>
31 #include <netinet/in.h>
32
33 #include "SDL_config.h"
34
35 #include "SDL_version.h"
36
37 //#include "SDL_opengles.h"
38 #include "SDL_screenkeyboard.h"
39 #include "../SDL_sysvideo.h"
40 #include "SDL_androidvideo.h"
41 #include "SDL_androidinput.h"
42 #include "jniwrapperstuff.h"
43
44 // #include "touchscreentheme.h" // Not used yet
45
46 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
47 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
48
49 enum { MAX_BUTTONS = SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM-1, MAX_BUTTONS_AUTOFIRE = 2, BUTTON_TEXT_INPUT = SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT-1 } ; // Max amount of custom buttons
50
51 int SDL_ANDROID_isTouchscreenKeyboardUsed = 0;
52 static int touchscreenKeyboardTheme = 0;
53 static int touchscreenKeyboardShown = 1;
54 static int AutoFireButtonsNum = 0;
55 static int buttonsize = 1;
56 static int transparency = 128;
57
58 static SDL_Rect arrows, buttons[MAX_BUTTONS], buttonsAutoFireRect[MAX_BUTTONS_AUTOFIRE];
59 static SDLKey buttonKeysyms[MAX_BUTTONS] = {
60 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_0)),
61 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_1)),
62 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_2)),
63 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_3)),
64 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_4)),
65 SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_5)),
66 0
67 };
68
69 enum { ARROW_LEFT = 1, ARROW_RIGHT = 2, ARROW_UP = 4, ARROW_DOWN = 8 };
70 static int oldArrows = 0;
71 static int ButtonAutoFire[MAX_BUTTONS_AUTOFIRE] = {0, 0};
72 static int ButtonAutoFireX[MAX_BUTTONS_AUTOFIRE*2] = {0, 0, 0, 0};
73 static int ButtonAutoFireRot[MAX_BUTTONS_AUTOFIRE] = {0, 0};
74 static int ButtonAutoFireDecay[MAX_BUTTONS_AUTOFIRE] = {0, 0};
75
76 static int pointerInButtonRect[MAX_BUTTONS + 1] = {0};
77
78 typedef struct
79 {
80 GLuint id;
81 GLfloat w;
82 GLfloat h;
83 } GLTexture_t;
84
85 static GLTexture_t arrowImages[5] = { {0, 0, 0}, };
86 static GLTexture_t buttonAutoFireImages[MAX_BUTTONS_AUTOFIRE*2] = { {0, 0, 0}, };
87 static GLTexture_t buttonImages[MAX_BUTTONS*2] = { {0, 0, 0}, };
88
89
InsideRect(const SDL_Rect * r,int x,int y)90 static inline int InsideRect(const SDL_Rect * r, int x, int y)
91 {
92 return ( x >= r->x && x <= r->x + r->w ) && ( y >= r->y && y <= r->y + r->h );
93 }
94
95 static struct ScreenKbGlState_t
96 {
97 GLboolean texture2d;
98 GLuint textureId;
99 GLfloat color[4];
100 GLfloat texEnvMode;
101 GLboolean blend;
102 GLenum blend1, blend2;
103 GLint texFilter1, texFilter2;
104 }
105 oldGlState;
106
beginDrawingTex()107 static inline void beginDrawingTex()
108 {
109 // Save OpenGL state
110 // TODO: this code does not work on 1.6 emulator, and on some devices
111 /*
112 oldGlState.texture2d = glIsEnabled(GL_TEXTURE_2D);
113 glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldGlState.textureId);
114 glGetFloatv(GL_CURRENT_COLOR, &(oldGlState.color[0]));
115 glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &oldGlState.texEnvMode);
116 oldGlState.blend = glIsEnabled(GL_BLEND);
117 glGetIntegerv(GL_BLEND_SRC, &oldGlState.blend1);
118 glGetIntegerv(GL_BLEND_DST, &oldGlState.blend2);
119 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &oldGlState.texFilter1);
120 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &oldGlState.texFilter2);
121 // It's very unlikely that some app will use GL_TEXTURE_CROP_RECT_OES, so just skip it
122 */
123
124 glEnable(GL_TEXTURE_2D);
125 }
126
endDrawingTex()127 static inline void endDrawingTex()
128 {
129 /*
130 // Restore OpenGL state
131 if( oldGlState.texture2d == GL_FALSE)
132 glDisable(GL_TEXTURE_2D);
133 glBindTexture(GL_TEXTURE_2D, oldGlState.textureId);
134 glColor4f(oldGlState.color[0], oldGlState.color[1], oldGlState.color[2], oldGlState.color[3]);
135 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, oldGlState.texEnvMode);
136 if( oldGlState.blend == GL_FALSE)
137 glDisable(GL_BLEND);
138 glBlendFunc(oldGlState.blend1, oldGlState.blend2);
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, oldGlState.texFilter1);
140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, oldGlState.texFilter2);
141 */
142 }
143
drawCharTex(GLTexture_t * tex,SDL_Rect * src,SDL_Rect * dest,Uint8 r,Uint8 g,Uint8 b,Uint8 a)144 static inline void drawCharTex(GLTexture_t * tex, SDL_Rect * src, SDL_Rect * dest, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
145 {
146 GLint cropRect[4];
147
148 if( !dest->h || !dest->w )
149 return;
150
151 glBindTexture(GL_TEXTURE_2D, tex->id);
152
153 glColor4x(r * 0x100, g * 0x100, b * 0x100, a * 0x100 );
154
155 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
156 glEnable(GL_BLEND);
157 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
158
159 if( SDL_ANDROID_SmoothVideo )
160 {
161 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
163 }
164 else
165 {
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
168 }
169
170 cropRect[0] = 0;
171 cropRect[1] = tex->h;
172 cropRect[2] = tex->w;
173 cropRect[3] = -tex->h;
174 if(src)
175 {
176 cropRect[0] = src->x;
177 cropRect[1] = src->h;
178 cropRect[2] = src->w;
179 cropRect[3] = -src->h;
180 }
181 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
182 glDrawTexiOES(dest->x, SDL_ANDROID_sWindowHeight - dest->y - dest->h, 0, dest->w, dest->h);
183 }
184
SDL_ANDROID_drawTouchscreenKeyboard()185 int SDL_ANDROID_drawTouchscreenKeyboard()
186 {
187 int i;
188 int blendFactor;
189
190 if( !SDL_ANDROID_isTouchscreenKeyboardUsed || !touchscreenKeyboardShown )
191 return 0;
192
193 blendFactor = ( SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] ? 1 : 0 ) +
194 ( SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] ? 1 : 0 ) +
195 ( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] ? 1 : 0 ) +
196 ( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] ? 1 : 0 );
197
198 beginDrawingTex();
199 if( blendFactor == 0 )
200 drawCharTex( &arrowImages[0], NULL, &arrows, 255, 255, 255, transparency );
201 else
202 {
203 if( SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] )
204 drawCharTex( &arrowImages[1], NULL, &arrows, 255, 255, 255, transparency / blendFactor );
205 if( SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] )
206 drawCharTex( &arrowImages[2], NULL, &arrows, 255, 255, 255, transparency / blendFactor );
207 if( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] )
208 drawCharTex( &arrowImages[3], NULL, &arrows, 255, 255, 255, transparency / blendFactor );
209 if( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] )
210 drawCharTex( &arrowImages[4], NULL, &arrows, 255, 255, 255, transparency / blendFactor );
211 }
212
213 for( i = 0; i < MAX_BUTTONS; i++ )
214 {
215 if( ! buttons[i].h || ! buttons[i].w )
216 continue;
217 if( i < AutoFireButtonsNum )
218 {
219 if( ButtonAutoFire[i] == 1 && SDL_GetTicks() - ButtonAutoFireDecay[i] > 1000 )
220 {
221 ButtonAutoFire[i] = 0;
222 }
223 if( ! ButtonAutoFire[i] && SDL_GetTicks() - ButtonAutoFireDecay[i] > 300 )
224 {
225 if( ButtonAutoFireX[i*2] > 0 )
226 ButtonAutoFireX[i*2] --;
227 if( ButtonAutoFireX[i*2+1] > 0 )
228 ButtonAutoFireX[i*2+1] --;
229 ButtonAutoFireDecay[i] = SDL_GetTicks();
230 }
231 }
232
233 if( i < AutoFireButtonsNum && ! ButtonAutoFire[i] &&
234 ( ButtonAutoFireX[i*2] > 0 || ButtonAutoFireX[i*2+1] > 0 ) )
235 {
236 int pos1src = buttonImages[i*2+1].w / 2 - ButtonAutoFireX[i*2];
237 int pos1dst = buttons[i].w * pos1src / buttonImages[i*2+1].w;
238 int pos2src = buttonImages[i*2+1].w - ( buttonImages[i*2+1].w / 2 - ButtonAutoFireX[i*2+1] );
239 int pos2dst = buttons[i].w * pos2src / buttonImages[i*2+1].w;
240
241 SDL_Rect autoFireCrop = { 0, 0, pos1src, buttonImages[i*2+1].h };
242 SDL_Rect autoFireDest = buttons[i];
243 autoFireDest.w = pos1dst;
244
245 drawCharTex( &buttonImages[i*2+1],
246 &autoFireCrop, &autoFireDest, 255, 255, 255, transparency );
247
248 autoFireCrop.x = pos2src;
249 autoFireCrop.w = buttonImages[i*2+1].w - pos2src;
250 autoFireDest.x = buttons[i].x + pos2dst;
251 autoFireDest.w = buttons[i].w - pos2dst;
252
253 drawCharTex( &buttonImages[i*2+1],
254 &autoFireCrop, &autoFireDest, 255, 255, 255, transparency );
255
256 autoFireCrop.x = pos1src;
257 autoFireCrop.w = pos2src - pos1src;
258 autoFireDest.x = buttons[i].x + pos1dst;
259 autoFireDest.w = pos2dst - pos1dst;
260
261 drawCharTex( &buttonAutoFireImages[i*2+1],
262 &autoFireCrop, &autoFireDest, 255, 255, 255, transparency );
263 }
264 else
265 {
266 drawCharTex( ( i < AutoFireButtonsNum && ButtonAutoFire[i] ) ? &buttonAutoFireImages[i*2] :
267 &buttonImages[ SDL_GetKeyboardState(NULL)[buttonKeysyms[i]] ? (i * 2 + 1) : (i * 2) ],
268 NULL, &buttons[i], 255, 255, 255, transparency );
269 }
270 }
271 endDrawingTex();
272
273 return 1;
274 };
275
ArrowKeysPressed(int x,int y)276 static inline int ArrowKeysPressed(int x, int y)
277 {
278 int ret = 0, dx, dy;
279 dx = x - arrows.x - arrows.w / 2;
280 dy = y - arrows.y - arrows.h / 2;
281 // Single arrow key pressed
282 if( abs(dy / 2) >= abs(dx) )
283 {
284 if( dy < 0 )
285 ret |= ARROW_UP;
286 else
287 ret |= ARROW_DOWN;
288 }
289 else
290 if( abs(dx / 2) >= abs(dy) )
291 {
292 if( dx > 0 )
293 ret |= ARROW_RIGHT;
294 else
295 ret |= ARROW_LEFT;
296 }
297 else // Two arrow keys pressed
298 {
299 if( dx > 0 )
300 ret |= ARROW_RIGHT;
301 else
302 ret |= ARROW_LEFT;
303
304 if( dy < 0 )
305 ret |= ARROW_UP;
306 else
307 ret |= ARROW_DOWN;
308 }
309 return ret;
310 }
311
SDL_ANDROID_processTouchscreenKeyboard(int x,int y,int action,int pointerId)312 int SDL_ANDROID_processTouchscreenKeyboard(int x, int y, int action, int pointerId)
313 {
314 int i;
315 int processed = 0;
316
317
318 if( !touchscreenKeyboardShown )
319 return 0;
320
321
322 if( action == MOUSE_DOWN )
323 {
324 //__android_log_print(ANDROID_LOG_INFO, "libSDL", "touch %03dx%03d ptr %d action %d", x, y, pointerId, action);
325 if( InsideRect( &arrows, x, y ) )
326 {
327 processed = 1;
328 if( pointerInButtonRect[MAX_BUTTONS] == -1 )
329 {
330 pointerInButtonRect[MAX_BUTTONS] = pointerId;
331 if( SDL_ANDROID_isJoystickUsed )
332 {
333 SDL_ANDROID_MainThreadPushJoystickAxis(0, 0, (x - arrows.x - arrows.w / 2) * 65534 / arrows.w );
334 SDL_ANDROID_MainThreadPushJoystickAxis(0, 1, (y - arrows.y - arrows.h / 2) * 65534 / arrows.h );
335 }
336 else
337 {
338 i = ArrowKeysPressed(x, y);
339 if( i & ARROW_UP )
340 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(UP) );
341 if( i & ARROW_DOWN )
342 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(DOWN) );
343 if( i & ARROW_LEFT )
344 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(LEFT) );
345 if( i & ARROW_RIGHT )
346 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(RIGHT) );
347 oldArrows = i;
348 }
349 }
350 }
351
352 for( i = 0; i < MAX_BUTTONS; i++ )
353 {
354 if( ! buttons[i].h || ! buttons[i].w )
355 continue;
356 if( InsideRect( &buttons[i], x, y) )
357 {
358 processed = 1;
359 if( pointerInButtonRect[i] == -1 )
360 {
361 pointerInButtonRect[i] = pointerId;
362 if( i == BUTTON_TEXT_INPUT )
363 SDL_ANDROID_ToggleScreenKeyboardTextInput(NULL);
364 else
365 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, buttonKeysyms[i] );
366 if( i < AutoFireButtonsNum )
367 {
368 ButtonAutoFire[i] = 0;
369 ButtonAutoFireX[i*2] = 0;
370 ButtonAutoFireX[i*2+1] = 0;
371 ButtonAutoFireRot[i] = x;
372 ButtonAutoFireDecay[i] = SDL_GetTicks();
373 }
374 }
375 }
376 }
377 }
378 else
379 if( action == MOUSE_UP )
380 {
381 //__android_log_print(ANDROID_LOG_INFO, "libSDL", "touch %03dx%03d ptr %d action %d", x, y, pointerId, action);
382 if( pointerInButtonRect[MAX_BUTTONS] == pointerId )
383 {
384 processed = 1;
385 pointerInButtonRect[MAX_BUTTONS] = -1;
386 if( SDL_ANDROID_isJoystickUsed )
387 {
388 SDL_ANDROID_MainThreadPushJoystickAxis(0, 0, 0 );
389 SDL_ANDROID_MainThreadPushJoystickAxis(0, 1, 0 );
390 }
391 else
392 {
393 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP) );
394 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN) );
395 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT) );
396 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT) );
397 oldArrows = 0;
398 }
399 }
400 for( i = 0; i < MAX_BUTTONS; i++ )
401 {
402 if( ! buttons[i].h || ! buttons[i].w )
403 continue;
404 if( pointerInButtonRect[i] == pointerId )
405 {
406 processed = 1;
407 pointerInButtonRect[i] = -1;
408 if( i < AutoFireButtonsNum && ButtonAutoFire[i] )
409 {
410 ButtonAutoFire[i] = 2;
411 }
412 else
413 {
414 if( i != BUTTON_TEXT_INPUT )
415 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, buttonKeysyms[i] );
416 }
417 if( i < AutoFireButtonsNum )
418 {
419 ButtonAutoFireX[i*2] = 0;
420 ButtonAutoFireX[i*2+1] = 0;
421 }
422 }
423 }
424 }
425 else
426 if( action == MOUSE_MOVE )
427 {
428 // Process cases when pointer enters button area (it won't send keypress twice if button already pressed)
429 processed = SDL_ANDROID_processTouchscreenKeyboard(x, y, MOUSE_DOWN, pointerId);
430
431 // Process cases when pointer leaves button area
432 // TODO: huge code size, split it or somehow make it more readable
433 if( pointerInButtonRect[MAX_BUTTONS] == pointerId )
434 {
435 processed = 1;
436 if( ! InsideRect( &arrows, x, y ) )
437 {
438 pointerInButtonRect[MAX_BUTTONS] = -1;
439 if( SDL_ANDROID_isJoystickUsed )
440 {
441 SDL_ANDROID_MainThreadPushJoystickAxis(0, 0, 0 );
442 SDL_ANDROID_MainThreadPushJoystickAxis(0, 1, 0 );
443 }
444 else
445 {
446 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP) );
447 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN) );
448 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT) );
449 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT) );
450 oldArrows = 0;
451 }
452 }
453 else
454 {
455 if( SDL_ANDROID_isJoystickUsed )
456 {
457 SDL_ANDROID_MainThreadPushJoystickAxis(0, 0, (x - arrows.x - arrows.w / 2) * 65534 / arrows.w );
458 SDL_ANDROID_MainThreadPushJoystickAxis(0, 1, (y - arrows.y - arrows.h / 2) * 65534 / arrows.h );
459 }
460 else
461 {
462 i = ArrowKeysPressed(x, y);
463 if( i != oldArrows )
464 {
465 if( oldArrows & ARROW_UP && ! (i & ARROW_UP) )
466 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP) );
467 if( oldArrows & ARROW_DOWN && ! (i & ARROW_DOWN) )
468 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN) );
469 if( oldArrows & ARROW_LEFT && ! (i & ARROW_LEFT) )
470 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT) );
471 if( oldArrows & ARROW_RIGHT && ! (i & ARROW_RIGHT) )
472 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT) );
473 if( i & ARROW_UP )
474 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(UP) );
475 if( i & ARROW_DOWN )
476 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(DOWN) );
477 if( i & ARROW_LEFT )
478 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(LEFT) );
479 if( i & ARROW_RIGHT )
480 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(RIGHT) );
481 }
482 oldArrows = i;
483 }
484 }
485 }
486 for( i = 0; i < AutoFireButtonsNum; i++ )
487 {
488 if( pointerInButtonRect[i] == pointerId )
489 {
490 processed = 1;
491 if( ! InsideRect( &buttonsAutoFireRect[i], x, y ) )
492 {
493 pointerInButtonRect[i] = -1;
494 if( !ButtonAutoFire[i] )
495 {
496 if( i != BUTTON_TEXT_INPUT )
497 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, buttonKeysyms[i] );
498 }
499 else
500 {
501 ButtonAutoFire[i] = 2;
502 }
503 ButtonAutoFireX[i*2] = 0;
504 ButtonAutoFireX[i*2+1] = 0;
505 }
506 else
507 {
508 int coeff = (buttonAutoFireImages[i*2+1].w > buttons[i].w) ? buttonAutoFireImages[i*2+1].w / buttons[i].w + 1 : 1;
509 if( ButtonAutoFireRot[i] < x )
510 ButtonAutoFireX[i*2+1] += (x - ButtonAutoFireRot[i]) * coeff;
511 if( ButtonAutoFireRot[i] > x )
512 ButtonAutoFireX[i*2] += (ButtonAutoFireRot[i] - x) * coeff;
513
514 ButtonAutoFireRot[i] = x;
515
516 if( ButtonAutoFireX[i*2] < 0 )
517 ButtonAutoFireX[i*2] = 0;
518 if( ButtonAutoFireX[i*2+1] < 0 )
519 ButtonAutoFireX[i*2+1] = 0;
520 if( ButtonAutoFireX[i*2] > buttonAutoFireImages[i*2+1].w / 2 )
521 ButtonAutoFireX[i*2] = buttonAutoFireImages[i*2+1].w / 2;
522 if( ButtonAutoFireX[i*2+1] > buttonAutoFireImages[i*2+1].w / 2 )
523 ButtonAutoFireX[i*2+1] = buttonAutoFireImages[i*2+1].w / 2;
524
525 if( ButtonAutoFireX[i*2] == buttonAutoFireImages[i*2+1].w / 2 &&
526 ButtonAutoFireX[i*2+1] == buttonAutoFireImages[i*2+1].w / 2 )
527 {
528 if( ! ButtonAutoFire[i] )
529 ButtonAutoFireDecay[i] = SDL_GetTicks();
530 ButtonAutoFire[i] = 1;
531 }
532 }
533 }
534 }
535 for( i = AutoFireButtonsNum; i < MAX_BUTTONS; i++ )
536 {
537 if( ! buttons[i].h || ! buttons[i].w )
538 continue;
539 if( pointerInButtonRect[i] == pointerId )
540 {
541 processed = 1;
542 if( ! InsideRect( &buttons[i], x, y ) )
543 {
544 pointerInButtonRect[i] = -1;
545 if( i != BUTTON_TEXT_INPUT )
546 SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, buttonKeysyms[i] );
547 }
548 }
549 }
550 }
551
552 return processed;
553 };
554
555 JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboard)556 JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboard) ( JNIEnv* env, jobject thiz, jint size, jint theme, jint nbuttonsAutoFire, jint _transparency )
557 {
558 int i, ii;
559 int nbuttons1row, nbuttons2row;
560 int _nbuttons = MAX_BUTTONS;
561 touchscreenKeyboardTheme = theme;
562 AutoFireButtonsNum = nbuttonsAutoFire;
563 if( AutoFireButtonsNum > MAX_BUTTONS_AUTOFIRE )
564 AutoFireButtonsNum = MAX_BUTTONS_AUTOFIRE;
565 // TODO: works for horizontal screen orientation only!
566 buttonsize = size;
567 switch(_transparency)
568 {
569 case 0: transparency = 16; break;
570 case 1: transparency = 32; break;
571 case 2: transparency = 64; break;
572 case 3: transparency = 128; break;
573 case 4: transparency = 192; break;
574 default: transparency = 128; break;
575 }
576
577 // Arrows to the lower-left part of screen
578 arrows.x = SDL_ANDROID_sWindowWidth / 4;
579 arrows.y = SDL_ANDROID_sWindowHeight - SDL_ANDROID_sWindowWidth / 4;
580 arrows.w = SDL_ANDROID_sWindowWidth / (size + 2);
581 arrows.h = arrows.w;
582 arrows.x -= arrows.w/2;
583 arrows.y -= arrows.h/2;
584 // Move arrows from the center of the screen
585 arrows.x -= size * SDL_ANDROID_sWindowWidth / 32;
586 arrows.y += size * SDL_ANDROID_sWindowWidth / 32;
587
588 // Buttons to the lower-right in 2 rows
589 for(i = 0; i < 2; i++)
590 for(ii = 0; ii < 3; ii++)
591 {
592 // Custom button ordering
593 int iii = ii + i*2;
594 if( ii == 2 )
595 iii = 4 + i;
596 buttons[iii].x = SDL_ANDROID_sWindowWidth - SDL_ANDROID_sWindowWidth / 12 - (SDL_ANDROID_sWindowWidth * ii / 6);
597 buttons[iii].y = SDL_ANDROID_sWindowHeight - SDL_ANDROID_sWindowHeight / 8 - (SDL_ANDROID_sWindowHeight * i / 4);
598 buttons[iii].w = SDL_ANDROID_sWindowWidth / (size + 2) / 3;
599 buttons[iii].h = buttons[iii].w;
600 buttons[iii].x -= buttons[iii].w/2;
601 buttons[iii].y -= buttons[iii].h/2;
602 }
603 buttons[6].x = 0;
604 buttons[6].y = 0;
605 buttons[6].w = SDL_ANDROID_sWindowHeight/10;
606 buttons[6].h = SDL_ANDROID_sWindowHeight/10;
607
608 for( i = 0; i < sizeof(pointerInButtonRect)/sizeof(pointerInButtonRect[0]); i++ )
609 {
610 pointerInButtonRect[i] = -1;
611 }
612 for( i = 0; i < nbuttonsAutoFire; i++ )
613 {
614 buttonsAutoFireRect[i].w = buttons[i].w * 2;
615 buttonsAutoFireRect[i].h = buttons[i].h * 2;
616 buttonsAutoFireRect[i].x = buttons[i].x - buttons[i].w / 2;
617 buttonsAutoFireRect[i].y = buttons[i].y - buttons[i].h / 2;
618 }
619 };
620
621
622 JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetTouchscreenKeyboardUsed)623 JAVA_EXPORT_NAME(Settings_nativeSetTouchscreenKeyboardUsed) ( JNIEnv* env, jobject thiz)
624 {
625 SDL_ANDROID_isTouchscreenKeyboardUsed = 1;
626 }
627
628 static int
power_of_2(int input)629 power_of_2(int input)
630 {
631 int value = 1;
632
633 while (value < input) {
634 value <<= 1;
635 }
636 return value;
637 }
638
setupScreenKeyboardButton(int buttonID,Uint8 * charBuf)639 static int setupScreenKeyboardButton( int buttonID, Uint8 * charBuf )
640 {
641 // TODO: softstretch with antialiasing
642 int w, h, len, format;
643 GLTexture_t * data = NULL;
644 int texture_w, texture_h;
645
646 if( buttonID < 5 )
647 data = &(arrowImages[buttonID]);
648 else
649 if( buttonID < 9 )
650 data = &(buttonAutoFireImages[buttonID-5]);
651 else
652 data = &(buttonImages[buttonID-9]);
653
654 if( buttonID > 22 ) // Error, array too big
655 return 12; // Return value bigger than zero to iterate it
656
657 memcpy(&w, charBuf, sizeof(int));
658 memcpy(&h, charBuf + sizeof(int), sizeof(int));
659 memcpy(&format, charBuf + 2*sizeof(int), sizeof(int));
660 w = ntohl(w);
661 h = ntohl(h);
662 format = ntohl(format);
663
664 texture_w = power_of_2(w);
665 texture_h = power_of_2(h);
666 data->w = w;
667 data->h = h;
668
669 glEnable(GL_TEXTURE_2D);
670
671 glGenTextures(1, &data->id);
672 glBindTexture(GL_TEXTURE_2D, data->id);
673 //__android_log_print(ANDROID_LOG_INFO, "libSDL", "On-screen keyboard generated OpenGL texture ID %d", data->id);
674
675 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA,
676 format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1, NULL);
677 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
678
679 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA,
680 format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1,
681 charBuf + 3*sizeof(int) );
682
683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
685
686 glDisable(GL_TEXTURE_2D);
687
688 return 3*sizeof(int) + w * h * 2;
689 }
690
691 JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboardButtons)692 JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboardButtons) ( JNIEnv* env, jobject thiz, jbyteArray charBufJava )
693 {
694 jboolean isCopy = JNI_TRUE;
695 int len = (*env)->GetArrayLength(env, charBufJava);
696 Uint8 * charBuf = (Uint8 *) (*env)->GetByteArrayElements(env, charBufJava, &isCopy);
697 int but, pos;
698
699 for( but = 0, pos = 0; pos < len; but ++ )
700 pos += setupScreenKeyboardButton( but, charBuf + pos );
701
702 (*env)->ReleaseByteArrayElements(env, charBufJava, (jbyte *)charBuf, 0);
703 }
704
705
SDL_ANDROID_SetScreenKeyboardButtonPos(int buttonId,SDL_Rect * pos)706 int SDL_ANDROID_SetScreenKeyboardButtonPos(int buttonId, SDL_Rect * pos)
707 {
708 if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM || ! pos )
709 return 0;
710
711 if( buttonId == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD )
712 {
713 arrows = *pos;
714 }
715 else
716 {
717 int i = buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0;
718 buttons[i] = *pos;
719 if( i < AutoFireButtonsNum )
720 {
721 buttonsAutoFireRect[i].w = buttons[i].w * 2;
722 buttonsAutoFireRect[i].h = buttons[i].h * 2;
723 buttonsAutoFireRect[i].x = buttons[i].x - buttons[i].w / 2;
724 buttonsAutoFireRect[i].y = buttons[i].y - buttons[i].h / 2;
725 }
726 }
727 return 1;
728 };
729
SDL_ANDROID_GetScreenKeyboardButtonPos(int buttonId,SDL_Rect * pos)730 int SDL_ANDROID_GetScreenKeyboardButtonPos(int buttonId, SDL_Rect * pos)
731 {
732 if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM || ! pos )
733 return 0;
734
735 if( buttonId == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD )
736 {
737 *pos = arrows;
738 }
739 else
740 {
741 *pos = buttons[buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0];
742 }
743 return 1;
744 };
745
SDL_ANDROID_SetScreenKeyboardButtonKey(int buttonId,SDLKey key)746 int SDL_ANDROID_SetScreenKeyboardButtonKey(int buttonId, SDLKey key)
747 {
748 if( buttonId < SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 || buttonId > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 || ! key )
749 return 0;
750 buttonKeysyms[buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0] = key;
751 return 1;
752 };
753
SDL_ANDROID_GetScreenKeyboardButtonKey(int buttonId)754 SDLKey SDL_ANDROID_GetScreenKeyboardButtonKey(int buttonId)
755 {
756 if( buttonId < SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 || buttonId > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 )
757 return SDLK_UNKNOWN;
758 return buttonKeysyms[buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0];
759 };
760
SDL_ANDROID_SetScreenKeyboardAutoFireButtonsAmount(int nbuttons)761 int SDL_ANDROID_SetScreenKeyboardAutoFireButtonsAmount(int nbuttons)
762 {
763 if( nbuttons < 0 || nbuttons >= MAX_BUTTONS_AUTOFIRE )
764 return 0;
765 AutoFireButtonsNum = nbuttons;
766 return 1;
767 };
768
SDL_ANDROID_GetScreenKeyboardAutoFireButtonsAmount()769 int SDL_ANDROID_GetScreenKeyboardAutoFireButtonsAmount()
770 {
771 return AutoFireButtonsNum;
772 };
773
SDL_ANDROID_SetScreenKeyboardShown(int shown)774 int SDL_ANDROID_SetScreenKeyboardShown(int shown)
775 {
776 touchscreenKeyboardShown = shown;
777 };
778
SDL_ANDROID_GetScreenKeyboardShown()779 int SDL_ANDROID_GetScreenKeyboardShown()
780 {
781 return touchscreenKeyboardShown;
782 };
783
SDL_ANDROID_GetScreenKeyboardSize()784 int SDL_ANDROID_GetScreenKeyboardSize()
785 {
786 return buttonsize;
787 };
788
SDL_ANDROID_ToggleScreenKeyboardTextInput(const char * previousText)789 int SDL_ANDROID_ToggleScreenKeyboardTextInput(const char * previousText)
790 {
791 static char textIn[255];
792 if( previousText == NULL )
793 previousText = "";
794 strncpy(textIn, previousText, sizeof(textIn));
795 textIn[sizeof(textIn)-1] = 0;
796 SDL_ANDROID_CallJavaShowScreenKeyboard(textIn, NULL, 0);
797 return 1;
798 };
799
SDL_ANDROID_GetScreenKeyboardTextInput(char * textBuf,int textBufSize)800 int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(char * textBuf, int textBufSize)
801 {
802 SDL_ANDROID_CallJavaShowScreenKeyboard(textBuf, textBuf, textBufSize);
803 return 1;
804 };
805
806