Files
commandergenius/project/jni/sdl-1.2/src/video/android/SDL_touchscreenkeyboard.c
2015-09-17 22:52:12 +03:00

1427 lines
45 KiB
C

/*
Simple DirectMedia Layer
Copyright (C) 2009-2014 Sergii Pylypenko
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
This source code is distibuted under ZLIB license, however when compiling with SDL 1.2,
which is licensed under LGPL, the resulting library, and all it's source code,
falls under "stronger" LGPL terms, so is this file.
If you compile this code with SDL 1.3 or newer, or use in some other way, the license stays ZLIB.
*/
#include <jni.h>
#include <android/log.h>
#include <sys/time.h>
#include <time.h>
#include <stdint.h>
#include <math.h>
#include <string.h> // for memset()
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <netinet/in.h>
#include "SDL_config.h"
#include "SDL_version.h"
//#include "SDL_opengles.h"
#include "SDL_screenkeyboard.h"
#include "../SDL_sysvideo.h"
#include "SDL_androidvideo.h"
#include "SDL_androidinput.h"
#include "jniwrapperstuff.h"
#include "atan2i.h"
// TODO: this code is a HUGE MESS
enum { MAX_BUTTONS = SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM-1, MAX_JOYSTICKS = 3, MAX_BUTTONS_AUTOFIRE = 2, BUTTON_TEXT_INPUT = SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, BUTTON_ARROWS = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD } ; // Max amount of custom buttons
int SDL_ANDROID_isTouchscreenKeyboardUsed = 0;
static short touchscreenKeyboardTheme = 0;
static short touchscreenKeyboardShown = 1;
static SDL_Rect hiddenButtons[SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM];
static short buttonsize = 1;
static short buttonDrawSize = 1;
static float transparency = 128.0f/255.0f;
static SDL_Rect arrows[MAX_JOYSTICKS], arrowsExtended[MAX_JOYSTICKS], buttons[MAX_BUTTONS];
static SDL_Rect arrowsDraw[MAX_JOYSTICKS], buttonsDraw[MAX_BUTTONS];
static SDLKey buttonKeysyms[MAX_BUTTONS] = {
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_0)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_1)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_2)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_3)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_4)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_5)),
0
};
enum { ARROW_LEFT = 1, ARROW_RIGHT = 2, ARROW_UP = 4, ARROW_DOWN = 8 };
static short oldArrows = 0;
static Sint8 pointerInButtonRect[MAX_BUTTONS + MAX_JOYSTICKS];
static Sint8 buttonsGenerateSdlEvents[MAX_BUTTONS + MAX_JOYSTICKS];
static Sint8 buttonsStayPressedAfterTouch[MAX_BUTTONS + MAX_JOYSTICKS];
typedef struct
{
GLuint id;
GLfloat w;
GLfloat h;
} GLTexture_t;
static GLTexture_t arrowImages[9];
static GLTexture_t buttonAutoFireImages[MAX_BUTTONS_AUTOFIRE*2]; // These are not used anymore
static GLTexture_t buttonImages[MAX_BUTTONS*2];
static GLTexture_t mousePointer;
enum { MOUSE_POINTER_W = 32, MOUSE_POINTER_H = 32, MOUSE_POINTER_X = 5, MOUSE_POINTER_Y = 7 }; // X and Y are offsets of the pointer tip
static int themeType = 0;
static int joystickTouchPoints[MAX_JOYSTICKS*2];
static int floatingScreenJoystick = 0;
static void R_DumpOpenGlState(void);
static inline int InsideRect(const SDL_Rect * r, int x, int y)
{
return ( x >= r->x && x <= r->x + r->w ) && ( y >= r->y && y <= r->y + r->h );
}
// Find the intersection of a line and a rectangle,
// where on of the line points and the center of rectangle
// are both at the coordinate [0,0].
// It returns the remaining line segment outside of the rectangle.
// Do not check for border condition, we check that the line point
// is outside of the rectangle in another function.
static inline void LineAndRectangleIntersection(
int lx, int ly, // Line point, that is outside of rectangle
int rw, int rh, // Rectangle dimensions
int *x, int *y)
{
if( abs(lx) * rh > abs(ly) * rw )
{
rw /= 2;
// Intersection at the left side
if( lx < -rw )
*x = lx + rw; // lx is negative
else //if( lx > rw ) // At the right side
*x = lx - rw; // lx is positive
*y = *x * ly / lx;
}
else
{
rh /= 2;
// At the top
if( ly < -rh )
*y = ly + rh; // ly is negative
else //if( ly > rh ) // At the right side
*y = ly - rh; // ly is positive
*x = *y * lx / ly;
}
}
static struct ScreenKbGlState_t
{
GLboolean texture2d;
GLuint texunitId;
GLuint clientTexunitId;
GLuint textureId;
GLfloat color[4];
GLint texEnvMode;
GLboolean blend;
GLenum blend1, blend2;
GLint texFilter1, texFilter2;
GLboolean colorArray;
}
oldGlState;
static inline void beginDrawingTex()
{
#ifndef SDL_TOUCHSCREEN_KEYBOARD_SAVE_RESTORE_OPENGL_STATE
// Make the video somehow work on emulator
oldGlState.texture2d = GL_TRUE;
oldGlState.texunitId = GL_TEXTURE0;
oldGlState.clientTexunitId = GL_TEXTURE0;
oldGlState.textureId = 0;
oldGlState.texEnvMode = GL_MODULATE;
oldGlState.blend = GL_TRUE;
oldGlState.blend1 = GL_SRC_ALPHA;
oldGlState.blend2 = GL_ONE_MINUS_SRC_ALPHA;
oldGlState.colorArray = GL_FALSE;
#else
// Save OpenGL state
// This code does not work on 1.6 emulator, and on some older devices
// However GLES 1.1 spec defines all theese values, so it's a device fault for not implementing them
oldGlState.texture2d = glIsEnabled(GL_TEXTURE_2D);
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldGlState.texunitId);
glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &oldGlState.clientTexunitId);
#endif
//R_DumpOpenGlState();
/*
glActiveTexture(GL_TEXTURE1);
glClientActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
*/
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
#ifdef SDL_TOUCHSCREEN_KEYBOARD_SAVE_RESTORE_OPENGL_STATE
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldGlState.textureId);
glGetFloatv(GL_CURRENT_COLOR, &(oldGlState.color[0]));
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &oldGlState.texEnvMode);
oldGlState.blend = glIsEnabled(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC, &oldGlState.blend1);
glGetIntegerv(GL_BLEND_DST, &oldGlState.blend2);
glGetBooleanv(GL_COLOR_ARRAY, &oldGlState.colorArray);
// It's very unlikely that some app will use GL_TEXTURE_CROP_RECT_OES, so just skip it
#endif
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisableClientState(GL_COLOR_ARRAY);
//static const GLfloat color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
//glDisable(GL_DEPTH_TEST);
//glDisable(GL_ALPHA_TEST);
//glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
//glDisableClientState(GL_NORMAL_ARRAY);
//glDisableClientState(GL_VERTEX_ARRAY);
//glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
static inline void endDrawingTex()
{
// Restore OpenGL state
if( oldGlState.texture2d == GL_FALSE )
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, oldGlState.textureId);
glColor4f(oldGlState.color[0], oldGlState.color[1], oldGlState.color[2], oldGlState.color[3]);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, oldGlState.texEnvMode);
if( oldGlState.blend == GL_FALSE )
glDisable(GL_BLEND);
glBlendFunc(oldGlState.blend1, oldGlState.blend2);
glActiveTexture(oldGlState.texunitId);
glClientActiveTexture(oldGlState.clientTexunitId);
if( oldGlState.colorArray )
glEnableClientState(GL_COLOR_ARRAY);
}
static inline void drawCharTexFlip(GLTexture_t * tex, SDL_Rect * src, SDL_Rect * dest, int flipX, int flipY, float r, float g, float b, float a)
{
GLint cropRect[4];
if( !dest->h || !dest->w )
return;
glBindTexture(GL_TEXTURE_2D, tex->id);
glColor4f(r, g, b, a);
if(src)
{
cropRect[0] = src->x;
cropRect[1] = tex->h - src->y;
cropRect[2] = src->w;
cropRect[3] = -src->h;
}
else
{
cropRect[0] = 0;
cropRect[1] = tex->h;
cropRect[2] = tex->w;
cropRect[3] = -tex->h;
}
if(flipX)
{
cropRect[0] += cropRect[2];
cropRect[2] = -cropRect[2];
}
if(flipY)
{
cropRect[1] += cropRect[3];
cropRect[3] = -cropRect[3];
}
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
glDrawTexiOES(dest->x + SDL_ANDROID_ScreenVisibleRect.x, SDL_ANDROID_sRealWindowHeight - dest->y - dest->h - SDL_ANDROID_ScreenVisibleRect.y, 0, dest->w, dest->h);
}
static inline void drawCharTex(GLTexture_t * tex, SDL_Rect * src, SDL_Rect * dest, float r, float g, float b, float a)
{
drawCharTexFlip(tex, src, dest, 0, 0, r, g, b, a);
}
static void drawTouchscreenKeyboardLegacy()
{
int i;
float blendFactor;
if( SDL_ANDROID_joysticksAmount >= 1 )
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( arrowImages[8].id == 0 ) // No diagonal arrow images
{
blendFactor = ( SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] ? 4 : 0 ) +
( SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] ? 4 : 0 ) +
( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] ? 4 : 0 ) +
( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] ? 4 : 0 );
if (blendFactor >= 8)
blendFactor = 7;
if( blendFactor == 0 )
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else
{
if( SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] )
drawCharTex( &arrowImages[1], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency * 4 / blendFactor );
if( SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] )
drawCharTex( &arrowImages[2], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency * 4 / blendFactor );
if( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] )
drawCharTex( &arrowImages[3], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency * 4 / blendFactor );
if( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] )
drawCharTex( &arrowImages[4], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency * 4 / blendFactor );
}
}
else // Diagonal arrow images present
{
if( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] && SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] )
drawCharTex( &arrowImages[5], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] && SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] )
drawCharTex( &arrowImages[6], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] && SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] )
drawCharTex( &arrowImages[7], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] && SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] )
drawCharTex( &arrowImages[8], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] )
drawCharTex( &arrowImages[1], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] )
drawCharTex( &arrowImages[2], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] )
drawCharTex( &arrowImages[3], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else if( SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] )
drawCharTex( &arrowImages[4], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
else
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[0], 1.0f, 1.0f, 1.0f, transparency );
}
if( SDL_ANDROID_joysticksAmount >= 2 )
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[1], 1.0f, 1.0f, 1.0f, transparency );
if( SDL_ANDROID_joysticksAmount >= 3 )
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[2], 1.0f, 1.0f, 1.0f, transparency );
for( i = 0; i < MAX_BUTTONS; i++ )
{
if( ! buttons[i].h || ! buttons[i].w )
continue;
drawCharTex( &buttonImages[ SDL_GetKeyboardState(NULL)[buttonKeysyms[i]] ? (i * 2 + 1) : (i * 2) ],
NULL, &buttonsDraw[i], 1.0f, 1.0f, 1.0f, transparency );
}
}
static void drawTouchscreenKeyboardSun()
{
int i;
for( i = 0; i < SDL_ANDROID_joysticksAmount || (i == 0 && arrowsDraw[0].w > 0); i++ )
{
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[i], 1.0f, 1.0f, 1.0f, transparency );
if(pointerInButtonRect[BUTTON_ARROWS+i] != -1)
{
SDL_Rect touch = arrowsDraw[i];
touch.w /= 2;
touch.h /= 2;
touch.x = joystickTouchPoints[0+i*2] - touch.w / 2;
touch.y = joystickTouchPoints[1+i*2] - touch.h / 2;
drawCharTex( &arrowImages[0], NULL, &touch, 1.0f, 1.0f, 1.0f, transparency );
}
}
for( i = 0; i < MAX_BUTTONS; i++ )
{
int pressed = SDL_GetKeyboardState(NULL)[buttonKeysyms[i]];
if( ! buttons[i].h || ! buttons[i].w )
continue;
drawCharTexFlip( &buttonImages[ pressed ? (i * 2 + 1) : (i * 2) ],
NULL, &buttonsDraw[i], (i >= 2 && pressed), 0, 1.0f, 1.0f, 1.0f, transparency );
}
}
static void drawTouchscreenKeyboardDualShock()
{
int i;
for( i = 0; i < SDL_ANDROID_joysticksAmount || (i == 0 && arrowsDraw[0].w > 0); i++ )
{
drawCharTex( &arrowImages[0], NULL, &arrowsDraw[i], 1.0f, 1.0f, 1.0f, transparency );
if(pointerInButtonRect[BUTTON_ARROWS+i] != -1)
{
SDL_Rect touch = arrowsDraw[i];
touch.w /= 1.5;
touch.h /= 1.5;
touch.x = joystickTouchPoints[0+i*2] - touch.w / 2;
touch.y = joystickTouchPoints[1+i*2] - touch.h / 2;
drawCharTex( &arrowImages[6], NULL, &touch, 1.0f, 1.0f, 1.0f, transparency );
}
else
{
SDL_Rect touch = arrowsDraw[i];
touch.w /= 1.5;
touch.h /= 1.5;
touch.x = arrowsDraw[i].x + touch.w / 4;
touch.y = arrowsDraw[i].y + touch.h / 4;
drawCharTex( &arrowImages[6], NULL, &touch, 1.0f, 1.0f, 1.0f, transparency );
}
}
for( i = 0; i < MAX_BUTTONS; i++ )
{
int pressed = SDL_GetKeyboardState(NULL)[buttonKeysyms[i]];
if( ! buttons[i].h || ! buttons[i].w )
continue;
drawCharTexFlip( &buttonImages[ pressed ? (i * 2 + 1) : (i * 2) ],
NULL, &buttonsDraw[i], (i >= 2 && pressed), 0, 1.0f, 1.0f, 1.0f, transparency );
}
}
int SDL_ANDROID_drawTouchscreenKeyboard()
{
if( !SDL_ANDROID_isTouchscreenKeyboardUsed || !touchscreenKeyboardShown )
return 0;
beginDrawingTex();
if(themeType==1)
drawTouchscreenKeyboardSun();
else if(themeType==2)
drawTouchscreenKeyboardDualShock();
else
drawTouchscreenKeyboardLegacy();
endDrawingTex();
return 1;
};
static inline int ArrowKeysPressed(int x, int y)
{
int ret = 0, dx, dy;
dx = x - arrows[0].x - arrows[0].w / 2;
dy = y - arrows[0].y - arrows[0].h / 2;
// Small deadzone at the center
if( abs(dx) < arrows[0].w / 20 && abs(dy) < arrows[0].h / 20 )
return ret;
// Single arrow key pressed
if( abs(dy / 2) >= abs(dx) )
{
if( dy < 0 )
ret |= ARROW_UP;
else
ret |= ARROW_DOWN;
}
else
if( abs(dx / 2) >= abs(dy) )
{
if( dx > 0 )
ret |= ARROW_RIGHT;
else
ret |= ARROW_LEFT;
}
else // Two arrow keys pressed
{
if( dx > 0 )
ret |= ARROW_RIGHT;
else
ret |= ARROW_LEFT;
if( dy < 0 )
ret |= ARROW_UP;
else
ret |= ARROW_DOWN;
}
return ret;
}
unsigned SDL_ANDROID_processTouchscreenKeyboard(int x, int y, int action, int pointerId)
{
int i, j;
unsigned processed = 0;
int joyAmount = SDL_ANDROID_joysticksAmount;
if( joyAmount == 0 && (arrows[0].w > 0 || floatingScreenJoystick) )
joyAmount = 1;
if( !touchscreenKeyboardShown )
return 0;
if( action == MOUSE_DOWN )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "touch %03dx%03d ptr %d action %d", x, y, pointerId, action);
for( j = 0; j < joyAmount; j++ )
{
if( InsideRect( &arrows[j], x, y ) )
{
processed |= 1<<(BUTTON_ARROWS+j);
if( pointerInButtonRect[BUTTON_ARROWS+j] == -1 )
{
pointerInButtonRect[BUTTON_ARROWS+j] = pointerId;
joystickTouchPoints[0+j*2] = x;
joystickTouchPoints[1+j*2] = y;
if( SDL_ANDROID_joysticksAmount > 0 )
{
int xx = (x - arrows[j].x - arrows[j].w / 2) * 65534 / arrows[j].w;
if( xx == 0 ) // Do not allow (0,0) coordinate, when the user touches the joystick - this indicates 'finger up' in OpenArena
xx = 1; // Yeah, maybe I should not include app-specific hacks into the library
int axis = j < 2 ? j*2 : MAX_MULTITOUCH_POINTERS + 4;
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis, xx );
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis + 1, (y - arrows[j].y - arrows[j].h / 2) * 65534 / arrows[j].h );
}
else
{
i = ArrowKeysPressed(x, y);
if( i & ARROW_UP )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(UP), 0 );
if( i & ARROW_DOWN )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(DOWN), 0 );
if( i & ARROW_LEFT )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(LEFT), 0 );
if( i & ARROW_RIGHT )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(RIGHT), 0 );
oldArrows = i;
}
}
}
}
for( i = 0; i < MAX_BUTTONS; i++ )
{
if( ! buttons[i].h || ! buttons[i].w )
continue;
if( InsideRect( &buttons[i], x, y) )
{
processed |= 1<<i;
if( pointerInButtonRect[i] == -1 )
{
pointerInButtonRect[i] = pointerId;
if( i == BUTTON_TEXT_INPUT )
SDL_ANDROID_ToggleScreenKeyboardTextInput(NULL);
else if( buttonsStayPressedAfterTouch[i] )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_GetKeyboardState(NULL)[buttonKeysyms[i]] == 0 ? SDL_PRESSED : SDL_RELEASED, buttonKeysyms[i], 0 );
else
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, buttonKeysyms[i], 0 );
}
}
}
if( floatingScreenJoystick && !processed && pointerInButtonRect[BUTTON_ARROWS] == -1 )
{
// Center joystick under finger
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD, 1);
arrows[0].x = x - arrows[0].w / 2;
arrows[0].y = y - arrows[0].h / 2;
arrowsDraw[0] = arrowsExtended[0] = arrows[0];
processed |= 1<<BUTTON_ARROWS;
pointerInButtonRect[BUTTON_ARROWS] = pointerId;
joystickTouchPoints[0] = x;
joystickTouchPoints[1] = y;
if( SDL_ANDROID_joysticksAmount > 0 )
{
SDL_ANDROID_MainThreadPushJoystickAxis( 0, 0, 1 ); // Non-zero joystick coordinate
SDL_ANDROID_MainThreadPushJoystickAxis( 0, 1, 0 );
}
}
}
else
if( action == MOUSE_UP )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "touch %03dx%03d ptr %d action %d", x, y, pointerId, action);
for( j = 0; j < joyAmount; j++ )
{
if( pointerInButtonRect[BUTTON_ARROWS+j] == pointerId )
{
processed |= 1<<(BUTTON_ARROWS+j);
pointerInButtonRect[BUTTON_ARROWS+j] = -1;
if( SDL_ANDROID_joysticksAmount > 0 )
{
int axis = j < 2 ? j*2 : MAX_MULTITOUCH_POINTERS + 4;
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis, 0 );
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis + 1, 0 );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT), 0 );
oldArrows = 0;
}
if( floatingScreenJoystick && j == 0 )
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD, 0);
}
}
for( i = 0; i < MAX_BUTTONS; i++ )
{
if( ! buttons[i].h || ! buttons[i].w )
continue;
if( pointerInButtonRect[i] == pointerId )
{
processed |= 1<<i;
pointerInButtonRect[i] = -1;
if( i != BUTTON_TEXT_INPUT && !buttonsStayPressedAfterTouch[i] )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, buttonKeysyms[i], 0 );
}
}
}
else
if( action == MOUSE_MOVE )
{
// Process cases when pointer enters button area (it won't send keypress twice if button already pressed)
int processOtherButtons = 1;
for( i = 0; i < MAX_BUTTONS; i++ )
{
if( buttonsGenerateSdlEvents[i] && pointerInButtonRect[i] == pointerId )
{
processOtherButtons = 0;
break;
}
}
if( processOtherButtons )
{
processed |= SDL_ANDROID_processTouchscreenKeyboard(x, y, MOUSE_DOWN, pointerId);
}
// Process cases when pointer leaves button area
// TODO: huge code size, split it or somehow make it more readable
for( j = 0; j < joyAmount; j++ )
{
if( pointerInButtonRect[BUTTON_ARROWS+j] == pointerId )
{
processed |= 1<<(BUTTON_ARROWS+j);
/*
if( floatingScreenJoystick && j == 0 && ! InsideRect( &arrows[j], x, y ) )
{
int xx = 0, yy = 0;
// A finger moved outside the joystick - move the joystick back under the finger
LineAndRectangleIntersection(x - (arrows[0].x + arrows[0].w / 2), y - (arrows[0].y + arrows[0].h / 2), arrows[0].w, arrows[0].h, &xx, &yy);
arrows[0].x += xx;
arrows[0].y += yy;
arrowsDraw[0] = arrowsExtended[0] = arrows[0];
}
*/
if( ! InsideRect( &arrowsExtended[j], x, y ) && ! floatingScreenJoystick )
{
pointerInButtonRect[BUTTON_ARROWS+j] = -1;
if( SDL_ANDROID_joysticksAmount > 0 )
{
int axis = j < 2 ? j*2 : MAX_MULTITOUCH_POINTERS + 4;
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis, 0 );
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis + 1, 0 );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT), 0 );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT), 0 );
oldArrows = 0;
}
}
else
{
joystickTouchPoints[0+j*2] = x;
joystickTouchPoints[1+j*2] = y;
if( SDL_ANDROID_joysticksAmount > 0 )
{
int axis = j < 2 ? j*2 : MAX_MULTITOUCH_POINTERS + 4;
int xx = (x - arrows[j].x - arrows[j].w / 2) * 65534 / arrows[j].w;
if( xx == 0 ) // Do not allow (0,0) coordinate, when the user touches the joystick - this indicates 'finger up' in OpenArena
xx = 1; // Yeah, maybe I should not include app-specific hacks into the library
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis, xx );
SDL_ANDROID_MainThreadPushJoystickAxis( 0, axis + 1, (y - arrows[j].y - arrows[j].h / 2) * 65534 / arrows[j].h );
}
else
{
i = ArrowKeysPressed(x, y);
if( i != oldArrows )
{
if( oldArrows & ARROW_UP && ! (i & ARROW_UP) )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(UP), 0 );
if( oldArrows & ARROW_DOWN && ! (i & ARROW_DOWN) )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(DOWN), 0 );
if( oldArrows & ARROW_LEFT && ! (i & ARROW_LEFT) )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(LEFT), 0 );
if( oldArrows & ARROW_RIGHT && ! (i & ARROW_RIGHT) )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, SDL_KEY(RIGHT), 0 );
if( i & ARROW_UP )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(UP), 0 );
if( i & ARROW_DOWN )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(DOWN), 0 );
if( i & ARROW_LEFT )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(LEFT), 0 );
if( i & ARROW_RIGHT )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, SDL_KEY(RIGHT), 0 );
}
oldArrows = i;
}
}
}
}
for( i = 0; i < MAX_BUTTONS; i++ )
{
if( ! buttons[i].h || ! buttons[i].w )
continue;
if( pointerInButtonRect[i] == pointerId )
{
processed |= 1<<i;
if( ! InsideRect( &buttons[i], x, y ) && ! buttonsGenerateSdlEvents[i] )
{
pointerInButtonRect[i] = -1;
if( i != BUTTON_TEXT_INPUT )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, buttonKeysyms[i], 0 );
}
}
}
}
for( i = 0; i <= MAX_BUTTONS ; i++ )
if( ( processed & (1<<i) ) && buttonsGenerateSdlEvents[i] )
processed |= TOUCHSCREEN_KEYBOARD_PASS_EVENT_DOWN_TO_SDL;
return processed;
};
void shrinkButtonRect(SDL_Rect s, SDL_Rect * d)
{
int i;
if( !buttonDrawSize )
{
memcpy(d, &s, sizeof(s));
return;
}
d->w = s.w * 2 / (buttonDrawSize+2);
d->h = s.h * 2 / (buttonDrawSize+2);
d->x = s.x + s.w / 2 - d->w / 2;
d->y = s.y + s.h / 2 - d->h / 2;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboard) ( JNIEnv* env, jobject thiz,
jint size, jint drawsize, jint theme, jint _transparency, jint _floatingScreenJoystick )
{
int i, ii;
int nbuttons1row, nbuttons2row;
int _nbuttons = MAX_BUTTONS;
SDL_Rect * r;
// TODO: screenRatio is not used yet
enum { STANDARD_PHONE_SCREEN_HEIGHT = 70 }; // And by "standard phone", I mean my own.
float screenRatio = getenv("DISPLAY_HEIGHT_MM") ? atoi(getenv("DISPLAY_HEIGHT_MM")) / STANDARD_PHONE_SCREEN_HEIGHT : 1.0f;
if( screenRatio < STANDARD_PHONE_SCREEN_HEIGHT )
screenRatio = STANDARD_PHONE_SCREEN_HEIGHT;
touchscreenKeyboardTheme = theme;
// TODO: works for horizontal screen orientation only!
buttonsize = size;
buttonDrawSize = drawsize;
switch(_transparency)
{
case 0: transparency = 32.0f/255.0f; break;
case 1: transparency = 64.0f/255.0f; break;
case 2: transparency = 128.0f/255.0f; break;
case 3: transparency = 192.0f/255.0f; break;
case 4: transparency = 255.0f/255.0f; break;
default: transparency = 192.0f/255.0f; break;
}
// Arrows to the lower-left part of screen
arrows[0].w = SDL_ANDROID_sRealWindowWidth / (size + 3) * 2 / 2;
arrows[0].h = arrows[0].w;
// Move to the screen edge
arrows[0].x = 0;
arrows[0].y = SDL_ANDROID_sRealWindowHeight - arrows[0].h;
arrowsExtended[0].w = arrows[0].w * 2;
arrowsExtended[0].h = arrows[0].h * 2;
arrowsExtended[0].x = arrows[0].x + arrows[0].w / 2 - arrowsExtended[0].w / 2;
arrowsExtended[0].y = arrows[0].y + arrows[0].h / 2 - arrowsExtended[0].h / 2;
arrows[1].w = arrows[0].w;
arrows[1].h = arrows[0].h;
arrows[1].x = SDL_ANDROID_sRealWindowWidth - arrows[1].w;
arrows[1].y = arrows[0].y;
arrowsExtended[1].w = arrows[1].w * 2;
arrowsExtended[1].h = arrows[1].h * 2;
arrowsExtended[1].x = arrows[1].x + arrows[1].w / 2 - arrowsExtended[1].w / 2;
arrowsExtended[1].y = arrows[1].y + arrows[1].h / 2 - arrowsExtended[1].h / 2;
arrows[2].w = arrows[1].w;
arrows[2].h = arrows[1].h;
arrows[2].x = arrows[1].x;
arrows[2].y = arrows[1].y - arrows[1].h;
arrowsExtended[2].w = arrows[2].w * 2;
arrowsExtended[2].h = arrows[2].h * 2;
arrowsExtended[2].x = arrows[2].x + arrows[2].w / 2 - arrowsExtended[2].w / 2;
arrowsExtended[2].y = arrows[2].y + arrows[2].h / 2 - arrowsExtended[2].h / 2;
// Buttons to the lower-right in 2 rows
for(i = 0; i < 3; i++)
for(ii = 0; ii < 2; ii++)
{
// Custom button ordering
int iii = ii + i*2;
buttons[iii].w = SDL_ANDROID_sRealWindowWidth / (size + 3) / 2;
buttons[iii].h = buttons[iii].w;
// Move to the screen edge
buttons[iii].x = SDL_ANDROID_sRealWindowWidth - buttons[iii].w * (ii + 1);
buttons[iii].y = SDL_ANDROID_sRealWindowHeight - buttons[iii].h * (i + 1);
}
if( SDL_ANDROID_joysticksAmount >= 2 )
{
// Move all buttons to center, 5-th and 6-th button will be misplaced, but we don't care much about that.
ii = SDL_ANDROID_sRealWindowWidth / 2 - buttons[0].w;
for(i = 0; i < 6; i++)
buttons[i].x -= ii;
}
buttons[6].x = 0;
buttons[6].y = 0;
buttons[6].w = SDL_ANDROID_sRealWindowHeight/10;
buttons[6].h = SDL_ANDROID_sRealWindowHeight/10;
for( i = 0; i < sizeof(pointerInButtonRect)/sizeof(pointerInButtonRect[0]); i++ )
pointerInButtonRect[i] = -1;
for( i = 0; i < MAX_JOYSTICKS; i++ )
shrinkButtonRect(arrows[i], &arrowsDraw[i]);
for( i = 0; i < MAX_BUTTONS; i++ )
shrinkButtonRect(buttons[i], &buttonsDraw[i]);
for( i = 0; i < SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM; i++ )
SDL_ANDROID_GetScreenKeyboardButtonPos(i, &hiddenButtons[i]);
floatingScreenJoystick = _floatingScreenJoystick;
if( floatingScreenJoystick )
{
arrowsExtended[0] = arrows[0] = arrowsDraw[0];
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD, 0);
}
};
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetTouchscreenKeyboardUsed) ( JNIEnv* env, jobject thiz)
{
SDL_ANDROID_isTouchscreenKeyboardUsed = 1;
}
void SDL_ANDROID_DrawMouseCursor(int x, int y, int size, float alpha)
{
SDL_Rect r;
// I've failed with size calculations, so leaving it as-is
r.x = x - MOUSE_POINTER_X;
r.y = y - MOUSE_POINTER_Y;
r.w = MOUSE_POINTER_W;
r.h = MOUSE_POINTER_H;
beginDrawingTex();
drawCharTex( &mousePointer, NULL, &r, 1.0f, 1.0f, 1.0f, alpha );
endDrawingTex();
}
static int
power_of_2(int input)
{
int value = 1;
while (value < input) {
value <<= 1;
}
return value;
}
static int setupScreenKeyboardButtonTexture( GLTexture_t * data, Uint8 * charBuf )
{
int w, h, format, bpp;
int texture_w, texture_h;
memcpy(&w, charBuf, sizeof(int));
memcpy(&h, charBuf + sizeof(int), sizeof(int));
memcpy(&format, charBuf + 2*sizeof(int), sizeof(int));
w = ntohl(w);
h = ntohl(h);
format = ntohl(format);
bpp = 2;
if(format == 2)
bpp = 4;
texture_w = power_of_2(w);
texture_h = power_of_2(h);
data->w = w;
data->h = h;
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &data->id);
glBindTexture(GL_TEXTURE_2D, data->id);
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "On-screen keyboard generated OpenGL texture ID %d", data->id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA,
bpp == 4 ? GL_UNSIGNED_BYTE : (format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1), NULL);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA,
bpp == 4 ? GL_UNSIGNED_BYTE : (format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1),
charBuf + 3*sizeof(int) );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( SDL_ANDROID_VideoLinearFilter )
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glDisable(GL_TEXTURE_2D);
return 3*sizeof(int) + w * h * bpp;
}
static int setupScreenKeyboardButtonLegacy( int buttonID, Uint8 * charBuf )
{
GLTexture_t * data = NULL;
if( buttonID < 5 )
data = &(arrowImages[buttonID]);
else if( buttonID < 9 )
data = &(buttonAutoFireImages[buttonID-5]);
else if( buttonID < 23 )
data = &(buttonImages[buttonID-9]);
else if( buttonID == 23 )
data = &mousePointer;
else if( buttonID < 28 )
data = &(arrowImages[buttonID - 24 + 5]); // Diagonal arrows
else // Error, array too big
return 12; // Return value bigger than zero to iterate it
return setupScreenKeyboardButtonTexture(data, charBuf);
}
static int setupScreenKeyboardButtonSun( int buttonID, Uint8 * charBuf )
{
GLTexture_t * data = NULL;
int i, ret;
if( buttonID == 0 )
data = &(arrowImages[0]);
if( buttonID >= 1 && buttonID <= 4 )
data = &(buttonImages[buttonID-1]);
if( buttonID >= 5 && buttonID <= 8 )
data = &(buttonImages[4+(buttonID-5)*2]);
if( buttonID == 9 )
data = &mousePointer;
if( buttonID == 10 )
data = &(arrowImages[10]);
if( buttonID == 11 )
data = &(arrowImages[11]);
else if( buttonID > 11 ) // Error, array too big
return 12; // Return value bigger than zero to iterate it
ret = setupScreenKeyboardButtonTexture(data, charBuf);
for( i = 1; i <=4; i++ )
arrowImages[i] = arrowImages[0];
for( i = 2; i < MAX_BUTTONS; i++ )
buttonImages[i * 2 + 1] = buttonImages[i * 2];
for( i = 0; i < MAX_BUTTONS_AUTOFIRE*2; i++ )
buttonAutoFireImages[i] = arrowImages[0];
buttonImages[BUTTON_TEXT_INPUT*2] = buttonImages[10];
buttonImages[BUTTON_TEXT_INPUT*2+1] = buttonImages[10];
return ret;
}
static int setupScreenKeyboardButtonDualShock( int buttonID, Uint8 * charBuf )
{
GLTexture_t * data = NULL;
int i, ret;
if( buttonID == 0 )
data = &(arrowImages[0]);
if( buttonID >= 1 && buttonID <= 4 )
data = &(buttonImages[buttonID-1]);
if( buttonID >= 5 && buttonID <= 8 )
data = &(buttonImages[4+(buttonID-5)*2]);
if( buttonID == 9 )
data = &mousePointer;
if( buttonID == 10 )
data = &(arrowImages[5]);
if( buttonID == 11 )
data = &(arrowImages[6]);
else if( buttonID > 11 ) // Error, array too big
return 12; // Return value bigger than zero to iterate it
ret = setupScreenKeyboardButtonTexture(data, charBuf);
for( i = 1; i <=4; i++ )
arrowImages[i] = arrowImages[0];
for( i = 2; i < MAX_BUTTONS; i++ )
buttonImages[i * 2 + 1] = buttonImages[i * 2];
for( i = 0; i < MAX_BUTTONS_AUTOFIRE*2; i++ )
buttonAutoFireImages[i] = arrowImages[0];
buttonImages[BUTTON_TEXT_INPUT*2] = arrowImages[5];
buttonImages[BUTTON_TEXT_INPUT*2+1] = arrowImages[5];
return ret;
}
static int setupScreenKeyboardButton( int buttonID, Uint8 * charBuf, int count )
{
if( count == 24 || count == 28)
{
themeType = 0;
return setupScreenKeyboardButtonLegacy(buttonID, charBuf);
}
else if( count == 10)
{
themeType = 1;
return setupScreenKeyboardButtonSun(buttonID, charBuf);
}
else if( count == 12)
{
themeType = 2;
return setupScreenKeyboardButtonDualShock(buttonID, charBuf);
}
else
{
__android_log_print(ANDROID_LOG_FATAL, "libSDL", "On-screen keyboard buton img count = %d, should be 10 or 24 or 28", count);
return 12; // Return value bigger than zero to iterate it
}
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboardButtons) ( JNIEnv* env, jobject thiz, jbyteArray charBufJava )
{
jboolean isCopy = JNI_TRUE;
int len = (*env)->GetArrayLength(env, charBufJava);
Uint8 * charBuf = (Uint8 *) (*env)->GetByteArrayElements(env, charBufJava, &isCopy);
int but, pos, count;
memcpy(&count, charBuf, sizeof(int));
count = ntohl(count);
for( but = 0, pos = sizeof(int); pos < len; but ++ )
pos += setupScreenKeyboardButton( but, charBuf + pos, count );
(*env)->ReleaseByteArrayElements(env, charBufJava, (jbyte *)charBuf, 0);
}
JNIEXPORT jint JNICALL
JAVA_EXPORT_NAME(Settings_nativeGetKeymapKeyScreenKb) (JNIEnv* env, jobject thiz, jint keynum)
{
if( keynum < 0 || keynum > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 + 4 )
return SDL_KEY(UNKNOWN);
if( keynum <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 )
return SDL_ANDROID_GetScreenKeyboardButtonKey(keynum + SDL_ANDROID_SCREENKEYBOARD_BUTTON_0);
return SDL_KEY(UNKNOWN);
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetKeymapKeyScreenKb) (JNIEnv* env, jobject thiz, jint keynum, jint key)
{
if( keynum < 0 || keynum > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 + 4 )
return;
if( keynum <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 )
SDL_ANDROID_SetScreenKeyboardButtonKey(keynum + SDL_ANDROID_SCREENKEYBOARD_BUTTON_0, key);
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetScreenKbKeyUsed) (JNIEnv* env, jobject thiz, jint keynum, jint used)
{
SDL_Rect rect = {0, 0, 0, 0};
int key = -1;
if( keynum == 0 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD;
if( keynum == 1 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT;
if( keynum - 2 >= 0 && keynum - 2 <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 )
key = keynum - 2 + SDL_ANDROID_SCREENKEYBOARD_BUTTON_0;
if( keynum == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD2 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD2;
if( keynum == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3;
if( key >= 0 && !used )
SDL_ANDROID_SetScreenKeyboardButtonPos(key, &rect);
}
int SDL_ANDROID_SetScreenKeyboardButtonPos(int buttonId, SDL_Rect * pos)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM || ! pos )
return 0;
if( buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD && buttonId <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3 )
{
int i = buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD;
arrows[i] = *pos;
arrowsExtended[i].w = arrows[i].w * 2;
arrowsExtended[i].h = arrows[i].h * 2;
arrowsExtended[i].x = arrows[i].x + arrows[i].w / 2 - arrowsExtended[i].w / 2;
arrowsExtended[i].y = arrows[i].y + arrows[i].h / 2 - arrowsExtended[i].h / 2;
shrinkButtonRect(arrows[i], &arrowsDraw[i]);
}
else
{
int i = buttonId;
buttons[i] = *pos;
shrinkButtonRect(buttons[i], &buttonsDraw[i]);
}
return 1;
};
int SDLCALL SDL_ANDROID_SetScreenKeyboardButtonImagePos(int buttonId, SDL_Rect * pos)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM || ! pos )
return 0;
if( buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD && buttonId <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3 )
arrowsDraw[buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD] = *pos;
else
buttonsDraw[buttonId] = *pos;
return 1;
}
int SDL_ANDROID_GetScreenKeyboardButtonPos(int buttonId, SDL_Rect * pos)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM || ! pos )
return 0;
if( buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD && buttonId <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3 )
{
*pos = arrows[buttonId - SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD];
}
else
{
*pos = buttons[buttonId];
}
return 1;
};
int SDL_ANDROID_SetScreenKeyboardButtonKey(int buttonId, SDLKey key)
{
if( buttonId < 0 || buttonId > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 || ! key )
return 0;
buttonKeysyms[buttonId] = key;
return 1;
};
SDLKey SDL_ANDROID_GetScreenKeyboardButtonKey(int buttonId)
{
if( buttonId < 0 || buttonId > SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 )
return SDLK_UNKNOWN;
return buttonKeysyms[buttonId];
};
int SDL_ANDROID_SetScreenKeyboardShown(int shown)
{
touchscreenKeyboardShown = shown;
};
int SDL_ANDROID_GetScreenKeyboardShown(void)
{
return touchscreenKeyboardShown;
};
int SDL_ANDROID_SetScreenKeyboardButtonShown(int buttonId, int shown)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM )
return 0;
//__android_log_print(ANDROID_LOG_INFO, "libsdl", "SDL_ANDROID_SetScreenKeyboardButtonShown: button %d shown %d", buttonId, shown);
if( !shown && SDL_ANDROID_GetScreenKeyboardButtonShown(buttonId) )
{
SDL_Rect pos = { 0, 0, 0, 0 };
SDL_ANDROID_GetScreenKeyboardButtonPos(buttonId, &hiddenButtons[buttonId]);
SDL_ANDROID_SetScreenKeyboardButtonPos(buttonId, &pos);
}
if( shown && !SDL_ANDROID_GetScreenKeyboardButtonShown(buttonId) )
SDL_ANDROID_SetScreenKeyboardButtonPos(buttonId, &hiddenButtons[buttonId]);
return 1;
};
int SDL_ANDROID_GetScreenKeyboardButtonShown(int buttonId)
{
SDL_Rect pos;
if( !SDL_ANDROID_GetScreenKeyboardButtonPos(buttonId, &pos) )
return 0;
return pos.h > 0 && pos.w > 0;
};
int SDL_ANDROID_GetScreenKeyboardSize(void)
{
return buttonsize;
};
int SDL_ANDROID_ToggleScreenKeyboardTextInput(const char * previousText)
{
static char textIn[255];
if( previousText == NULL )
previousText = "";
strncpy(textIn, previousText, sizeof(textIn));
textIn[sizeof(textIn)-1] = 0;
SDL_ANDROID_CallJavaShowScreenKeyboard(textIn, NULL, 0);
return 1;
};
int SDLCALL SDL_ANDROID_GetScreenKeyboardTextInput(char * textBuf, int textBufSize)
{
SDL_ANDROID_CallJavaShowScreenKeyboard(textBuf, textBuf, textBufSize);
return 1;
};
int SDLCALL SDL_HasScreenKeyboardSupport(void *unused)
{
return 1;
}
// SDL2 compatibility
int SDLCALL SDL_ShowScreenKeyboard(void *unused)
{
return SDL_ANDROID_ToggleScreenKeyboardTextInput(NULL);
}
int SDLCALL SDL_HideScreenKeyboard(void *unused)
{
SDL_ANDROID_CallJavaHideScreenKeyboard();
return 1;
}
int SDLCALL SDL_IsScreenKeyboardShown(void *unused)
{
return SDL_ANDROID_IsScreenKeyboardShown();
}
int SDLCALL SDL_ToggleScreenKeyboard(void *unused)
{
if( SDL_IsScreenKeyboardShown(NULL) )
return SDL_HideScreenKeyboard(NULL);
else
return SDL_ShowScreenKeyboard(NULL);
}
int SDLCALL SDL_ANDROID_SetScreenKeyboardButtonGenerateTouchEvents(int buttonId, int generateEvents)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM )
return 0;
buttonsGenerateSdlEvents[buttonId] = generateEvents;
return 1;
}
int SDLCALL SDL_ANDROID_SetScreenKeyboardButtonStayPressedAfterTouch(int buttonId, int stayPressed)
{
if( buttonId < 0 || buttonId >= SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM )
return 0;
buttonsStayPressedAfterTouch[buttonId] = stayPressed;
return 1;
}
int SDLCALL SDL_ANDROID_SetScreenKeyboardTransparency(int alpha)
{
transparency = (float)alpha / 255.0f;
}
static int ScreenKbRedefinedByUser = 0;
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetScreenKbKeyLayout) (JNIEnv* env, jobject thiz, jint keynum, jint x1, jint y1, jint x2, jint y2)
{
SDL_Rect rect = {x1, y1, x2-x1, y2-y1};
int key = -1;
// Why didn't I use consistent IDs between Java and C code?
if( keynum == 0 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD;
if( keynum == 1 )
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT;
if( keynum - 2 >= 0 && keynum - 2 <= SDL_ANDROID_SCREENKEYBOARD_BUTTON_5 - SDL_ANDROID_SCREENKEYBOARD_BUTTON_0 )
key = keynum - 2 + SDL_ANDROID_SCREENKEYBOARD_BUTTON_0;
if( keynum == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD2 ) // This one is consistent by chance
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD2;
if( keynum == SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3 ) // This one is consistent by chance
key = SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD3;
if( key >= 0 )
{
ScreenKbRedefinedByUser = 1;
SDL_ANDROID_SetScreenKeyboardButtonPos(key, &rect);
}
}
int SDL_ANDROID_GetScreenKeyboardRedefinedByUser()
{
return ScreenKbRedefinedByUser;
}
int SDL_ANDROID_SetScreenKeyboardHintMesage(const char * hint)
{
SDL_ANDROID_CallJavaSetScreenKeyboardHintMessage(hint);
return 1;
}
extern DECLSPEC int SDLCALL SDL_ANDROID_SetScreenKeyboardFloatingJoystick(int enabled)
{
floatingScreenJoystick = enabled;
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_DPAD, 0);
return 1;
}
extern DECLSPEC int SDL_ANDROID_ScreenKeyboardUpdateToNewVideoMode(int oldx, int oldy, int newx, int newy)
{
int i;
for( i = 0; i < SDL_ANDROID_SCREENKEYBOARD_BUTTON_NUM; i++ )
{
SDL_Rect pos, pos2;
SDL_ANDROID_GetScreenKeyboardButtonPos(i, &pos);
pos2.x = pos.x * newx / oldx;
pos2.y = pos.y * newy / oldy;
pos2.w = (pos.x + pos.w) * newx / oldx - pos2.x;
pos2.h = (pos.y + pos.h) * newy / oldy - pos2.y;
SDL_ANDROID_SetScreenKeyboardButtonPos(i, &pos2);
}
}
/**
* @brief Dumps OpenGL state for debugging - typically every capability set with glEnable().
*/
void R_DumpOpenGlState(void)
{
#define CAPABILITY( X ) {GL_ ## X, # X}
/* List taken from here: http://www.khronos.org/opengles/sdk/1.1/docs/man/glIsEnabled.xml */
const struct { GLenum idx; const char * text; } openGLCaps[] = {
CAPABILITY(ALPHA_TEST),
CAPABILITY(BLEND),
CAPABILITY(COLOR_ARRAY),
CAPABILITY(COLOR_LOGIC_OP),
CAPABILITY(COLOR_MATERIAL),
CAPABILITY(CULL_FACE),
CAPABILITY(DEPTH_TEST),
CAPABILITY(DITHER),
CAPABILITY(FOG),
CAPABILITY(LIGHTING),
CAPABILITY(LINE_SMOOTH),
CAPABILITY(MULTISAMPLE),
CAPABILITY(NORMAL_ARRAY),
CAPABILITY(NORMALIZE),
CAPABILITY(POINT_SMOOTH),
CAPABILITY(POLYGON_OFFSET_FILL),
CAPABILITY(RESCALE_NORMAL),
CAPABILITY(SAMPLE_ALPHA_TO_COVERAGE),
CAPABILITY(SAMPLE_ALPHA_TO_ONE),
CAPABILITY(SAMPLE_COVERAGE),
CAPABILITY(SCISSOR_TEST),
CAPABILITY(STENCIL_TEST),
CAPABILITY(VERTEX_ARRAY)
};
#undef CAPABILITY
char s[1024] = "";
GLint i;
GLint maxTexUnits = 0;
GLint activeTexUnit = 0;
GLint activeClientTexUnit = 0;
GLint activeTexId = 0;
GLfloat texEnvMode = 0;
const char * texEnvModeStr = "UNKNOWN";
GLfloat color[4];
for (i = 0; i < sizeof(openGLCaps) / sizeof(openGLCaps[0]); i++) {
if (glIsEnabled(openGLCaps[i].idx)) {
strcat(s, openGLCaps[i].text);
strcat(s, " ");
}
}
glGetFloatv(GL_CURRENT_COLOR, color);
__android_log_print(ANDROID_LOG_INFO, "libSDL", "OpenGL enabled caps: %s color %f %f %f %f \n", s, color[0], color[1], color[2], color[3]);
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexUnit);
glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &activeClientTexUnit);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTexUnits);
for (i = GL_TEXTURE0; i < GL_TEXTURE0 + maxTexUnits; i++) {
glActiveTexture(i);
glClientActiveTexture(i);
strcpy(s, "");
if (glIsEnabled (GL_TEXTURE_2D))
strcat(s, "enabled, ");
if (glIsEnabled (GL_TEXTURE_COORD_ARRAY))
strcat(s, "with texcoord array, ");
if (i == activeTexUnit)
strcat(s, "active, ");
if (i == activeClientTexUnit)
strcat(s, "client active, ");
glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexId);
glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texEnvMode);
if (fabs(texEnvMode - GL_ADD) < 0.1f)
texEnvModeStr = "ADD";
if (fabs(texEnvMode - GL_MODULATE) < 0.1f)
texEnvModeStr = "MODULATE";
if (fabs(texEnvMode - GL_DECAL) < 0.1f)
texEnvModeStr = "DECAL";
if (fabs(texEnvMode - GL_BLEND) < 0.1f)
texEnvModeStr = "BLEND";
if (fabs(texEnvMode - GL_REPLACE) < 0.1f)
texEnvModeStr = "REPLACE";
if (fabs(texEnvMode - GL_COMBINE) < 0.1f)
texEnvModeStr = "COMBINE";
__android_log_print(ANDROID_LOG_INFO, "libSDL", "Texunit: %d texID %d %s texEnv mode %s\n", i - GL_TEXTURE0, activeTexId, s, texEnvModeStr);
}
glActiveTexture(activeTexUnit);
glClientActiveTexture(activeClientTexUnit);
}