mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
feat: add gamepad buttons support android (#2066)
* feat: add support gamepad buttons * feat: add support gamepad with github repo * feat: add gitmodules dependency * feat: add submodule qtgamepad * chore: update qtgamepad submodule to commit 4e57142e563b931766056b4c7507c16892260222 * fix: update qtgamepad with standard CMake and private headers support Update qtgamepad to commit f72b3e0 which: - Replaces qt_add_library with standard add_library to avoid Qt 6.10 macro conflicts - Copies private headers to build include tree for Android backend - Creates Qt:: and Qt6:: namespace aliases for proper linking
This commit is contained in:
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -14,3 +14,7 @@
|
|||||||
[submodule "client/3rd/QSimpleCrypto"]
|
[submodule "client/3rd/QSimpleCrypto"]
|
||||||
path = client/3rd/QSimpleCrypto
|
path = client/3rd/QSimpleCrypto
|
||||||
url = https://github.com/amnezia-vpn/QSimpleCrypto.git
|
url = https://github.com/amnezia-vpn/QSimpleCrypto.git
|
||||||
|
[submodule "client/3rd/qtgamepad"]
|
||||||
|
path = client/3rd/qtgamepad
|
||||||
|
url = https://github.com/amnezia-vpn/qtgamepad.git
|
||||||
|
branch = 6.6
|
||||||
|
|||||||
1
client/3rd/qtgamepad
vendored
Submodule
1
client/3rd/qtgamepad
vendored
Submodule
Submodule client/3rd/qtgamepad added at f72b3e0c62
@@ -39,6 +39,11 @@ endif()
|
|||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
|
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
|
||||||
|
|
||||||
|
# Android: Qt private modules (like CorePrivate) are needed by qtgamepad
|
||||||
|
if(ANDROID)
|
||||||
|
find_package(Qt6CorePrivate CONFIG REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(LIBS ${LIBS}
|
set(LIBS ${LIBS}
|
||||||
Qt6::Core Qt6::Gui
|
Qt6::Core Qt6::Gui
|
||||||
Qt6::Network Qt6::Xml Qt6::RemoteObjects
|
Qt6::Network Qt6::Xml Qt6::RemoteObjects
|
||||||
@@ -228,4 +233,13 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||||
qt_finalize_target(${PROJECT})
|
|
||||||
|
# Finalize the executable so Qt can gather/deploy QML modules and plugins correctly (Android needs this).
|
||||||
|
if(COMMAND qt_import_qml_plugins)
|
||||||
|
qt_import_qml_plugins(${PROJECT})
|
||||||
|
endif()
|
||||||
|
if(COMMAND qt_finalize_executable)
|
||||||
|
qt_finalize_executable(${PROJECT})
|
||||||
|
else()
|
||||||
|
qt_finalize_target(${PROJECT})
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import android.os.ParcelFileDescriptor
|
|||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.provider.OpenableColumns
|
import android.provider.OpenableColumns
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.view.InputDevice
|
||||||
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -274,6 +276,44 @@ class AmneziaActivity : QtActivity() {
|
|||||||
Log.d(TAG, "Window focus changed: hasFocus=$hasFocus")
|
Log.d(TAG, "Window focus changed: hasFocus=$hasFocus")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||||
|
val deviceId = event.deviceId
|
||||||
|
val keyCode = event.keyCode
|
||||||
|
val pressed = event.action == KeyEvent.ACTION_DOWN
|
||||||
|
val source = event.source
|
||||||
|
|
||||||
|
if (deviceId < 0 && pressed) {
|
||||||
|
when (keyCode) {
|
||||||
|
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, true)
|
||||||
|
nativeGamepadKeyEvent(0, keyCode, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real gamepad events (deviceId >= 0)
|
||||||
|
if (deviceId >= 0) {
|
||||||
|
val isGamepad = (source and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
|
||||||
|
val isJoystick = (source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
|
||||||
|
val isDpad = (source and InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
|
||||||
|
if (isGamepad || isJoystick || isDpad) {
|
||||||
|
nativeGamepadKeyEvent(deviceId, keyCode, pressed)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.dispatchKeyEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun nativeGamepadKeyEvent(deviceId: Int, keyCode: Int, pressed: Boolean)
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
Log.d(TAG, "Pause Amnezia activity")
|
Log.d(TAG, "Pause Amnezia activity")
|
||||||
|
|||||||
@@ -83,6 +83,19 @@ add_compile_definitions(_WINSOCKAPI_)
|
|||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_WITH_QT6 ON)
|
set(BUILD_WITH_QT6 ON)
|
||||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain)
|
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain)
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
# Use qtgamepad from amnezia-vpn/qtgamepad repository
|
||||||
|
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtgamepad)
|
||||||
|
# Link both the C++ module and QML plugin
|
||||||
|
if(TARGET GamepadLegacy)
|
||||||
|
target_link_libraries(${PROJECT} PRIVATE GamepadLegacy)
|
||||||
|
endif()
|
||||||
|
if(TARGET GamepadLegacyQuickPrivate)
|
||||||
|
target_link_libraries(${PROJECT} PRIVATE GamepadLegacyQuickPrivate)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
set(LIBS ${LIBS} qt6keychain)
|
set(LIBS ${LIBS} qt6keychain)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import QtQuick.Dialogs
|
|||||||
|
|
||||||
import PageEnum 1.0
|
import PageEnum 1.0
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
import QtGamepadLegacy
|
||||||
|
|
||||||
import "Config"
|
import "Config"
|
||||||
import "Controls2"
|
import "Controls2"
|
||||||
@@ -83,6 +84,44 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: Qt.platform.os === "android"
|
||||||
|
sourceComponent: Component {
|
||||||
|
Item {
|
||||||
|
Gamepad {
|
||||||
|
id: gamepad
|
||||||
|
deviceId: GamepadManager.connectedGamepads.length > 0 ? GamepadManager.connectedGamepads[0] : -1
|
||||||
|
|
||||||
|
onButtonStartChanged: {
|
||||||
|
if (buttonStart) {
|
||||||
|
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
|
||||||
|
ConnectionController.connectButtonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GamepadKeyNavigation {
|
||||||
|
id: gamepadKeyNav
|
||||||
|
gamepad: gamepad
|
||||||
|
active: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: GamepadManager
|
||||||
|
function onConnectedGamepadsChanged() {
|
||||||
|
if (GamepadManager.connectedGamepads.length > 0) {
|
||||||
|
gamepad.deviceId = GamepadManager.connectedGamepads[0]
|
||||||
|
} else {
|
||||||
|
gamepad.deviceId = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
objectName: "pageControllerConnections"
|
objectName: "pageControllerConnections"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user