void SDL_ANDROID_DeferredTextInput()
{
	if( !deferredTextMutex )
		deferredTextMutex = SDL_CreateMutex();

	SDL_mutexP(deferredTextMutex);
	
	if( deferredTextIdx1 != deferredTextIdx2 )
	{
		SDL_keysym keysym;

		deferredTextIdx1++;
		if( deferredTextIdx1 >= DEFERRED_TEXT_COUNT )
			deferredTextIdx1 = 0;
		
		keysym = asciiToKeysym( deferredText[deferredTextIdx1].scancode, deferredText[deferredTextIdx1].unicode );
		if( deferredText[deferredTextIdx1].down == SDL_RELEASED )
			keysym.unicode = 0;

		SDL_SendKeyboardKey( deferredText[deferredTextIdx1].down, &keysym );

		if( SDL_ANDROID_isMouseUsed )
			SDL_ANDROID_MainThreadPushMouseMotion(SDL_ANDROID_currentMouseX + (SDL_ANDROID_currentMouseX % 2 ? -1 : 1), SDL_ANDROID_currentMouseY); // Force screen redraw
	}
	else
	{
		if( SDL_ANDROID_TextInputFinished )
		{
			SDL_ANDROID_TextInputFinished = 0;
			SDL_ANDROID_IsScreenKeyboardShownFlag = 0;
		}
	}
	
	SDL_mutexV(deferredTextMutex);
}
JNIEXPORT void JNICALL
JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMotionEvent) ( JNIEnv*  env, jobject  thiz, jint x, jint y)
{
    if( !SDL_CurrentVideoSurface )
        return;

    SDL_ANDROID_MainThreadPushMouseMotion(x, y);
}
void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, char * outBuf, int outBufLen)
{
	// Clear mouse button state, to avoid repeated clicks on the text field in some apps
	SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_LEFT );
	SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_RIGHT );
	SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, SDL_BUTTON_MIDDLE );

	SDL_ANDROID_TextInputFinished = 0;
	SDL_ANDROID_IsScreenKeyboardShownFlag = 1;
	if( !outBuf )
	{
		showScreenKeyboardDeferred = 1;
		showScreenKeyboardOldText = oldText;
		showScreenKeyboardSendBackspace = 1;
		// Move mouse by 1 pixel to force screen update
		int x, y;
		SDL_GetMouseState( &x, &y );
		SDL_ANDROID_MainThreadPushMouseMotion(x > 0 ? x-1 : 0, y);
	}
	else
	{
		SDL_ANDROID_TextInputInit(outBuf, outBufLen);

		if( SDL_ANDROID_VideoMultithreaded )
		{
#if SDL_VERSION_ATLEAST(1,3,0)
#else
			// Dirty hack: we may call (*JavaEnv)->CallVoidMethod(...) only from video thread
			showScreenKeyboardDeferred = 1;
			showScreenKeyboardOldText = oldText;
			showScreenKeyboardSendBackspace = 0;
			SDL_Flip(SDL_GetVideoSurface());
#endif
		}
		else
		{
			(*JavaEnv)->PushLocalFrame(JavaEnv, 1);
			jstring s = (*JavaEnv)->NewStringUTF( JavaEnv, oldText );
			(*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaShowScreenKeyboard, s, 0 );
			(*JavaEnv)->DeleteLocalRef( JavaEnv, s );
			(*JavaEnv)->PopLocalFrame(JavaEnv, NULL);
		}

		while( !SDL_ANDROID_TextInputFinished )
			SDL_Delay(100);
		SDL_ANDROID_TextInputFinished = 0;
		SDL_ANDROID_IsScreenKeyboardShownFlag = 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);
		if( SDL_ANDROID_isMouseUsed )
			SDL_ANDROID_MainThreadPushMouseMotion(SDL_ANDROID_currentMouseX + (SDL_ANDROID_currentMouseX % 2 ? -1 : 1), SDL_ANDROID_currentMouseY); // Force screen redraw
	}
	else
	{
		if( SDL_ANDROID_TextInputFinished )
		{
			SDL_ANDROID_TextInputFinished = 0;
			SDL_ANDROID_IsScreenKeyboardShownFlag = 0;
		}
	}
	
	SDL_mutexV(deferredTextMutex);
};
void SDL_ANDROID_CallJavaShowScreenKeyboard(const char * oldText, char * outBuf, int outBufLen)
{
	SDL_ANDROID_TextInputFinished = 0;
	SDL_ANDROID_IsScreenKeyboardShownFlag = 1;
	if( !outBuf )
	{
		showScreenKeyboardDeferred = 1;
		showScreenKeyboardOldText = oldText;
		showScreenKeyboardSendBackspace = 1;
		// Move mouse by 1 pixel to force screen update
		int x, y;
		SDL_GetMouseState( &x, &y );
		SDL_ANDROID_MainThreadPushMouseMotion(x > 0 ? x-1 : 0, y);
	}
	else
	{
		SDL_ANDROID_TextInputInit(outBuf, outBufLen);

		if( SDL_ANDROID_VideoMultithreaded )
		{
#if SDL_VERSION_ATLEAST(1,3,0)
#else
			// Dirty hack: we may call (*JavaEnv)->CallVoidMethod(...) only from video thread
			showScreenKeyboardDeferred = 1;
			showScreenKeyboardOldText = oldText;
			showScreenKeyboardSendBackspace = 0;
			SDL_Flip(SDL_GetVideoSurface());
#endif
		}
		else
			(*JavaEnv)->CallVoidMethod( JavaEnv, JavaRenderer, JavaShowScreenKeyboard, (*JavaEnv)->NewStringUTF(JavaEnv, oldText), 0 );

		while( !SDL_ANDROID_TextInputFinished )
			SDL_Delay(100);
		SDL_ANDROID_TextInputFinished = 0;
		SDL_ANDROID_IsScreenKeyboardShownFlag = 0;
	}
}
extern void SDL_ANDROID_MainThreadPushKeyboardKey(int pressed, SDL_scancode key, int unicode)
{
	SDL_keysym keysym;

	if( SDL_ANDROID_moveMouseWithArrowKeys && (
		key == SDL_KEY(UP) || key == SDL_KEY(DOWN) ||
		key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) ) )
	{
		if( SDL_ANDROID_moveMouseWithKbX < 0 )
		{
			SDL_ANDROID_moveMouseWithKbX = SDL_ANDROID_currentMouseX;
			SDL_ANDROID_moveMouseWithKbY = SDL_ANDROID_currentMouseY;
		}

		if( pressed )
		{
			if( key == SDL_KEY(LEFT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}
			else if( key == SDL_KEY(RIGHT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}

			if( key == SDL_KEY(UP) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
			else if( key == SDL_KEY(DOWN) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
		}
		else
		{
			if( key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbAccelX = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~1;
			}
			if( key == SDL_KEY(UP) || key == SDL_KEY(DOWN) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbAccelY = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~2;
			}
		}

		SDL_ANDROID_moveMouseWithKbX += SDL_ANDROID_moveMouseWithKbSpeedX;
		SDL_ANDROID_moveMouseWithKbY += SDL_ANDROID_moveMouseWithKbSpeedY;

		SDL_ANDROID_MainThreadPushMouseMotion(SDL_ANDROID_moveMouseWithKbX, SDL_ANDROID_moveMouseWithKbY);
		return;
	}

	if ( key >= SDLK_MOUSE_LEFT && key <= SDLK_MOUSE_X2 )
	{
		SDL_ANDROID_MainThreadPushMouseButton(pressed, key - SDLK_MOUSE_LEFT + SDL_BUTTON_LEFT);
		return;
	}

	keysym.scancode = key;
	if ( key < SDLK_LAST )
		keysym.scancode = SDL_android_keysym_to_scancode[key];
	keysym.sym = key;
	keysym.mod = KMOD_NONE;
	keysym.unicode = 0;
#if SDL_VERSION_ATLEAST(1,3,0)
#else
	if ( SDL_TranslateUNICODE )
#endif
		keysym.unicode = unicode;
	if( (keysym.unicode & 0xFF80) != 0 )
		keysym.sym = SDLK_WORLD_0;
	//else if( keysym.sym < 0x80 )
	//	keysym.unicode = keysym.sym;

	if( pressed == SDL_RELEASED )
		keysym.unicode = 0;

	//__android_log_print(ANDROID_LOG_INFO, "libSDL","SDL_SendKeyboardKey sym %d scancode %d unicode %d", keysym.sym, keysym.scancode, keysym.unicode);

	SDL_SendKeyboardKey( pressed, &keysym );
}
extern void SDL_ANDROID_MainThreadPushKeyboardKey(int pressed, SDL_scancode key)
{
	SDL_keysym keysym;

	if( SDL_ANDROID_moveMouseWithArrowKeys && (
		key == SDL_KEY(UP) || key == SDL_KEY(DOWN) ||
		key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) ) )
	{
		if( SDL_ANDROID_moveMouseWithKbX < 0 )
		{
			SDL_ANDROID_moveMouseWithKbX = SDL_ANDROID_currentMouseX;
			SDL_ANDROID_moveMouseWithKbY = SDL_ANDROID_currentMouseY;
		}

		if( pressed )
		{
			if( key == SDL_KEY(LEFT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}
			else if( key == SDL_KEY(RIGHT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}

			if( key == SDL_KEY(UP) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
			else if( key == SDL_KEY(DOWN) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
		}
		else
		{
			if( key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbAccelX = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~1;
			}
			if( key == SDL_KEY(UP) || key == SDL_KEY(DOWN) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbAccelY = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~2;
			}
		}

		SDL_ANDROID_moveMouseWithKbX += SDL_ANDROID_moveMouseWithKbSpeedX;
		SDL_ANDROID_moveMouseWithKbY += SDL_ANDROID_moveMouseWithKbSpeedY;

		SDL_ANDROID_MainThreadPushMouseMotion(SDL_ANDROID_moveMouseWithKbX, SDL_ANDROID_moveMouseWithKbY);
		return;
	}

	keysym.scancode = key;
	keysym.sym = key;
	keysym.mod = KMOD_NONE;
	keysym.unicode = 0;
#if SDL_VERSION_ATLEAST(1,3,0)
#else
	if ( SDL_TranslateUNICODE )
#endif
		keysym.unicode = key;

	if( pressed == SDL_RELEASED )
		keysym.unicode = 0;

	SDL_SendKeyboardKey( pressed, &keysym );
}
extern void SDL_ANDROID_MainThreadPushKeyboardKey(int pressed, SDL_scancode key)
{
	int nextEvent = getNextEventAndLock();
	if( nextEvent == -1 )
		return;
	
	SDL_Event * ev = &BufferedEvents[BufferedEventsEnd];
	
	if( SDL_ANDROID_moveMouseWithArrowKeys && (
		key == SDL_KEY(UP) || key == SDL_KEY(DOWN) ||
		key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) ) )
	{
		if( SDL_ANDROID_moveMouseWithKbX < 0 )
		{
			SDL_ANDROID_moveMouseWithKbX = SDL_ANDROID_currentMouseX;
			SDL_ANDROID_moveMouseWithKbY = SDL_ANDROID_currentMouseY;
		}

		if( pressed )
		{
			if( key == SDL_KEY(LEFT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}
			else if( key == SDL_KEY(RIGHT) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedX < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbSpeedX += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelX = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 1;
			}

			if( key == SDL_KEY(UP) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY > 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY -= SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = -SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
			else if( key == SDL_KEY(DOWN) )
			{
				if( SDL_ANDROID_moveMouseWithKbSpeedY < 0 )
					SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbSpeedY += SDL_ANDROID_moveMouseWithKbSpeed;
				SDL_ANDROID_moveMouseWithKbAccelY = SDL_ANDROID_moveMouseWithKbAccel;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded |= 2;
			}
		}
		else
		{
			if( key == SDL_KEY(LEFT) || key == SDL_KEY(RIGHT) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedX = 0;
				SDL_ANDROID_moveMouseWithKbAccelX = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~1;
			}
			if( key == SDL_KEY(UP) || key == SDL_KEY(DOWN) )
			{
				SDL_ANDROID_moveMouseWithKbSpeedY = 0;
				SDL_ANDROID_moveMouseWithKbAccelY = 0;
				SDL_ANDROID_moveMouseWithKbAccelUpdateNeeded &= ~2;
			}
		}

		SDL_ANDROID_moveMouseWithKbX += SDL_ANDROID_moveMouseWithKbSpeedX;
		SDL_ANDROID_moveMouseWithKbY += SDL_ANDROID_moveMouseWithKbSpeedY;

		SDL_mutexV(BufferedEventsMutex);

		SDL_ANDROID_MainThreadPushMouseMotion(SDL_ANDROID_moveMouseWithKbX, SDL_ANDROID_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);
};