335 lines
10 KiB
C
335 lines
10 KiB
C
/*
|
|
SDL - Simple DirectMedia Layer
|
|
Copyright (C) 1997-2009 Sam Lantinga
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
Sam Lantinga
|
|
slouken@libsdl.org
|
|
*/
|
|
#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 "SDL_config.h"
|
|
|
|
#include "SDL_version.h"
|
|
|
|
#include "SDL_androidvideo.h"
|
|
#include "SDL_androidinput.h"
|
|
#include "jniwrapperstuff.h"
|
|
|
|
#include "touchscreenfont.h"
|
|
|
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
|
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
|
|
|
static int isTouchscreenKeyboardUsed = 0;
|
|
|
|
enum {
|
|
FONT_LEFT = 0, FONT_RIGHT = 1, FONT_UP = 2, FONT_DOWN = 3,
|
|
FONT_BTN1 = 4, FONT_BTN2 = 5, FONT_BTN3 = 6, FONT_BTN4 = 7
|
|
};
|
|
|
|
enum { MAX_BUTTONS = 4 } ; // Max amount of custom buttons
|
|
|
|
static GLshort fontGL[sizeof(font)/sizeof(font[0])][FONT_MAX_LINES_PER_CHAR * 4 + 1];
|
|
enum { FONT_CHAR_LINES_COUNT = FONT_MAX_LINES_PER_CHAR * 4 };
|
|
|
|
static SDL_Rect arrows, buttons[MAX_BUTTONS];
|
|
static int nbuttons;
|
|
static SDLKey buttonKeysyms[MAX_BUTTONS] = {
|
|
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_KEYCODE_0)),
|
|
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_KEYCODE_1)),
|
|
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_KEYCODE_2)),
|
|
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_KEYCODE_3))
|
|
};
|
|
|
|
enum { ARROW_LEFT = 1, ARROW_RIGHT = 2, ARROW_UP = 4, ARROW_DOWN = 8 };
|
|
static int oldArrows = 0;
|
|
static int Button1AutoFire = 0, Button1AutoFireX = 0;
|
|
|
|
static SDL_Rect * OldCoords[MAX_MULTITOUCH_POINTERS] = { NULL };
|
|
|
|
static const float inv255f = 1.0f / 255.0f;
|
|
|
|
// Should be called on each char of font before drawing
|
|
static void prepareFontChar(int idx, int w, int h)
|
|
{
|
|
int i, count = 0;
|
|
float fw = (float) w / 255.0f;
|
|
float fh = (float) h / 255.0f;
|
|
|
|
//for( idx = 0; idx < sizeof(font)/sizeof(font[0]); idx++ )
|
|
{
|
|
for( i = 0; i < FONT_MAX_LINES_PER_CHAR; i++ )
|
|
if( font[idx][i].x1 == 0 && font[idx][i].y1 == 0 &&
|
|
font[idx][i].x2 == 0 && font[idx][i].y2 == 0 )
|
|
break;
|
|
count = i;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
fontGL[idx][4*i+0] = (GLshort)(((int)font[idx][i].x1 - 128) * fw);
|
|
fontGL[idx][4*i+1] = (GLshort)(((int)font[idx][i].y1 - 128) * fh);
|
|
fontGL[idx][4*i+2] = (GLshort)(((int)font[idx][i].x2 - 128) * fw);
|
|
fontGL[idx][4*i+3] = (GLshort)(((int)font[idx][i].y2 - 128) * fh);
|
|
}
|
|
fontGL[idx][FONT_CHAR_LINES_COUNT] = count*2;
|
|
}
|
|
};
|
|
|
|
// Draws a char on screen using embedded line font, (x, y) are center of char, not upper-left corner
|
|
// TODO: use SDL 1.3 renderer routines? It will not be pixel-aligned then, if the screen is resized
|
|
static inline void drawChar(int idx, Uint16 x, Uint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
|
{
|
|
glColor4f((GLfloat) r * inv255f, (GLfloat) g * inv255f, (GLfloat) b * inv255f, (GLfloat) a * inv255f);
|
|
|
|
glPushMatrix();
|
|
glTranslatex( x, y, 0 );
|
|
glVertexPointer(2, GL_SHORT, 0, fontGL[idx]);
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glDrawArrays(GL_LINE_STRIP, 0, fontGL[idx][FONT_CHAR_LINES_COUNT]);
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glPopMatrix();
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
JAVA_EXPORT_NAME(Settings_nativeSetupScreenKeyboard) ( JNIEnv* env, jobject thiz, jint size, jint _nbuttons )
|
|
{
|
|
int i;
|
|
nbuttons = _nbuttons;
|
|
if( nbuttons > MAX_BUTTONS )
|
|
nbuttons = MAX_BUTTONS;
|
|
// TODO: works for horizontal screen orientation only!
|
|
// TODO: configurable keyboard size
|
|
|
|
// Arrows to the lower-left part of screen
|
|
arrows.x = 0;
|
|
arrows.w = SDL_ANDROID_sWindowWidth / 2;
|
|
arrows.h = arrows.w;
|
|
arrows.y = SDL_ANDROID_sWindowHeight - arrows.h;
|
|
prepareFontChar(FONT_LEFT, arrows.w / 2, arrows.h / 2);
|
|
prepareFontChar(FONT_RIGHT, arrows.w / 2, arrows.h / 2);
|
|
prepareFontChar(FONT_UP, arrows.w / 2, arrows.h / 2);
|
|
prepareFontChar(FONT_DOWN, arrows.w / 2, arrows.h / 2);
|
|
|
|
// Main button to the lower-right
|
|
buttons[0].x = SDL_ANDROID_sWindowWidth / 2;
|
|
buttons[0].w = SDL_ANDROID_sWindowWidth / 2;
|
|
buttons[0].y = SDL_ANDROID_sWindowHeight / 2;
|
|
buttons[0].h = SDL_ANDROID_sWindowHeight / 2;
|
|
prepareFontChar(FONT_BTN1, MIN(buttons[0].h, buttons[0].w) / 2, MIN(buttons[0].h, buttons[0].w) / 2);
|
|
|
|
// Row of secondary buttons to the upper-right
|
|
for( i = 1; i < nbuttons; i++ )
|
|
{
|
|
buttons[i].y = 0;
|
|
buttons[i].h = SDL_ANDROID_sWindowHeight / 2;
|
|
buttons[i].w = (SDL_ANDROID_sWindowWidth / 2) / (nbuttons - 1);
|
|
buttons[i].x = SDL_ANDROID_sWindowWidth / 2 + buttons[i].w * (i - 1);
|
|
prepareFontChar(FONT_BTN1 + i, MIN(buttons[i].h, buttons[i].w) / 2, MIN(buttons[i].h, buttons[i].w) / 2);
|
|
}
|
|
};
|
|
|
|
int SDL_android_drawTouchscreenKeyboard()
|
|
{
|
|
int i;
|
|
if( !isTouchscreenKeyboardUsed )
|
|
return 0;
|
|
// Draw arrow keys
|
|
drawChar( FONT_LEFT, arrows.x + arrows.w / 4, arrows.y + arrows.h / 2,
|
|
255, 255, SDL_GetKeyboardState(NULL)[SDL_KEY(LEFT)] ? 255 : 0, 128 );
|
|
drawChar( FONT_RIGHT, arrows.x + arrows.w / 4 * 3, arrows.y + arrows.h / 2,
|
|
255, 255, SDL_GetKeyboardState(NULL)[SDL_KEY(RIGHT)] ? 255 : 0, 128 );
|
|
drawChar( FONT_UP, arrows.x + arrows.w / 2, arrows.y + arrows.h / 4,
|
|
255, 255, SDL_GetKeyboardState(NULL)[SDL_KEY(UP)] ? 255 : 0, 128 );
|
|
drawChar( FONT_DOWN, arrows.x + arrows.w / 2, arrows.y + arrows.h / 4 * 3,
|
|
255, 255, SDL_GetKeyboardState(NULL)[SDL_KEY(DOWN)] ? 255 : 0, 128 );
|
|
|
|
// Draw buttons
|
|
for( i = 0; i < nbuttons; i++ )
|
|
{
|
|
drawChar( FONT_BTN1 + i, buttons[i].x + buttons[i].w / 2, buttons[i].y + buttons[i].h / 2,
|
|
( i == 0 && Button1AutoFire ) ? 0 : 255, 255, SDL_GetKeyboardState(NULL)[buttonKeysyms[i]] ? 255 : 0, 128 );
|
|
}
|
|
return 1;
|
|
};
|
|
|
|
static inline int ArrowKeysPressed(int x, int y)
|
|
{
|
|
int ret = 0, dx, dy;
|
|
/*
|
|
if( !InsideRect( &arrows, x, y ) )
|
|
return 0;
|
|
*/
|
|
dx = x - arrows.x - arrows.w / 2;
|
|
dy = y - arrows.y - arrows.h / 2;
|
|
// Single arrow key pressed
|
|
if( abs(dx / 2) <= abs(dy) )
|
|
{
|
|
if( dy > 0 )
|
|
ret |= ARROW_UP;
|
|
else
|
|
ret |= ARROW_DOWN;
|
|
}
|
|
else
|
|
if( abs(dy / 2) <= abs(dx) )
|
|
{
|
|
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;
|
|
}
|
|
|
|
int SDL_android_processTouchscreenKeyboard(int x, int y, int action, int pointerId)
|
|
{
|
|
int i;
|
|
SDL_keysym keysym;
|
|
|
|
if( !isTouchscreenKeyboardUsed )
|
|
return 0;
|
|
|
|
if( action == MOUSE_DOWN )
|
|
{
|
|
if( InsideRect( &arrows, x, y ) )
|
|
{
|
|
OldCoords[pointerId] = &arrows;
|
|
i = ArrowKeysPressed(x, y);
|
|
if( i & ARROW_UP )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(UP), &keysym) );
|
|
if( i & ARROW_DOWN )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(DOWN), &keysym) );
|
|
if( i & ARROW_LEFT )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(LEFT), &keysym) );
|
|
if( i & ARROW_RIGHT )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(RIGHT), &keysym) );
|
|
oldArrows = i;
|
|
return 1;
|
|
}
|
|
|
|
for( i = 0; i < nbuttons; i++ )
|
|
{
|
|
if( InsideRect( &buttons[i], x, y) )
|
|
{
|
|
OldCoords[pointerId] = &buttons[i];
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym(buttonKeysyms[i], &keysym) );
|
|
if( i == 0 )
|
|
{
|
|
Button1AutoFireX = x;
|
|
Button1AutoFire = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if( action == MOUSE_UP )
|
|
{
|
|
if( OldCoords[pointerId] == &arrows )
|
|
{
|
|
OldCoords[pointerId] = NULL;
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(UP), &keysym) );
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(DOWN), &keysym) );
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(LEFT), &keysym) );
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(RIGHT), &keysym) );
|
|
oldArrows = 0;
|
|
return 1;
|
|
}
|
|
for( i = 0; i < nbuttons; i++ )
|
|
{
|
|
if( OldCoords[pointerId] == &buttons[i] )
|
|
{
|
|
if( ! ( i == 0 && Button1AutoFire ) )
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym(buttonKeysyms[i] ,&keysym) );
|
|
OldCoords[pointerId] = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if( action == MOUSE_MOVE )
|
|
{
|
|
if( OldCoords[pointerId] && !InsideRect(OldCoords[pointerId], x, y) )
|
|
{
|
|
SDL_android_processTouchscreenKeyboard(x, y, MOUSE_UP, pointerId);
|
|
return SDL_android_processTouchscreenKeyboard(x, y, MOUSE_DOWN, pointerId);
|
|
}
|
|
else
|
|
if( OldCoords[pointerId] == &arrows )
|
|
{
|
|
i = ArrowKeysPressed(x, y);
|
|
if( i == oldArrows )
|
|
return 1;
|
|
if( oldArrows & ARROW_UP && ! (i & ARROW_UP) )
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(UP), &keysym) );
|
|
if( oldArrows & ARROW_DOWN && ! (i & ARROW_DOWN) )
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(DOWN), &keysym) );
|
|
if( oldArrows & ARROW_LEFT && ! (i & ARROW_LEFT) )
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(LEFT), &keysym) );
|
|
if( oldArrows & ARROW_RIGHT && ! (i & ARROW_RIGHT) )
|
|
SDL_SendKeyboardKey( SDL_RELEASED, GetKeysym( SDL_KEY(RIGHT), &keysym) );
|
|
if( i & ARROW_UP )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(UP), &keysym) );
|
|
if( i & ARROW_DOWN )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(DOWN), &keysym) );
|
|
if( i & ARROW_LEFT )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(LEFT), &keysym) );
|
|
if( i & ARROW_RIGHT )
|
|
SDL_SendKeyboardKey( SDL_PRESSED, GetKeysym( SDL_KEY(RIGHT), &keysym) );
|
|
oldArrows = i;
|
|
}
|
|
else
|
|
if( OldCoords[pointerId] == &buttons[0] )
|
|
Button1AutoFire = abs(Button1AutoFireX - x) > buttons[0].w / 2;
|
|
|
|
if( OldCoords[pointerId] )
|
|
return 1;
|
|
|
|
return SDL_android_processTouchscreenKeyboard(x, y, MOUSE_DOWN, pointerId);
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
|
|
JNIEXPORT void JNICALL
|
|
JAVA_EXPORT_NAME(Settings_nativeSetTouchscreenKeyboardUsed) ( JNIEnv* env, jobject thiz)
|
|
{
|
|
isTouchscreenKeyboardUsed = 1;
|
|
}
|
|
|