mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
fix: add suppord android 9 gamepad and remote control (#2302)
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user