fix: add suppord android 9 gamepad and remote control (#2302)

This commit is contained in:
NickVs2015
2026-03-03 10:14:51 +03:00
committed by GitHub
parent befb2bf19a
commit c86a641e05

View File

@@ -92,7 +92,7 @@ class AmneziaActivity : QtActivity() {
private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>() private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>() private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>()
private var isActivityResumed = false private var isActivityResumed = false
private var hasWindowFocus = false private var hasWindowFocus = false
private val resumeHandler = Handler(Looper.getMainLooper()) private val resumeHandler = Handler(Looper.getMainLooper())
@@ -295,7 +295,7 @@ class AmneziaActivity : QtActivity() {
super.onWindowFocusChanged(hasFocus) super.onWindowFocusChanged(hasFocus)
hasWindowFocus = hasFocus hasWindowFocus = hasFocus
Log.d(TAG, "Window focus changed: hasFocus=$hasFocus") Log.d(TAG, "Window focus changed: hasFocus=$hasFocus")
// Cancel pending operations if window loses focus // Cancel pending operations if window loses focus
if (!hasFocus) { if (!hasFocus) {
resumeHandler.removeCallbacksAndMessages(null) resumeHandler.removeCallbacksAndMessages(null)
@@ -309,68 +309,93 @@ class AmneziaActivity : QtActivity() {
val source = event.source val source = event.source
if (deviceId < 0 && pressed) { if (deviceId < 0 && pressed) {
when (keyCode) { when (keyCode) {
KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B, KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X, KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y, KeyEvent.KEYCODE_BUTTON_Y,
KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_BUTTON_START,
KeyEvent.KEYCODE_BUTTON_SELECT -> { KeyEvent.KEYCODE_BUTTON_SELECT -> {
nativeGamepadKeyEvent(0, keyCode, true) nativeGamepadKeyEvent(0, keyCode, true)
nativeGamepadKeyEvent(0, keyCode, false) nativeGamepadKeyEvent(0, keyCode, false)
return true return true
} }
KeyEvent.KEYCODE_DPAD_CENTER -> { KeyEvent.KEYCODE_DPAD_CENTER -> {
if (isOnTv()) { if (isOnTv()) {
val down = KeyEvent( val down = KeyEvent(
event.downTime, event.downTime,
event.eventTime, event.eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER,
0, 0,
event.metaState, event.metaState,
0, 0,
event.scanCode, event.scanCode,
event.flags, event.flags,
event.source event.source
) )
val up = KeyEvent( val up = KeyEvent(
event.downTime, event.downTime,
event.eventTime, event.eventTime,
KeyEvent.ACTION_UP, KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER,
0, 0,
event.metaState, event.metaState,
0, 0,
event.scanCode, event.scanCode,
event.flags, event.flags,
event.source event.source
) )
super.dispatchKeyEvent(down) super.dispatchKeyEvent(down)
super.dispatchKeyEvent(up) super.dispatchKeyEvent(up)
return true return true
} }
nativeGamepadKeyEvent(0, keyCode, true) nativeGamepadKeyEvent(0, keyCode, true)
nativeGamepadKeyEvent(0, keyCode, false) nativeGamepadKeyEvent(0, keyCode, false)
return true return true
} }
} }
} }
// Real gamepad events (deviceId >= 0) // Real devices (remotes and gamepads) have deviceId >= 0.
if (deviceId >= 0) { if (deviceId >= 0) {
val isGamepad = (source and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD val isGamepad = (source and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
val isJoystick = (source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK val isJoystick = (source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
val isDpad = (source and InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD val isDpad = (source and InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
if (isGamepad || isJoystick || isDpad) { if (isGamepad || isJoystick || isDpad) {
nativeGamepadKeyEvent(deviceId, keyCode, pressed) when (keyCode) {
return true KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y,
KeyEvent.KEYCODE_BUTTON_START,
KeyEvent.KEYCODE_BUTTON_SELECT,
KeyEvent.KEYCODE_DPAD_CENTER -> {
nativeGamepadKeyEvent(0, keyCode, pressed)
return true
}
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT -> {
val synthetic = KeyEvent(
event.downTime, event.eventTime, event.action, event.keyCode,
event.repeatCount, event.metaState, -1, event.scanCode,
event.flags, InputDevice.SOURCE_KEYBOARD
)
return super.dispatchKeyEvent(synthetic)
}
}
return super.dispatchKeyEvent(event)
} }
} }
return super.dispatchKeyEvent(event) return super.dispatchKeyEvent(event)
} }
private external fun nativeGamepadKeyEvent(deviceId: Int, keyCode: Int, pressed: Boolean) private external fun nativeGamepadKeyEvent(deviceId: Int, keyCode: Int, pressed: Boolean)
override fun onPause() { override fun onPause() {
@@ -412,13 +437,13 @@ class AmneziaActivity : QtActivity() {
sendTouch(1f, 1f) sendTouch(1f, 1f)
} }
}, 100) }, 100)
resumeHandler.postDelayed({ resumeHandler.postDelayed({
if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) { if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) {
sendTouch(2f, 2f) sendTouch(2f, 2f)
} }
}, 200) }, 200)
resumeHandler.postDelayed({ resumeHandler.postDelayed({
if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) { if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) {
requestLayout() requestLayout()
@@ -464,25 +489,25 @@ class AmneziaActivity : QtActivity() {
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, windowInsets -> ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, windowInsets ->
val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime()) val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
val imeVisible = windowInsets.isVisible(WindowInsetsCompat.Type.ime()) val imeVisible = windowInsets.isVisible(WindowInsetsCompat.Type.ime())
val imeHeight = if (imeVisible) imeInsets.bottom else 0 val imeHeight = if (imeVisible) imeInsets.bottom else 0
val density = resources.displayMetrics.density val density = resources.displayMetrics.density
val imeHeightDp = (imeHeight / density).toInt() val imeHeightDp = (imeHeight / density).toInt()
// Also track system bars (navigation bar, status bar) changes // Also track system bars (navigation bar, status bar) changes
val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val navBarHeight = systemBarsInsets.bottom val navBarHeight = systemBarsInsets.bottom
val navBarHeightDp = (navBarHeight / density).toInt() val navBarHeightDp = (navBarHeight / density).toInt()
val statusBarHeight = systemBarsInsets.top val statusBarHeight = systemBarsInsets.top
val statusBarHeightDp = (statusBarHeight / density).toInt() val statusBarHeightDp = (statusBarHeight / density).toInt()
mainScope.launch { mainScope.launch {
qtInitialized.await() qtInitialized.await()
QtAndroidController.onImeInsetsChanged(imeHeightDp) QtAndroidController.onImeInsetsChanged(imeHeightDp)
QtAndroidController.onSystemBarsInsetsChanged(navBarHeightDp, statusBarHeightDp) QtAndroidController.onSystemBarsInsetsChanged(navBarHeightDp, statusBarHeightDp)
} }
// Return windowInsets instead of CONSUMED to allow proper handling // Return windowInsets instead of CONSUMED to allow proper handling
windowInsets windowInsets
} }