Files
commandergenius/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c

2102 lines
66 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 "SDL_config.h"
#include "SDL_version.h"
#include "SDL_mutex.h"
#include "SDL_events.h"
#if SDL_VERSION_ATLEAST(1,3,0)
#include "SDL_touch.h"
#include "../../events/SDL_touch_c.h"
#endif
#include "../SDL_sysvideo.h"
#include "SDL_androidvideo.h"
#include "SDL_androidinput.h"
#include "SDL_screenkeyboard.h"
#include "jniwrapperstuff.h"
#include "atan2i.h"
static SDLKey SDL_android_keymap[KEYCODE_LAST+1];
static inline SDL_scancode TranslateKey(int scancode)
{
if ( scancode >= SDL_arraysize(SDL_android_keymap) )
scancode = KEYCODE_UNKNOWN;
return SDL_android_keymap[scancode];
}
static int isTrackballUsed = 0;
static int isMouseUsed = 0;
enum { RIGHT_CLICK_NONE = 0, RIGHT_CLICK_WITH_MULTITOUCH = 1, RIGHT_CLICK_WITH_PRESSURE = 2,
RIGHT_CLICK_WITH_KEY = 3, RIGHT_CLICK_WITH_TIMEOUT = 4 };
enum { LEFT_CLICK_NORMAL = 0, LEFT_CLICK_NEAR_CURSOR = 1, LEFT_CLICK_WITH_MULTITOUCH = 2, LEFT_CLICK_WITH_PRESSURE = 3,
LEFT_CLICK_WITH_KEY = 4, LEFT_CLICK_WITH_TIMEOUT = 5, LEFT_CLICK_WITH_TAP = 6, LEFT_CLICK_WITH_TAP_OR_TIMEOUT = 7 };
static int leftClickMethod = LEFT_CLICK_NORMAL;
static int rightClickMethod = RIGHT_CLICK_NONE;
static int leftClickKey = KEYCODE_DPAD_CENTER;
static int rightClickKey = KEYCODE_MENU;
int SDL_ANDROID_ShowScreenUnderFinger = ZOOM_NONE;
SDL_Rect SDL_ANDROID_ShowScreenUnderFingerRect = {0, 0, 0, 0}, SDL_ANDROID_ShowScreenUnderFingerRectSrc = {0, 0, 0, 0};
static int moveMouseWithArrowKeys = 0;
static int clickMouseWithDpadCenter = 0;
static int moveMouseWithKbSpeed = 0;
static int moveMouseWithKbAccel = 0;
static int moveMouseWithKbX = -1, moveMouseWithKbY = -1;
static int moveMouseWithKbSpeedX = 0, moveMouseWithKbSpeedY = 0;
static int moveMouseWithKbAccelX = 0, moveMouseWithKbAccelY = 0;
static int moveMouseWithKbAccelUpdateNeeded = 0;
static int maxForce = 0;
static int maxRadius = 0;
int SDL_ANDROID_isJoystickUsed = 0;
static int isMultitouchUsed = 0;
SDL_Joystick *SDL_ANDROID_CurrentJoysticks[MAX_MULTITOUCH_POINTERS+1] = {NULL};
static int TrackballDampening = 0; // in milliseconds
static Uint32 lastTrackballAction = 0;
enum { TOUCH_PTR_UP = 0, TOUCH_PTR_MOUSE = 1, TOUCH_PTR_SCREENKB = 2 };
static int touchPointers[MAX_MULTITOUCH_POINTERS] = {0};
static int firstMousePointerId = -1;
enum { MAX_MULTITOUCH_GESTURES = 4 };
static int multitouchGestureKeycode[MAX_MULTITOUCH_GESTURES] = {
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_6)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_7)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_8)),
SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_9))
};
static int multitouchGestureKeyPressed[MAX_MULTITOUCH_GESTURES] = { 0, 0, 0, 0 };
static int multitouchGestureSensitivity = 0;
static int multitouchGestureDist = -1;
static int multitouchGestureAngle = 0;
static int multitouchGestureX = -1;
static int multitouchGestureY = -1;
int SDL_ANDROID_TouchscreenCalibrationWidth = 480;
int SDL_ANDROID_TouchscreenCalibrationHeight = 320;
int SDL_ANDROID_TouchscreenCalibrationX = 0;
int SDL_ANDROID_TouchscreenCalibrationY = 0;
static int leftClickTimeout = 0;
static int rightClickTimeout = 0;
static int mouseInitialX = -1;
static int mouseInitialY = -1;
static unsigned int mouseInitialTime = 0;
static volatile int deferredMouseTap = 0;
static int relativeMovement = 0;
static int relativeMovementSpeed = 2;
static int relativeMovementAccel = 0;
static int relativeMovementX = 0;
static int relativeMovementY = 0;
static unsigned int relativeMovementTime = 0;
static int oldMouseX = 0;
static int oldMouseY = 0;
static int oldMouseButtons = 0;
static int hardwareMouseDetected = 0;
enum { MOUSE_HW_BUTTON_LEFT = 1, MOUSE_HW_BUTTON_RIGHT = 2, MOUSE_HW_BUTTON_MIDDLE = 4, MOUSE_HW_BUTTON_BACK = 8, MOUSE_HW_BUTTON_FORWARD = 16, MOUSE_HW_BUTTON_MAX = MOUSE_HW_BUTTON_FORWARD };
static int hardwareMouseButtonsPressed = 0;
static int hardwareMouseButtonsPressedOld = 0;
static int UnicodeToUtf8(int src, char * dest)
{
int len = 0;
if ( src <= 0x007f) {
*dest++ = (char)src;
len = 1;
} else if (src <= 0x07ff) {
*dest++ = (char)0xc0 | (src >> 6);
*dest++ = (char)0x80 | (src & 0x003f);
len = 2;
} else if (src == 0xFEFF) {
// nop -- zap the BOM
} else if (src >= 0xD800 && src <= 0xDFFF) {
// surrogates not supported
} else if (src <= 0xffff) {
*dest++ = (char)0xe0 | (src >> 12);
*dest++ = (char)0x80 | ((src >> 6) & 0x003f);
*dest++ = (char)0x80 | (src & 0x003f);
len = 3;
} else if (src <= 0xffff) {
*dest++ = (char)0xf0 | (src >> 18);
*dest++ = (char)0x80 | ((src >> 12) & 0x3f);
*dest++ = (char)0x80 | ((src >> 6) & 0x3f);
*dest++ = (char)0x80 | (src & 0x3f);
len = 4;
} else {
// out of Unicode range
}
*dest = 0;
return len;
}
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 );
}
void UpdateScreenUnderFingerRect(int x, int y)
{
#if SDL_VERSION_ATLEAST(1,3,0)
return;
#else
int screenX = SDL_ANDROID_sFakeWindowWidth, screenY = SDL_ANDROID_sFakeWindowHeight;
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_NONE )
return;
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_MAGNIFIER )
{
SDL_ANDROID_ShowScreenUnderFingerRectSrc.w = screenX / 4;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.h = screenY / 4;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = x - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w/2;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = y - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h/2;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x > screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y > screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h;
SDL_ANDROID_ShowScreenUnderFingerRect.w = SDL_ANDROID_ShowScreenUnderFingerRectSrc.w * 3 / 2;
SDL_ANDROID_ShowScreenUnderFingerRect.h = SDL_ANDROID_ShowScreenUnderFingerRectSrc.h * 3 / 2;
SDL_ANDROID_ShowScreenUnderFingerRect.x = x + SDL_ANDROID_ShowScreenUnderFingerRect.w/10;
SDL_ANDROID_ShowScreenUnderFingerRect.y = y - SDL_ANDROID_ShowScreenUnderFingerRect.h*11/10;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x < 0 )
SDL_ANDROID_ShowScreenUnderFingerRect.x = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y < 0 )
SDL_ANDROID_ShowScreenUnderFingerRect.y = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x + SDL_ANDROID_ShowScreenUnderFingerRect.w >= screenX )
SDL_ANDROID_ShowScreenUnderFingerRect.x = screenX - SDL_ANDROID_ShowScreenUnderFingerRect.w - 1;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y + SDL_ANDROID_ShowScreenUnderFingerRect.h >= screenY )
SDL_ANDROID_ShowScreenUnderFingerRect.y = screenY - SDL_ANDROID_ShowScreenUnderFingerRect.h - 1;
if( InsideRect(&SDL_ANDROID_ShowScreenUnderFingerRect, x, y) )
SDL_ANDROID_ShowScreenUnderFingerRect.x = x - SDL_ANDROID_ShowScreenUnderFingerRect.w*11/10 - 1;
}
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_SCREEN_TRANSFORM )
{
SDL_ANDROID_ShowScreenUnderFingerRectSrc.w = screenX / 3;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.h = screenY / 3;
//SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = x - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w/2;
//SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = y - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h/2;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = x * (screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w) / screenX;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = y * (screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h) / screenY;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x > screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y > screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h;
SDL_ANDROID_ShowScreenUnderFingerRect.w = screenX * 2 / 3;
SDL_ANDROID_ShowScreenUnderFingerRect.h = screenY * 2 / 3;
//SDL_ANDROID_ShowScreenUnderFingerRect.x = x - SDL_ANDROID_ShowScreenUnderFingerRect.w/2;
//SDL_ANDROID_ShowScreenUnderFingerRect.y = y - SDL_ANDROID_ShowScreenUnderFingerRect.h/2;
SDL_ANDROID_ShowScreenUnderFingerRect.x = x * (screenX - SDL_ANDROID_ShowScreenUnderFingerRect.w) / screenX;
SDL_ANDROID_ShowScreenUnderFingerRect.y = y * (screenY - SDL_ANDROID_ShowScreenUnderFingerRect.h) / screenY;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x > SDL_ANDROID_ShowScreenUnderFingerRectSrc.x )
SDL_ANDROID_ShowScreenUnderFingerRect.x = SDL_ANDROID_ShowScreenUnderFingerRectSrc.x;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y > SDL_ANDROID_ShowScreenUnderFingerRectSrc.y )
SDL_ANDROID_ShowScreenUnderFingerRect.y = SDL_ANDROID_ShowScreenUnderFingerRectSrc.y;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x + SDL_ANDROID_ShowScreenUnderFingerRect.w < SDL_ANDROID_ShowScreenUnderFingerRectSrc.x + SDL_ANDROID_ShowScreenUnderFingerRectSrc.w )
SDL_ANDROID_ShowScreenUnderFingerRect.x = SDL_ANDROID_ShowScreenUnderFingerRectSrc.x + SDL_ANDROID_ShowScreenUnderFingerRectSrc.w - SDL_ANDROID_ShowScreenUnderFingerRect.w;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y + SDL_ANDROID_ShowScreenUnderFingerRect.h < SDL_ANDROID_ShowScreenUnderFingerRectSrc.y + SDL_ANDROID_ShowScreenUnderFingerRectSrc.h )
SDL_ANDROID_ShowScreenUnderFingerRect.y = SDL_ANDROID_ShowScreenUnderFingerRectSrc.y + SDL_ANDROID_ShowScreenUnderFingerRectSrc.h - SDL_ANDROID_ShowScreenUnderFingerRect.h;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x < 0 )
SDL_ANDROID_ShowScreenUnderFingerRect.x = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y < 0 )
SDL_ANDROID_ShowScreenUnderFingerRect.y = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRect.x > screenX - SDL_ANDROID_ShowScreenUnderFingerRect.w )
SDL_ANDROID_ShowScreenUnderFingerRect.x = screenX - SDL_ANDROID_ShowScreenUnderFingerRect.w;
if( SDL_ANDROID_ShowScreenUnderFingerRect.y > screenY - SDL_ANDROID_ShowScreenUnderFingerRect.h )
SDL_ANDROID_ShowScreenUnderFingerRect.y = screenY - SDL_ANDROID_ShowScreenUnderFingerRect.h;
}
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_FULLSCREEN_MAGNIFIER )
{
SDL_ANDROID_ShowScreenUnderFingerRectSrc.w = screenX / 2;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.h = screenY / 2;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = x - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w/2;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = y - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h/2;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y < 0 )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = 0;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.x > screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.x = screenX - SDL_ANDROID_ShowScreenUnderFingerRectSrc.w;
if( SDL_ANDROID_ShowScreenUnderFingerRectSrc.y > screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h )
SDL_ANDROID_ShowScreenUnderFingerRectSrc.y = screenY - SDL_ANDROID_ShowScreenUnderFingerRectSrc.h;
SDL_ANDROID_ShowScreenUnderFingerRect.x = 0;
SDL_ANDROID_ShowScreenUnderFingerRect.y = 0;
SDL_ANDROID_ShowScreenUnderFingerRect.w = screenX;
SDL_ANDROID_ShowScreenUnderFingerRect.h = screenY;
}
#endif
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMotionEvent) ( JNIEnv* env, jobject thiz, jint x, jint y, jint action, jint pointerId, jint force, jint radius )
{
// TODO: this method is damn huge
int i;
#if SDL_VERSION_ATLEAST(1,3,0)
SDL_Window * window = SDL_GetFocusWindow();
if( !window )
return;
#define SDL_ANDROID_sFakeWindowWidth window->w
#define SDL_ANDROID_sFakeWindowHeight window->h
#else
if( !SDL_CurrentVideoSurface )
return;
#endif
if(pointerId < 0)
pointerId = 0;
if(pointerId > MAX_MULTITOUCH_POINTERS)
pointerId = MAX_MULTITOUCH_POINTERS;
// The touch is passed either to on-screen keyboard or as mouse event for all duration of touch between down and up,
// even if the finger is not anymore above screen kb button it will not acr as mouse event, and if it's initially
// touches the screen outside of screen kb it won't trigger button keypress -
// I think it's more logical this way
if( SDL_ANDROID_isTouchscreenKeyboardUsed && ( action == MOUSE_DOWN || touchPointers[pointerId] == TOUCH_PTR_SCREENKB ) )
{
if( SDL_ANDROID_processTouchscreenKeyboard(x, y, action, pointerId) && action == MOUSE_DOWN )
touchPointers[pointerId] = TOUCH_PTR_SCREENKB;
if( touchPointers[pointerId] == TOUCH_PTR_SCREENKB )
{
if( action == MOUSE_UP )
touchPointers[pointerId] = TOUCH_PTR_UP;
return;
}
}
if( action == MOUSE_DOWN )
{
touchPointers[pointerId] = TOUCH_PTR_MOUSE;
firstMousePointerId = -1;
for( i = 0; i < MAX_MULTITOUCH_POINTERS; i++ )
{
if( touchPointers[i] == TOUCH_PTR_MOUSE )
{
firstMousePointerId = i;
break;
}
}
}
x -= SDL_ANDROID_TouchscreenCalibrationX;
y -= SDL_ANDROID_TouchscreenCalibrationY;
#if SDL_VIDEO_RENDER_RESIZE
// Translate mouse coordinates
x = x * SDL_ANDROID_sFakeWindowWidth / SDL_ANDROID_TouchscreenCalibrationWidth;
y = y * SDL_ANDROID_sFakeWindowHeight / SDL_ANDROID_TouchscreenCalibrationHeight;
if( x < 0 )
x = 0;
if( x > SDL_ANDROID_sFakeWindowWidth )
x = SDL_ANDROID_sFakeWindowWidth;
if( y < 0 )
y = 0;
if( y > SDL_ANDROID_sFakeWindowHeight )
y = SDL_ANDROID_sFakeWindowHeight;
#else
x = x * SDL_ANDROID_sRealWindowWidth / SDL_ANDROID_TouchscreenCalibrationWidth;
y = y * SDL_ANDROID_sRealWindowHeight / SDL_ANDROID_TouchscreenCalibrationHeight;
#endif
if( action == MOUSE_UP )
{
multitouchGestureX = -1;
multitouchGestureY = -1;
multitouchGestureDist = -1;
for(i = 0; i < MAX_MULTITOUCH_GESTURES; i++)
{
if( multitouchGestureKeyPressed[i] )
{
multitouchGestureKeyPressed[i] = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, multitouchGestureKeycode[i] );
}
}
}
else if( !hardwareMouseDetected )
{
if( firstMousePointerId != pointerId )
{
multitouchGestureX = x;
multitouchGestureY = y;
}
if( firstMousePointerId == pointerId && multitouchGestureX >= 0 )
{
int dist = abs( x - multitouchGestureX ) + abs( y - multitouchGestureY );
int angle = atan2i( y - multitouchGestureY, x - multitouchGestureX );
if( multitouchGestureDist < 0 )
{
multitouchGestureDist = dist;
multitouchGestureAngle = angle;
}
else
{
int distMaxDiff = SDL_ANDROID_sFakeWindowHeight / ( 1 + (1 + multitouchGestureSensitivity) * 2 );
int angleMaxDiff = atan2i_PI / ( 1 + (1 + multitouchGestureSensitivity) * 2 );
if( dist - multitouchGestureDist > distMaxDiff )
{
multitouchGestureKeyPressed[0] = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, multitouchGestureKeycode[0] );
}
else
if( multitouchGestureKeyPressed[0] )
{
multitouchGestureKeyPressed[0] = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, multitouchGestureKeycode[0] );
}
if( multitouchGestureDist - dist > distMaxDiff )
{
multitouchGestureKeyPressed[1] = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, multitouchGestureKeycode[1] );
}
else
if( multitouchGestureKeyPressed[1] )
{
multitouchGestureKeyPressed[1] = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, multitouchGestureKeycode[1] );
}
int angleDiff = angle - multitouchGestureAngle;
while( angleDiff < atan2i_PI )
angleDiff += atan2i_PI * 2;
while( angleDiff > atan2i_PI )
angleDiff -= atan2i_PI * 2;
if( angleDiff < -angleMaxDiff )
{
multitouchGestureKeyPressed[2] = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, multitouchGestureKeycode[2] );
}
else
if( multitouchGestureKeyPressed[2] )
{
multitouchGestureKeyPressed[2] = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, multitouchGestureKeycode[2] );
}
if( angleDiff > angleMaxDiff )
{
multitouchGestureKeyPressed[3] = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, multitouchGestureKeycode[3] );
}
else
if( multitouchGestureKeyPressed[3] )
{
multitouchGestureKeyPressed[3] = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, multitouchGestureKeycode[3] );
}
}
}
}
if( isMultitouchUsed )
{
#if SDL_VERSION_ATLEAST(1,3,0)
// Use nifty SDL 1.3 multitouch API
if( action == MOUSE_MOVE )
SDL_ANDROID_MainThreadPushMultitouchMotion(pointerId, x, y, force + radius);
else
SDL_ANDROID_MainThreadPushMultitouchButton(pointerId, action == MOUSE_DOWN ? 1 : 0, x, y, force + radius);
#endif
// The old, bad, deprecated, but still used multitouch API
/*
if( action == MOUSE_DOWN )
SDL_ANDROID_MainThreadPushJoystickButton(pointerId+1, 0, SDL_PRESSED);
SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 0, x);
SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 1, y);
SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 2, force);
SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 3, radius);
if( action == MOUSE_UP )
SDL_ANDROID_MainThreadPushJoystickButton(pointerId+1, 0, SDL_RELEASED);
*/
// The new, good, clean multitouch API, which is using only the first joystick, and sending both X and Y coords simultaneously in one event
if( action == MOUSE_DOWN )
SDL_ANDROID_MainThreadPushJoystickButton(0, pointerId, SDL_PRESSED);
SDL_ANDROID_MainThreadPushJoystickBall(0, pointerId, x, y);
SDL_ANDROID_MainThreadPushJoystickAxis(0, pointerId+3, force + radius); // Radius is more sensitive usually
if( action == MOUSE_UP )
SDL_ANDROID_MainThreadPushJoystickButton(0, pointerId, SDL_RELEASED);
}
if( !isMouseUsed && !SDL_ANDROID_isTouchscreenKeyboardUsed )
{
SDL_keysym keysym;
if( action != MOUSE_MOVE )
SDL_ANDROID_MainThreadPushKeyboardKey( action == MOUSE_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_ANDROID_GetScreenKeyboardButtonKey(SDL_ANDROID_SCREENKEYBOARD_BUTTON_0) );
return;
}
if( !isMouseUsed )
return;
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse buttons %d pointerId %d firstMousePointerId %d", hardwareMouseButtonsPressed, pointerId, firstMousePointerId);
if( pointerId == firstMousePointerId && (hardwareMouseButtonsPressedOld != hardwareMouseButtonsPressed || hardwareMouseButtonsPressed != 0) )
{
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
for( i = 1; i <= MOUSE_HW_BUTTON_MAX; i *= 2 )
{
int btn = SDL_BUTTON_LEFT;
switch(i)
{
case MOUSE_HW_BUTTON_LEFT:
btn = SDL_BUTTON_LEFT;
break;
case MOUSE_HW_BUTTON_RIGHT:
btn = SDL_BUTTON_RIGHT;
break;
case MOUSE_HW_BUTTON_MIDDLE:
btn = SDL_BUTTON_MIDDLE;
break;
case MOUSE_HW_BUTTON_BACK:
btn = SDL_BUTTON_WHEELUP;
break;
case MOUSE_HW_BUTTON_FORWARD:
btn = SDL_BUTTON_WHEELDOWN;
break;
}
if( (hardwareMouseButtonsPressed & i) && !(hardwareMouseButtonsPressedOld & i) )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse button DOWN: %d", btn);
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, btn );
}
else
if( !(hardwareMouseButtonsPressed & i) && (hardwareMouseButtonsPressedOld & i) )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse button UP : %d", btn);
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, btn );
}
}
hardwareMouseButtonsPressedOld = hardwareMouseButtonsPressed;
}
else if( pointerId == firstMousePointerId )
{
if( relativeMovement )
{
if( action == MOUSE_DOWN )
{
relativeMovementX = oldMouseX - x;
relativeMovementY = oldMouseY - y;
}
x += relativeMovementX;
y += relativeMovementY;
int diffX = x - oldMouseX;
int diffY = y - oldMouseY;
int coeff = relativeMovementSpeed + 2;
if( relativeMovementSpeed > 2 )
coeff += relativeMovementSpeed - 2;
diffX = diffX * coeff / 4;
diffY = diffY * coeff / 4;
if( relativeMovementAccel > 0 )
{
unsigned int newTime = SDL_GetTicks();
if( newTime - relativeMovementTime > 0 )
{
diffX += diffX * ( relativeMovementAccel * 30 ) / (int)(newTime - relativeMovementTime);
diffY += diffY * ( relativeMovementAccel * 30 ) / (int)(newTime - relativeMovementTime);
}
relativeMovementTime = newTime;
}
diffX -= x - oldMouseX;
diffY -= y - oldMouseY;
x += diffX;
y += diffY;
relativeMovementX += diffX;
relativeMovementY += diffY;
diffX = x;
diffY = y;
if( x < 0 )
x = 0;
if( x > SDL_ANDROID_sFakeWindowWidth )
x = SDL_ANDROID_sFakeWindowWidth;
if( y < 0 )
y = 0;
if( y > SDL_ANDROID_sFakeWindowHeight )
y = SDL_ANDROID_sFakeWindowHeight;
relativeMovementX += x - diffX;
relativeMovementY += y - diffY;
}
if( action == MOUSE_UP )
{
if( rightClickMethod != RIGHT_CLICK_WITH_KEY )
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_RIGHT );
if( mouseInitialX >= 0 && mouseInitialY >= 0 && (
leftClickMethod == LEFT_CLICK_WITH_TAP || leftClickMethod == LEFT_CLICK_WITH_TAP_OR_TIMEOUT ) &&
abs(mouseInitialX - x) < SDL_ANDROID_sFakeWindowHeight / 16 &&
abs(mouseInitialY - y) < SDL_ANDROID_sFakeWindowHeight / 16 &&
SDL_GetTicks() - mouseInitialTime < 700 )
{
SDL_ANDROID_MainThreadPushMouseMotion(mouseInitialX, mouseInitialY);
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_LEFT );
deferredMouseTap = 2;
mouseInitialX = -1;
mouseInitialY = -1;
}
else
{
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
}
SDL_ANDROID_ShowScreenUnderFingerRect.w = SDL_ANDROID_ShowScreenUnderFingerRect.h = 0;
SDL_ANDROID_ShowScreenUnderFingerRectSrc.w = SDL_ANDROID_ShowScreenUnderFingerRectSrc.h = 0;
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_MAGNIFIER )
{
// Move mouse by 1 pixel so it will force screen update and mouse-under-finger window will be removed
if( moveMouseWithKbX >= 0 )
SDL_ANDROID_MainThreadPushMouseMotion(moveMouseWithKbX > 0 ? moveMouseWithKbX-1 : 0, moveMouseWithKbY);
else
SDL_ANDROID_MainThreadPushMouseMotion(x > 0 ? x-1 : 0, y);
}
moveMouseWithKbX = -1;
moveMouseWithKbY = -1;
moveMouseWithKbSpeedX = 0;
moveMouseWithKbSpeedY = 0;
}
if( action == MOUSE_DOWN )
{
if( (moveMouseWithKbX >= 0 || leftClickMethod == LEFT_CLICK_NEAR_CURSOR) &&
abs(oldMouseX - x) < SDL_ANDROID_sFakeWindowWidth / 8 && abs(oldMouseY - y) < SDL_ANDROID_sFakeWindowHeight / 8 )
{
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_LEFT );
moveMouseWithKbX = oldMouseX;
moveMouseWithKbY = oldMouseY;
moveMouseWithKbSpeedX = 0;
moveMouseWithKbSpeedY = 0;
action = MOUSE_MOVE;
}
else
if( leftClickMethod == LEFT_CLICK_NORMAL )
{
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_LEFT );
}
else
{
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
action == MOUSE_MOVE;
mouseInitialX = x;
mouseInitialY = y;
mouseInitialTime = SDL_GetTicks();
}
UpdateScreenUnderFingerRect(x, y);
}
if( action == MOUSE_MOVE )
{
if( moveMouseWithKbX >= 0 )
{
if( abs(moveMouseWithKbX - x) > SDL_ANDROID_sFakeWindowWidth / 12 )
moveMouseWithKbSpeedX += moveMouseWithKbX > x ? -1 : 1;
else
moveMouseWithKbSpeedX = moveMouseWithKbSpeedX * 2 / 3;
if( abs(moveMouseWithKbY - y) > SDL_ANDROID_sFakeWindowHeight / 12 )
moveMouseWithKbSpeedY += moveMouseWithKbY > y ? -1 : 1;
else
moveMouseWithKbSpeedY = moveMouseWithKbSpeedY * 2 / 3;
moveMouseWithKbX += moveMouseWithKbSpeedX;
moveMouseWithKbY += moveMouseWithKbSpeedY;
if( abs(moveMouseWithKbX - x) > SDL_ANDROID_sFakeWindowWidth / 8 ||
abs(moveMouseWithKbY - y) > SDL_ANDROID_sFakeWindowHeight / 8 )
{
moveMouseWithKbX = -1;
moveMouseWithKbY = -1;
moveMouseWithKbSpeedX = 0;
moveMouseWithKbSpeedY = 0;
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
else
SDL_ANDROID_MainThreadPushMouseMotion(moveMouseWithKbX, moveMouseWithKbY);
}
else
{
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
if( rightClickMethod == RIGHT_CLICK_WITH_PRESSURE || leftClickMethod == LEFT_CLICK_WITH_PRESSURE )
{
int button = (leftClickMethod == LEFT_CLICK_WITH_PRESSURE) ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT;
int buttonState = ( force > maxForce || radius > maxRadius );
if( button == SDL_BUTTON_RIGHT )
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
SDL_ANDROID_MainThreadPushMouseButton( buttonState ? SDL_PRESSED : SDL_RELEASED, button );
}
if( mouseInitialX >= 0 && mouseInitialY >= 0 && (
leftClickMethod == LEFT_CLICK_WITH_TIMEOUT || leftClickMethod == LEFT_CLICK_WITH_TAP ||
leftClickMethod == LEFT_CLICK_WITH_TAP_OR_TIMEOUT || rightClickMethod == RIGHT_CLICK_WITH_TIMEOUT ) )
{
if( abs(mouseInitialX - x) >= SDL_ANDROID_sFakeWindowHeight / 15 || abs(mouseInitialY - y) >= SDL_ANDROID_sFakeWindowHeight / 15 )
{
mouseInitialX = -1;
mouseInitialY = -1;
}
else
{
if( leftClickMethod == LEFT_CLICK_WITH_TIMEOUT || leftClickMethod == LEFT_CLICK_WITH_TAP_OR_TIMEOUT )
{
if( SDL_GetTicks() - mouseInitialTime > leftClickTimeout )
{
//SDL_ANDROID_MainThreadPushMouseMotion(mouseInitialX, mouseInitialY);
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_LEFT );
mouseInitialX = -1;
mouseInitialY = -1;
}
}
if( rightClickMethod == RIGHT_CLICK_WITH_TIMEOUT )
{
if( SDL_GetTicks() - mouseInitialTime > rightClickTimeout )
{
//SDL_ANDROID_MainThreadPushMouseMotion(mouseInitialX, mouseInitialY);
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_RIGHT );
mouseInitialX = -1;
mouseInitialY = -1;
}
}
}
}
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_MAGNIFIER )
UpdateScreenUnderFingerRect(x, y);
}
if( SDL_ANDROID_ShowScreenUnderFinger == ZOOM_SCREEN_TRANSFORM ||
SDL_ANDROID_ShowScreenUnderFinger == ZOOM_FULLSCREEN_MAGNIFIER )
UpdateScreenUnderFingerRect(x, y);
}
if( pointerId != firstMousePointerId && (action == MOUSE_DOWN || action == MOUSE_UP) )
{
if( leftClickMethod == LEFT_CLICK_WITH_MULTITOUCH )
{
SDL_ANDROID_MainThreadPushMouseButton( (action == MOUSE_DOWN) ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT );
}
else if( rightClickMethod == RIGHT_CLICK_WITH_MULTITOUCH )
{
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
SDL_ANDROID_MainThreadPushMouseButton( (action == MOUSE_DOWN) ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT );
}
}
if( action == MOUSE_UP )
{
touchPointers[pointerId] = TOUCH_PTR_UP;
firstMousePointerId = -1;
for( i = 0; i < MAX_MULTITOUCH_POINTERS; i++ )
{
if( touchPointers[i] == TOUCH_PTR_MOUSE )
{
firstMousePointerId = i;
break;
}
}
}
if( action == MOUSE_HOVER && !relativeMovement )
{
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
}
void ProcessDeferredMouseTap()
{
if( deferredMouseTap > 0 )
{
deferredMouseTap--;
if( deferredMouseTap <= 0 )
{
#if SDL_VERSION_ATLEAST(1,3,0)
SDL_Window * window = SDL_GetFocusWindow();
if( !window )
return;
#define SDL_ANDROID_sFakeWindowWidth window->w
#define SDL_ANDROID_sFakeWindowHeight window->h
#endif
if( oldMouseX + 1 < SDL_ANDROID_sFakeWindowWidth )
SDL_ANDROID_MainThreadPushMouseMotion(oldMouseX + 1, oldMouseY);
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
}
else if( oldMouseX > 0 ) // Force application to redraw, and call SDL_Flip()
SDL_ANDROID_MainThreadPushMouseMotion(oldMouseX - 1, oldMouseY);
}
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeTouchpad) ( JNIEnv* env, jobject thiz, jint x, jint y, jint down, jint multitouch)
{
if( !isMouseUsed )
return;
if( ! down )
{
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_RIGHT );
SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
moveMouseWithKbX = -1;
moveMouseWithKbY = -1;
moveMouseWithKbAccelUpdateNeeded = 0;
}
else
{
// x and y from 0 to 65535
if( moveMouseWithKbX < 0 )
{
moveMouseWithKbX = oldMouseX;
moveMouseWithKbY = oldMouseY;
}
moveMouseWithKbSpeedX = (x - 32767) / 8192;
moveMouseWithKbSpeedY = (y - 32767) / 8192;
//moveMouseWithKbX += moveMouseWithKbSpeedX;
//moveMouseWithKbY += moveMouseWithKbSpeedY;
SDL_ANDROID_MainThreadPushMouseMotion(moveMouseWithKbX, moveMouseWithKbY);
moveMouseWithKbAccelUpdateNeeded = 1;
if( multitouch )
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_RIGHT );
else
if( abs(x - 32767) < 8192 && abs(y - 32767) < 8192 )
SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, SDL_BUTTON_LEFT );
}
}
void SDL_ANDROID_WarpMouse(int x, int y)
{
if(!relativeMovement)
{
//SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
else
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_ANDROID_WarpMouse(): %dx%d rel %dx%d old %dx%d", x, y, relativeMovementX, relativeMovementY, oldMouseX, oldMouseY);
relativeMovementX -= oldMouseX-x;
relativeMovementY -= oldMouseY-y;
SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
};
static int processAndroidTrackball(int key, int action);
JNIEXPORT jint JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeKey) ( JNIEnv* env, jobject thiz, jint key, jint action )
{
#if SDL_VERSION_ATLEAST(1,3,0)
#else
if( !SDL_CurrentVideoSurface )
return 1;
#endif
if( isTrackballUsed )
if( processAndroidTrackball(key, action) )
return 1;
if( key == rightClickKey && rightClickMethod == RIGHT_CLICK_WITH_KEY )
{
SDL_ANDROID_MainThreadPushMouseButton( action ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT );
return 1;
}
if( (key == leftClickKey && leftClickMethod == LEFT_CLICK_WITH_KEY) || (clickMouseWithDpadCenter && key == KEYCODE_DPAD_CENTER) )
{
SDL_ANDROID_MainThreadPushMouseButton( action ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT );
return 1;
}
if( TranslateKey(key) == SDLK_NO_REMAP || TranslateKey(key) == SDLK_UNKNOWN )
return 0;
SDL_ANDROID_MainThreadPushKeyboardKey( action ? SDL_PRESSED : SDL_RELEASED, TranslateKey(key) );
return 1;
}
static char * textInputBuffer = NULL;
int textInputBufferLen = 0;
int textInputBufferPos = 0;
void SDL_ANDROID_TextInputInit(char * buffer, int len)
{
textInputBuffer = buffer;
textInputBufferLen = len;
textInputBufferPos = 0;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoRenderer_nativeTextInput) ( JNIEnv* env, jobject thiz, jint ascii, jint unicode )
{
if( ascii == 10 )
ascii = SDLK_RETURN;
if( !textInputBuffer )
SDL_ANDROID_MainThreadPushText(ascii, unicode);
else
{
if( textInputBufferPos < textInputBufferLen + 4 && ascii != SDLK_RETURN && ascii != '\r' && ascii != '\n' )
{
textInputBufferPos += UnicodeToUtf8(unicode, textInputBuffer + textInputBufferPos);
}
}
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoRenderer_nativeTextInputFinished) ( JNIEnv* env, jobject thiz )
{
textInputBuffer = NULL;
SDL_ANDROID_TextInputFinished();
}
static void updateOrientation ( float accX, float accY, float accZ );
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(AccelerometerReader_nativeAccelerometer) ( JNIEnv* env, jobject thiz, jfloat accPosX, jfloat accPosY, jfloat accPosZ )
{
#if SDL_VERSION_ATLEAST(1,3,0)
#else
if( !SDL_CurrentVideoSurface )
return;
#endif
// Calculate two angles from three coordinates - TODO: this is faulty!
//float accX = atan2f(-accPosX, sqrtf(accPosY*accPosY+accPosZ*accPosZ) * ( accPosY > 0 ? 1.0f : -1.0f ) ) * M_1_PI * 180.0f;
//float accY = atan2f(accPosZ, accPosY) * M_1_PI;
float normal = sqrt(accPosX*accPosX+accPosY*accPosY+accPosZ*accPosZ);
if(normal <= 0.0000001f)
normal = 0.00001f;
updateOrientation (accPosX/normal, accPosY/normal, 0.0f);
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(AccelerometerReader_nativeOrientation) ( JNIEnv* env, jobject thiz, jfloat accX, jfloat accY, jfloat accZ )
{
#if SDL_VERSION_ATLEAST(1,3,0)
#else
if( !SDL_CurrentVideoSurface )
return;
#endif
updateOrientation (accX, accY, accZ); // TODO: make values in range 0.0:1.0
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetTrackballUsed) ( JNIEnv* env, jobject thiz)
{
isTrackballUsed = 1;
}
static int getClickTimeout(int v)
{
switch(v)
{
case 0: return 200;
case 1: return 300;
case 2: return 400;
case 3: return 700;
case 4: return 1000;
}
return 1000;
}
// Mwahaha overkill!
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetMouseUsed) (JNIEnv* env, jobject thiz,
jint RightClickMethod, jint ShowScreenUnderFinger, jint LeftClickMethod,
jint MoveMouseWithJoystick, jint ClickMouseWithDpad,
jint MaxForce, jint MaxRadius,
jint MoveMouseWithJoystickSpeed, jint MoveMouseWithJoystickAccel,
jint LeftClickKeycode, jint RightClickKeycode,
jint LeftClickTimeout, jint RightClickTimeout,
jint RelativeMovement, jint RelativeMovementSpeed, jint RelativeMovementAccel,
jint ShowMouseCursor)
{
isMouseUsed = 1;
rightClickMethod = RightClickMethod;
SDL_ANDROID_ShowScreenUnderFinger = ShowScreenUnderFinger;
moveMouseWithArrowKeys = MoveMouseWithJoystick;
clickMouseWithDpadCenter = ClickMouseWithDpad;
leftClickMethod = LeftClickMethod;
maxForce = MaxForce;
maxRadius = MaxRadius;
moveMouseWithKbSpeed = MoveMouseWithJoystickSpeed + 1;
moveMouseWithKbAccel = MoveMouseWithJoystickAccel;
leftClickKey = LeftClickKeycode;
rightClickKey = RightClickKeycode;
leftClickTimeout = getClickTimeout(LeftClickTimeout);
rightClickTimeout = getClickTimeout(RightClickTimeout);
relativeMovement = RelativeMovement;
relativeMovementSpeed = RelativeMovementSpeed;
relativeMovementAccel = RelativeMovementAccel;
SDL_ANDROID_ShowMouseCursor = ShowMouseCursor;
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "relativeMovementSpeed %d relativeMovementAccel %d", relativeMovementSpeed, relativeMovementAccel);
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeHardwareMouseDetected) (JNIEnv* env, jobject thiz, int detected)
{
if( !isMouseUsed )
return;
static struct {
int leftClickMethod;
int ShowScreenUnderFinger;
int leftClickTimeout;
int relativeMovement;
int ShowMouseCursor;
} cfg = { 0 };
if( hardwareMouseDetected != detected )
{
hardwareMouseDetected = detected;
if(detected)
{
cfg.leftClickMethod = leftClickMethod;
cfg.ShowScreenUnderFinger = SDL_ANDROID_ShowScreenUnderFinger;
cfg.leftClickTimeout = leftClickTimeout;
cfg.relativeMovement = relativeMovement;
cfg.ShowMouseCursor = SDL_ANDROID_ShowMouseCursor;
leftClickMethod = LEFT_CLICK_NORMAL;
SDL_ANDROID_ShowScreenUnderFinger = 0;
leftClickTimeout = 0;
relativeMovement = 0;
SDL_ANDROID_ShowMouseCursor = 0;
}
else
{
leftClickMethod = cfg.leftClickMethod;
SDL_ANDROID_ShowScreenUnderFinger = cfg.ShowScreenUnderFinger;
leftClickTimeout = cfg.leftClickTimeout;
relativeMovement = cfg.relativeMovement;
SDL_ANDROID_ShowMouseCursor = cfg.ShowMouseCursor;
}
}
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouseButtonsPressed) (JNIEnv* env, jobject thiz, int buttons)
{
if( !isMouseUsed )
return;
hardwareMouseButtonsPressed = buttons;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetJoystickUsed) (JNIEnv* env, jobject thiz)
{
SDL_ANDROID_isJoystickUsed = 1;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetMultitouchUsed) ( JNIEnv* env, jobject thiz)
{
isMultitouchUsed = 1;
}
static float dx = 0.04, dy = 0.1, dz = 0.1, joystickSensitivity = 400.0f; // For accelerometer
enum { ACCELEROMETER_CENTER_FLOATING, ACCELEROMETER_CENTER_FIXED_START, ACCELEROMETER_CENTER_FIXED_HORIZ };
static int accelerometerCenterPos = ACCELEROMETER_CENTER_FLOATING;
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetAccelerometerSettings) ( JNIEnv* env, jobject thiz, jint sensitivity, jint centerPos)
{
dx = 0.04; dy = 0.08; dz = 0.08; joystickSensitivity = 32767.0f * 3.0f; // Fast sensitivity
if( sensitivity == 1 )
{
dx = 0.1; dy = 0.15; dz = 0.15; joystickSensitivity = 32767.0f * 2.0f; // Medium sensitivity
}
if( sensitivity == 2 )
{
dx = 0.2; dy = 0.25; dz = 0.25; joystickSensitivity = 32767.0f; // Slow sensitivity
}
accelerometerCenterPos = centerPos;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetTrackballDampening) ( JNIEnv* env, jobject thiz, jint value)
{
TrackballDampening = (value * 200);
}
void updateOrientation ( float accX, float accY, float accZ )
{
SDL_keysym keysym;
// TODO: ask user for accelerometer precision from Java
static float midX = 0, midY = 0, midZ = 0;
static int pressLeft = 0, pressRight = 0, pressUp = 0, pressDown = 0, pressR = 0, pressL = 0;
if( accelerometerCenterPos == ACCELEROMETER_CENTER_FIXED_START )
{
accelerometerCenterPos = ACCELEROMETER_CENTER_FIXED_HORIZ;
midX = accX;
midY = accY;
midZ = accZ;
}
// midX = 0.0f; // Do not remember old value for phone tilt, it feels weird
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "updateOrientation(): %f %f %f", accX, accY, accZ);
if( SDL_ANDROID_isJoystickUsed ) // TODO: mutex for that stuff?
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "updateOrientation(): sending joystick event");
SDL_ANDROID_MainThreadPushJoystickAxis(0, 0, (Sint16)(fminf(32767.0f, fmax(-32767.0f, (accX - midX) * joystickSensitivity))));
SDL_ANDROID_MainThreadPushJoystickAxis(0, 1, (Sint16)(fminf(32767.0f, fmax(-32767.0f, -(accY - midY) * joystickSensitivity))));
SDL_ANDROID_MainThreadPushJoystickAxis(0, 2, (Sint16)(fminf(32767.0f, fmax(-32767.0f, -(accZ - midZ) * joystickSensitivity))));
if( accelerometerCenterPos == ACCELEROMETER_CENTER_FLOATING )
{
if( accY < midY - dy*2 )
midY = accY + dy*2;
if( accY > midY + dy*2 )
midY = accY - dy*2;
if( accZ < midZ - dz*2 )
midZ = accZ + dz*2;
if( accZ > midZ + dz*2 )
midZ = accZ - dz*2;
}
}
if(SDL_ANDROID_isJoystickUsed)
return;
if( accX < midX - dx )
{
if( !pressLeft )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: press left, acc %f mid %f d %f", accX, midX, dx);
pressLeft = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_DPAD_LEFT) );
}
}
else
{
if( pressLeft )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: release left, acc %f mid %f d %f", accX, midX, dx);
pressLeft = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_LEFT) );
}
}
if( accX < midX - dx*2 )
midX = accX + dx*2;
if( accX > midX + dx )
{
if( !pressRight )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: press right, acc %f mid %f d %f", accX, midX, dx);
pressRight = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_DPAD_RIGHT) );
}
}
else
{
if( pressRight )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: release right, acc %f mid %f d %f", accX, midX, dx);
pressRight = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_RIGHT) );
}
}
if( accX > midX + dx*2 )
midX = accX - dx*2;
if( accY < midY - dy )
{
if( !pressUp )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: press up, acc %f mid %f d %f", accY, midY, dy);
pressUp = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_DPAD_DOWN) );
}
}
else
{
if( pressUp )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: release up, acc %f mid %f d %f", accY, midY, dy);
pressUp = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_DOWN) );
}
}
if( accY < midY - dy*2 )
midY = accY + dy*2;
if( accY > midY + dy )
{
if( !pressDown )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: press down, acc %f mid %f d %f", accY, midY, dy);
pressDown = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_DPAD_UP) );
}
}
else
{
if( pressDown )
{
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "Accelerometer: release down, acc %f mid %f d %f", accY, midY, dy);
pressDown = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_UP) );
}
}
if( accY > midY + dy*2 )
midY = accY - dy*2;
if( accZ < midZ - dz )
{
if( !pressL )
{
pressL = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_ALT_LEFT) );
}
}
else
{
if( pressL )
{
pressL = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_ALT_LEFT) );
}
}
if( accZ < midZ - dz*2 )
midZ = accZ + dz*2;
if( accZ > midZ + dz )
{
if( !pressR )
{
pressR = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(KEYCODE_ALT_RIGHT) );
}
}
else
{
if( pressR )
{
pressR = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_ALT_RIGHT) );
}
}
if( accZ > midZ + dz*2 )
midZ = accZ - dz*2;
}
static int leftPressed = 0, rightPressed = 0, upPressed = 0, downPressed = 0;
int processAndroidTrackball(int key, int action)
{
SDL_keysym keysym;
if( ! action && (
key == KEYCODE_DPAD_UP ||
key == KEYCODE_DPAD_DOWN ||
key == KEYCODE_DPAD_LEFT ||
key == KEYCODE_DPAD_RIGHT ) )
return 1;
lastTrackballAction = SDL_GetTicks();
if( key == KEYCODE_DPAD_UP )
{
if( downPressed )
{
downPressed = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_DOWN) );
return 1;
}
if( !upPressed )
{
upPressed = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(key) );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
return 1;
}
if( key == KEYCODE_DPAD_DOWN )
{
if( upPressed )
{
upPressed = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_UP) );
return 1;
}
if( !upPressed )
{
downPressed = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(key) );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
return 1;
}
if( key == KEYCODE_DPAD_LEFT )
{
if( rightPressed )
{
rightPressed = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_RIGHT) );
return 1;
}
if( !leftPressed )
{
leftPressed = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(key) );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
return 1;
}
if( key == KEYCODE_DPAD_RIGHT )
{
if( leftPressed )
{
leftPressed = 0;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_LEFT) );
return 1;
}
if( !rightPressed )
{
rightPressed = 1;
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
else
{
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(key) );
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_PRESSED, TranslateKey(key) );
}
return 1;
}
return 0;
}
void SDL_ANDROID_processAndroidTrackballDampening()
{
if( !TrackballDampening )
return;
if( SDL_GetTicks() > TrackballDampening + lastTrackballAction )
{
if( upPressed )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_UP) );
if( downPressed )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_DOWN) );
if( leftPressed )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_LEFT) );
if( rightPressed )
SDL_ANDROID_MainThreadPushKeyboardKey( SDL_RELEASED, TranslateKey(KEYCODE_DPAD_RIGHT) );
upPressed = 0;
downPressed = 0;
leftPressed = 0;
rightPressed = 0;
}
}
int SDL_SYS_JoystickInit(void)
{
SDL_numjoysticks = 0;
if( SDL_ANDROID_isJoystickUsed )
SDL_numjoysticks = 1;
if( isMultitouchUsed )
SDL_numjoysticks = MAX_MULTITOUCH_POINTERS+1;
return(SDL_numjoysticks);
}
/* Function to get the device-dependent name of a joystick */
const char *SDL_SYS_JoystickName(int index)
{
if(index)
return("Android multitouch");
return("Android accelerometer/orientation sensor");
}
/* Function to open a joystick for use.
The joystick to open is specified by the index field of the joystick.
This should fill the nbuttons and naxes fields of the joystick structure.
It returns 0, or -1 if there is an error.
*/
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
{
joystick->nbuttons = 0;
joystick->nhats = 0;
joystick->nballs = 0;
if( joystick->index == 0 )
{
joystick->naxes = 3;
if(isMultitouchUsed)
{
joystick->naxes = 3 + MAX_MULTITOUCH_POINTERS; // Accelerometer/orientation, plus touch pressure/size
joystick->nbuttons = MAX_MULTITOUCH_POINTERS;
joystick->nballs = MAX_MULTITOUCH_POINTERS;
}
}
else
{
joystick->naxes = 4;
joystick->nbuttons = 1;
}
SDL_ANDROID_CurrentJoysticks[joystick->index] = joystick;
return(0);
}
/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
* but instead should call SDL_PrivateJoystick*() to deliver events
* and update joystick device state.
*/
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
{
return;
}
/* Function to close a joystick after use */
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
{
SDL_ANDROID_CurrentJoysticks[joystick->index] = NULL;
return;
}
/* Function to perform any system-specific joystick related cleanup */
void SDL_SYS_JoystickQuit(void)
{
int i;
for(i=0; i<MAX_MULTITOUCH_POINTERS+1; i++)
SDL_ANDROID_CurrentJoysticks[i] = NULL;
return;
}
enum { MAX_BUFFERED_EVENTS = 64 };
static SDL_Event BufferedEvents[MAX_BUFFERED_EVENTS];
static int BufferedEventsStart = 0, BufferedEventsEnd = 0;
static SDL_mutex * BufferedEventsMutex = NULL;
#if SDL_VERSION_ATLEAST(1,3,0)
#define SDL_SendKeyboardKey(state, keysym) SDL_SendKeyboardKey(state, (keysym)->sym)
extern SDL_Window * ANDROID_CurrentWindow;
#else
#define SDL_SendMouseMotion(A,B,X,Y) SDL_PrivateMouseMotion(0, 0, X, Y)
#define SDL_SendMouseButton(N, A, B) SDL_PrivateMouseButton( A, B, 0, 0 )
#define SDL_SendKeyboardKey(state, keysym) SDL_PrivateKeyboard(state, keysym)
#endif
extern void SDL_ANDROID_PumpEvents()
{
SDL_Event ev;
SDL_ANDROID_processAndroidTrackballDampening();
SDL_ANDROID_processMoveMouseWithKeyboard();
#if SDL_VERSION_ATLEAST(1,3,0)
SDL_Window * window = SDL_GetFocusWindow();
if( !window )
return;
#endif
if( !BufferedEventsMutex )
BufferedEventsMutex = SDL_CreateMutex();
SDL_mutexP(BufferedEventsMutex);
while( BufferedEventsStart != BufferedEventsEnd )
{
ev = BufferedEvents[BufferedEventsStart];
BufferedEvents[BufferedEventsStart].type = 0;
BufferedEventsStart++;
if( BufferedEventsStart >= MAX_BUFFERED_EVENTS )
BufferedEventsStart = 0;
SDL_mutexV(BufferedEventsMutex);
switch( ev.type )
{
case SDL_MOUSEMOTION:
SDL_SendMouseMotion(ANDROID_CurrentWindow, 0, ev.motion.x, ev.motion.y);
break;
case SDL_MOUSEBUTTONDOWN:
if( ((oldMouseButtons & SDL_BUTTON(ev.button.button)) != 0) != ev.button.state )
{
oldMouseButtons = (oldMouseButtons & ~SDL_BUTTON(ev.button.button)) | (ev.button.state ? SDL_BUTTON(ev.button.button) : 0);
SDL_SendMouseButton( ANDROID_CurrentWindow, ev.button.state, ev.button.button );
}
break;
case SDL_KEYDOWN:
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_KEYDOWN: %i %i", ev->key.keysym.sym, ev->key.state);
SDL_SendKeyboardKey( ev.key.state, &ev.key.keysym );
break;
case SDL_JOYAXISMOTION:
if( ev.jaxis.which < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[ev.jaxis.which] )
SDL_PrivateJoystickAxis( SDL_ANDROID_CurrentJoysticks[ev.jaxis.which], ev.jaxis.axis, ev.jaxis.value );
break;
case SDL_JOYBUTTONDOWN:
if( ev.jbutton.which < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[ev.jbutton.which] )
SDL_PrivateJoystickButton( SDL_ANDROID_CurrentJoysticks[ev.jbutton.which], ev.jbutton.button, ev.jbutton.state );
break;
case SDL_JOYBALLMOTION:
if( ev.jball.which < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[ev.jbutton.which] )
SDL_PrivateJoystickBall( SDL_ANDROID_CurrentJoysticks[ev.jball.which], ev.jball.ball, ev.jball.xrel, ev.jball.yrel );
break;
#if SDL_VERSION_ATLEAST(1,3,0)
case SDL_FINGERMOTION:
SDL_SendTouchMotion(0, ev.tfinger.fingerId, 0, (float)ev.tfinger.x / (float)window->w, (float)ev.tfinger.y / (float)window->h, ev.tfinger.pressure);
break;
case SDL_FINGERDOWN:
SDL_SendFingerDown(0, ev.tfinger.fingerId, ev.tfinger.state ? 1 : 0, (float)ev.tfinger.x / (float)window->w, (float)ev.tfinger.y / (float)window->h, ev.tfinger.pressure);
break;
case SDL_TEXTINPUT:
SDL_SendKeyboardText(ev.text.text);
break;
#endif
}
SDL_mutexP(BufferedEventsMutex);
}
SDL_mutexV(BufferedEventsMutex);
};
// Queue events to main thread
static int getNextEventAndLock()
{
int nextEvent;
if( !BufferedEventsMutex )
return -1;
SDL_mutexP(BufferedEventsMutex);
nextEvent = BufferedEventsEnd;
nextEvent++;
if( nextEvent >= MAX_BUFFERED_EVENTS )
nextEvent = 0;
while( nextEvent == BufferedEventsStart )
{
SDL_mutexV(BufferedEventsMutex);
if( SDL_ANDROID_InsideVideoThread() )
SDL_ANDROID_PumpEvents();
else
SDL_Delay(100);
SDL_mutexP(BufferedEventsMutex);
nextEvent = BufferedEventsEnd;
nextEvent++;
if( nextEvent >= MAX_BUFFERED_EVENTS )
nextEvent = 0;
}
return nextEvent;
}
static int getPrevEventNoLock()
{
int prevEvent;
if(BufferedEventsStart == BufferedEventsEnd)
return -1;
prevEvent = BufferedEventsEnd;
prevEvent--;
if( prevEvent < 0 )
prevEvent = MAX_BUFFERED_EVENTS - 1;
return prevEvent;
}
extern void SDL_ANDROID_MainThreadPushMouseMotion(int x, int y)
{
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
int prevEvent = getPrevEventNoLock();
if( prevEvent > 0 && BufferedEvents[prevEvent].type == SDL_MOUSEMOTION )
{
// Reuse previous mouse motion event, to prevent mouse movement lag
BufferedEvents[prevEvent].motion.x = x;
BufferedEvents[prevEvent].motion.y = y;
}
else
{
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_MOUSEMOTION;
ev->motion.x = x;
ev->motion.y = y;
}
oldMouseX = x;
oldMouseY = y;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
extern void SDL_ANDROID_MainThreadPushMouseButton(int pressed, int button)
{
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_MOUSEBUTTONDOWN;
ev->button.state = pressed;
ev->button.button = button;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
extern void SDL_ANDROID_MainThreadPushKeyboardKey(int pressed, SDL_scancode key)
{
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
if( moveMouseWithArrowKeys && (
key == SDL_KEY(UP) || key == SDL_KEY(DOWN) ||
key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) ) )
{
if( moveMouseWithKbX < 0 )
{
moveMouseWithKbX = oldMouseX;
moveMouseWithKbY = oldMouseY;
}
if( pressed )
{
if( key == SDL_KEY(LEFT) )
{
if( moveMouseWithKbSpeedX > 0 )
moveMouseWithKbSpeedX = 0;
moveMouseWithKbSpeedX -= moveMouseWithKbSpeed;
moveMouseWithKbAccelX = -moveMouseWithKbAccel;
moveMouseWithKbAccelUpdateNeeded |= 1;
}
else if( key == SDL_KEY(RIGHT) )
{
if( moveMouseWithKbSpeedX < 0 )
moveMouseWithKbSpeedX = 0;
moveMouseWithKbSpeedX += moveMouseWithKbSpeed;
moveMouseWithKbAccelX = moveMouseWithKbAccel;
moveMouseWithKbAccelUpdateNeeded |= 1;
}
if( key == SDL_KEY(UP) )
{
if( moveMouseWithKbSpeedY > 0 )
moveMouseWithKbSpeedY = 0;
moveMouseWithKbSpeedY -= moveMouseWithKbSpeed;
moveMouseWithKbAccelY = -moveMouseWithKbAccel;
moveMouseWithKbAccelUpdateNeeded |= 2;
}
else if( key == SDL_KEY(DOWN) )
{
if( moveMouseWithKbSpeedY < 0 )
moveMouseWithKbSpeedY = 0;
moveMouseWithKbSpeedY += moveMouseWithKbSpeed;
moveMouseWithKbAccelY = moveMouseWithKbAccel;
moveMouseWithKbAccelUpdateNeeded |= 2;
}
}
else
{
if( key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) )
{
moveMouseWithKbSpeedX = 0;
moveMouseWithKbAccelX = 0;
moveMouseWithKbAccelUpdateNeeded &= ~1;
}
if( key == SDL_KEY(UP) || key == SDL_KEY(DOWN) )
{
moveMouseWithKbSpeedY = 0;
moveMouseWithKbAccelY = 0;
moveMouseWithKbAccelUpdateNeeded &= ~2;
}
}
moveMouseWithKbX += moveMouseWithKbSpeedX;
moveMouseWithKbY += moveMouseWithKbSpeedY;
SDL_mutexV(BufferedEventsMutex);
SDL_ANDROID_MainThreadPushMouseMotion(moveMouseWithKbX, moveMouseWithKbY);
return;
}
ev->type = SDL_KEYDOWN;
ev->key.state = pressed;
ev->key.keysym.scancode = key;
ev->key.keysym.sym = key;
ev->key.keysym.mod = KMOD_NONE;
ev->key.keysym.unicode = 0;
#if SDL_VERSION_ATLEAST(1,3,0)
#else
if ( SDL_TranslateUNICODE )
#endif
ev->key.keysym.unicode = key;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
extern void SDL_ANDROID_MainThreadPushJoystickAxis(int joy, int axis, int value)
{
if( ! ( joy < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[joy] ) )
return;
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_JOYAXISMOTION;
ev->jaxis.which = joy;
ev->jaxis.axis = axis;
ev->jaxis.value = value;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
extern void SDL_ANDROID_MainThreadPushJoystickButton(int joy, int button, int pressed)
{
if( ! ( joy < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[joy] ) )
return;
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_JOYBUTTONDOWN;
ev->jbutton.which = joy;
ev->jbutton.button = button;
ev->jbutton.state = pressed;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
extern void SDL_ANDROID_MainThreadPushJoystickBall(int joy, int ball, int x, int y)
{
if( ! ( joy < MAX_MULTITOUCH_POINTERS+1 && SDL_ANDROID_CurrentJoysticks[joy] ) )
return;
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_JOYBALLMOTION;
ev->jball.which = joy;
ev->jball.ball = ball;
ev->jball.xrel = x;
ev->jball.yrel = y;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
}
extern void SDL_ANDROID_MainThreadPushMultitouchButton(int id, int pressed, int x, int y, int force)
{
#if SDL_VERSION_ATLEAST(1,3,0)
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_FINGERDOWN;
ev->tfinger.fingerId = id;
ev->tfinger.state = pressed;
ev->tfinger.x = x;
ev->tfinger.y = y;
ev->tfinger.pressure = force;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
#endif
};
extern void SDL_ANDROID_MainThreadPushMultitouchMotion(int id, int x, int y, int force)
{
#if SDL_VERSION_ATLEAST(1,3,0)
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
ev->type = SDL_FINGERMOTION;
ev->tfinger.fingerId = id;
ev->tfinger.x = x;
ev->tfinger.y = y;
ev->tfinger.pressure = force;
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
#endif
};
enum { DEFERRED_TEXT_COUNT = 256 };
static struct { int scancode; int unicode; int down; } deferredText[DEFERRED_TEXT_COUNT];
static int deferredTextIdx1 = 0;
static int deferredTextIdx2 = 0;
static SDL_mutex * deferredTextMutex = NULL;
static SDL_keysym asciiToKeysym(int ascii, int unicode)
{
SDL_keysym keysym;
keysym.scancode = ascii;
keysym.sym = ascii;
keysym.mod = KMOD_NONE;
keysym.unicode = 0;
#if SDL_VERSION_ATLEAST(1,3,0)
keysym.sym = SDL_GetScancodeFromKey(ascii);
#else
if ( SDL_TranslateUNICODE )
#endif
keysym.unicode = unicode;
return keysym;
}
static int checkShiftRequired( int * sym )
{
switch( *sym )
{
case '!': *sym = '1'; return 1;
case '@': *sym = '2'; return 1;
case '#': *sym = '3'; return 1;
case '$': *sym = '4'; return 1;
case '%': *sym = '5'; return 1;
case '^': *sym = '6'; return 1;
case '&': *sym = '7'; return 1;
case '*': *sym = '8'; return 1;
case '(': *sym = '9'; return 1;
case ')': *sym = '0'; return 1;
case '_': *sym = '-'; return 1;
case '+': *sym = '='; return 1;
case '|': *sym = '\\';return 1;
case '<': *sym = ','; return 1;
case '>': *sym = '.'; return 1;
case '?': *sym = '/'; return 1;
case ':': *sym = ';'; return 1;
case '"': *sym = '\'';return 1;
case '{': *sym = '['; return 1;
case '}': *sym = ']'; return 1;
case '~': *sym = '`'; return 1;
default: if( *sym >= 'A' && *sym <= 'Z' ) { *sym += 'a' - 'A'; return 1; };
}
return 0;
}
void SDL_ANDROID_DeferredTextInput()
{
if( !deferredTextMutex )
deferredTextMutex = SDL_CreateMutex();
SDL_mutexP(deferredTextMutex);
if( deferredTextIdx1 != deferredTextIdx2 )
{
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
{
SDL_mutexV(deferredTextMutex);
return;
}
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
deferredTextIdx1++;
if( deferredTextIdx1 >= DEFERRED_TEXT_COUNT )
deferredTextIdx1 = 0;
ev->type = SDL_KEYDOWN;
ev->key.state = deferredText[deferredTextIdx1].down;
ev->key.keysym = asciiToKeysym( deferredText[deferredTextIdx1].scancode, deferredText[deferredTextIdx1].unicode );
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
SDL_ANDROID_MainThreadPushMouseMotion(oldMouseX + (oldMouseX % 2 ? -1 : 1), oldMouseY); // Force screen redraw
}
SDL_mutexV(deferredTextMutex);
};
extern void SDL_ANDROID_MainThreadPushText( int ascii, int unicode )
{
int shiftRequired;
//__android_log_print(ANDROID_LOG_INFO, "libSDL", "SDL_ANDROID_MainThreadPushText(): %i %i", scancode, unicode);
int nextEvent = getNextEventAndLock();
if( nextEvent == -1 )
return;
SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
#if SDL_VERSION_ATLEAST(1,3,0)
ev->type = SDL_TEXTINPUT;
UnicodeToUtf8(unicode, ev->text.text);
#endif
if( !deferredTextMutex )
deferredTextMutex = SDL_CreateMutex();
SDL_mutexP(deferredTextMutex);
ev->type = 0;
shiftRequired = checkShiftRequired(&ascii);
if( shiftRequired )
{
deferredTextIdx2++;
if( deferredTextIdx2 >= DEFERRED_TEXT_COUNT )
deferredTextIdx2 = 0;
deferredText[deferredTextIdx2].down = SDL_PRESSED;
deferredText[deferredTextIdx2].scancode = SDLK_LSHIFT;
deferredText[deferredTextIdx2].unicode = 0;
}
deferredTextIdx2++;
if( deferredTextIdx2 >= DEFERRED_TEXT_COUNT )
deferredTextIdx2 = 0;
deferredText[deferredTextIdx2].down = SDL_PRESSED;
deferredText[deferredTextIdx2].scancode = ascii;
deferredText[deferredTextIdx2].unicode = unicode;
deferredTextIdx2++;
if( deferredTextIdx2 >= DEFERRED_TEXT_COUNT )
deferredTextIdx2 = 0;
deferredText[deferredTextIdx2].down = SDL_RELEASED;
deferredText[deferredTextIdx2].scancode = ascii;
deferredText[deferredTextIdx2].unicode = unicode;
if( shiftRequired )
{
deferredTextIdx2++;
if( deferredTextIdx2 >= DEFERRED_TEXT_COUNT )
deferredTextIdx2 = 0;
deferredText[deferredTextIdx2].down = SDL_RELEASED;
deferredText[deferredTextIdx2].scancode = SDLK_LSHIFT;
deferredText[deferredTextIdx2].unicode = 0;
}
SDL_mutexV(deferredTextMutex);
BufferedEventsEnd = nextEvent;
SDL_mutexV(BufferedEventsMutex);
};
Uint32 lastMoveMouseWithKeyboardUpdate = 0;
void SDL_ANDROID_processMoveMouseWithKeyboard()
{
if( ! moveMouseWithKbAccelUpdateNeeded )
return;
Uint32 ticks = SDL_GetTicks();
if( ticks - lastMoveMouseWithKeyboardUpdate < 20 ) // Update at 50 FPS max, or it will not work properlty on very fast devices
return;
lastMoveMouseWithKeyboardUpdate = ticks;
moveMouseWithKbSpeedX += moveMouseWithKbAccelX;
moveMouseWithKbSpeedY += moveMouseWithKbAccelY;
moveMouseWithKbX += moveMouseWithKbSpeedX;
moveMouseWithKbY += moveMouseWithKbSpeedY;
SDL_ANDROID_MainThreadPushMouseMotion(moveMouseWithKbX, moveMouseWithKbY);
};
extern void SDL_ANDROID_ProcessDeferredEvents()
{
SDL_ANDROID_DeferredTextInput();
ProcessDeferredMouseTap();
};
void ANDROID_InitOSKeymap()
{
#if (SDL_VERSION_ATLEAST(1,3,0))
SDLKey defaultKeymap[SDL_NUM_SCANCODES];
SDL_GetDefaultKeymap(defaultKeymap);
SDL_SetKeymap(0, defaultKeymap, SDL_NUM_SCANCODES);
SDL_Touch touch;
memset( &touch, 0, sizeof(touch) );
touch.x_min = touch.y_min = touch.pressure_min = 0.0f;
touch.pressure_max = 1000000;
touch.x_max = SDL_ANDROID_sWindowWidth;
touch.y_max = SDL_ANDROID_sWindowHeight;
// These constants are hardcoded inside SDL_touch.c, which makes no sense for me.
touch.xres = touch.yres = 32768;
touch.native_xres = touch.native_yres = 32768.0f;
touch.pressureres = 1;
touch.native_pressureres = 1.0f;
touch.id = 0;
SDL_AddTouch(&touch, "Android touch screen");
#endif
}
JNIEXPORT jint JNICALL
JAVA_EXPORT_NAME(Settings_nativeGetKeymapKey) (JNIEnv* env, jobject thiz, jint code)
{
if( code < 0 || code > KEYCODE_LAST )
return SDL_KEY(UNKNOWN);
return SDL_android_keymap[code];
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetKeymapKey) (JNIEnv* env, jobject thiz, jint javakey, jint key)
{
if( javakey < 0 || javakey > KEYCODE_LAST )
return;
SDL_android_keymap[javakey] = key;
}
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( key >= 0 && !used )
SDL_ANDROID_SetScreenKeyboardButtonPos(key, &rect);
}
JNIEXPORT jint JNICALL
JAVA_EXPORT_NAME(Settings_nativeGetKeymapKeyMultitouchGesture) (JNIEnv* env, jobject thiz, jint keynum)
{
if( keynum < 0 || keynum >= MAX_MULTITOUCH_GESTURES )
return SDL_KEY(UNKNOWN);
return multitouchGestureKeycode[keynum];
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetKeymapKeyMultitouchGesture) (JNIEnv* env, jobject thiz, jint keynum, jint keycode)
{
if( keynum < 0 || keynum >= MAX_MULTITOUCH_GESTURES )
return;
multitouchGestureKeycode[keynum] = keycode;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetMultitouchGestureSensitivity) (JNIEnv* env, jobject thiz, jint sensitivity)
{
multitouchGestureSensitivity = sensitivity;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeSetTouchscreenCalibration) (JNIEnv* env, jobject thiz, jint x1, jint y1, jint x2, jint y2)
{
SDL_ANDROID_TouchscreenCalibrationX = x1;
SDL_ANDROID_TouchscreenCalibrationY = y1;
SDL_ANDROID_TouchscreenCalibrationWidth = x2 - x1;
SDL_ANDROID_TouchscreenCalibrationHeight = y2 - y1;
}
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;
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( key >= 0 )
{
ScreenKbRedefinedByUser = 1;
SDL_ANDROID_SetScreenKeyboardButtonPos(key, &rect);
}
}
int SDL_ANDROID_GetScreenKeyboardRedefinedByUser()
{
return ScreenKbRedefinedByUser;
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(Settings_nativeInitKeymap) ( JNIEnv* env, jobject thiz )
{
SDL_android_init_keymap(SDL_android_keymap);
}