diff --git a/Package.swift b/Package.swift index 0f5c3d6e..6c61d0cd 100644 --- a/Package.swift +++ b/Package.swift @@ -81,6 +81,12 @@ var package = Package( ), .library( name: "AndroidFileManager", targets: ["AndroidFileManager"] + ), + .library( + name: "AndroidNativeActivity", targets: ["AndroidNativeActivity"] + ), + .library( + name: "AndroidInput", targets: ["AndroidInput"] ) ], dependencies: [ @@ -153,7 +159,9 @@ var package = Package( "AndroidLogging", "AndroidLooper", "AndroidHardware", - "AndroidFileManager" + "AndroidFileManager", + "AndroidNativeActivity", + "AndroidInput" ], swiftSettings: [ .swiftLanguageMode(.v5), @@ -489,6 +497,42 @@ var package = Package( linkerSettings: [ .linkedLibrary("android", .when(platforms: [.android])) ] + ), + .target( + name: "AndroidNativeActivity", + dependencies: [ + "AndroidNDK", + "AndroidLooper", + "AndroidFileManager", + "AndroidInput", + .product( + name: "SystemPackage", + package: "swift-system" + ) + ], + swiftSettings: [ + .swiftLanguageMode(.v6), + ndkVersionDefine, + sdkVersionDefine + ], + linkerSettings: [ + .linkedLibrary("android", .when(platforms: [.android])) + ] + ), + .target( + name: "AndroidInput", + dependencies: [ + "AndroidNDK", + "AndroidLooper" + ], + swiftSettings: [ + .swiftLanguageMode(.v6), + ndkVersionDefine, + sdkVersionDefine + ], + linkerSettings: [ + .linkedLibrary("android", .when(platforms: [.android])) + ] ) ], swiftLanguageModes: [.v5, .v6] diff --git a/Sources/AndroidHardware/Syscalls.swift b/Sources/AndroidHardware/Syscalls.swift index af01e18e..9aea9a8c 100644 --- a/Sources/AndroidHardware/Syscalls.swift +++ b/Sources/AndroidHardware/Syscalls.swift @@ -17,7 +17,7 @@ func stub() -> Never { fatalError("Not running on Android") } -typealias ALooper_callbackFunc = @convention(c) (Int32, Int32, UnsafeMutableRawPointer?) -> Int32 +public typealias ALooper_callbackFunc = @convention(c) (Int32, Int32, UnsafeMutableRawPointer?) -> Int32 // MARK: - ASensorEvent @@ -29,7 +29,7 @@ typealias ALooper_callbackFunc = @convention(c) (Int32, Int32, UnsafeMutableRawP * version(4) + sensor(4) + type(4) + reserved0(4) + * timestamp(8) + data_union(64) + flags(4) + reserved1(12) */ -public struct ASensorEvent { +public struct ASensorEvent: Sendable { public var version: Int32 // sizeof(struct ASensorEvent) public var sensor: Int32 // sensor identifier public var type: Int32 // sensor type diff --git a/Sources/AndroidInput/GameController.swift b/Sources/AndroidInput/GameController.swift new file mode 100644 index 00000000..a1e6a30d --- /dev/null +++ b/Sources/AndroidInput/GameController.swift @@ -0,0 +1,167 @@ +// +// GameController.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if AGDK +#if os(Android) +import Android +import AndroidNDK +#endif + +/// Swift wrapper for the Android Game Controller (Paddleboat) C API. +@MainActor +public struct GameController: ~Copyable { + + let environment: JNIEnvironment + + public init(context: jobject, environment: JNIEnvironment) throws { + let result = Paddleboat_init(environment, context) + guard result == 0 else { + throw GameController.Error(rawValue: result) ?? GameController.Error.notInitialized + } + guard Paddleboat_isInitialized() else { + throw GameController.Error.notInitialized + } + self.environment = environment + } + + deinit { + Paddleboat_destroy(environment) + } + + public func update() { + Paddleboat_update(environment) + } + + // MARK: - Back button + public static func setBackButtonConsumed(_ consume: Bool) { + Paddleboat_setBackButtonConsumed(consume) + } + + public static func isBackButtonConsumed() -> Bool { + Paddleboat_getBackButtonConsumed() + } + + // MARK: - Controller Info / Data + public static func getControllerStatus(index: Int32) -> ControllerStatus { + ControllerStatus(rawValue: Paddleboat_getControllerStatus(index)) ?? .inactive + } + + public static func getControllerName(index: Int32, bufferSize: Int = 128) -> (ErrorCode, String) { + var buffer = [CChar](repeating: 0, count: bufferSize) + let err = Paddleboat_getControllerName(index, Int32(buffer.count), &buffer) + let code = ErrorCode(rawValue: err) ?? .noError + let name = buffer.withUnsafeBufferPointer { String(cString: $0.baseAddress!) } + return (code, name) + } + + // MARK: - Lights / Vibration + @discardableResult + public func setControllerLight(index: Int32, type: LightType, data: UInt32) -> ErrorCode { + let err = Paddleboat_setControllerLight(index, type.rawValue, data, environment) + return ErrorCode(rawValue: err) ?? .noError + } + + @discardableResult + public func setControllerVibration(index: Int32, vibration: VibrationData) -> ErrorCode { + var cData = Paddleboat_Vibration_Data(duration_ms: vibration.durationMs, + left_motor_intensity: vibration.intensityLeft, + right_motor_intensity: vibration.intensityRight) + let err = Paddleboat_setControllerVibrationData(index, &cData, environment) + return ErrorCode(rawValue: err) ?? .noError + } + + // MARK: - Motion + public static func getIntegratedMotionSensorFlags() -> IntegratedMotionSensorFlags { + IntegratedMotionSensorFlags(rawValue: Paddleboat_getIntegratedMotionSensorFlags()) + } +} + +// MARK: - Supporting Types + +public extension GameController { + + // MARK: - Version / Constants + public static var maxControllers: Int32 { 8 } + + // MARK: - Error + public enum Error: Int32, Swift.Error { + case noError = 0 + case alreadyInitialized = -2000 + case notInitialized = -2001 + case invalidParameter = -2002 + case invalidControllerIndex = -2003 + case noController = -2004 + case featureNotSupported = -2005 + case fileIO = -2006 + case incompatibleMappingData = -2007 + case invalidMappingData = -2008 + case noMouse = -2009 + case initGCMFailure = -2010 + } + + typealias ErrorCode = Error + + public enum ControllerStatus: Int32 { + case inactive = 0 + case active = 1 + case justConnected = 2 + case justDisconnected = 3 + } + + public struct Buttons: OptionSet, Sendable { + public let rawValue: UInt32 + public init(rawValue: UInt32) { self.rawValue = rawValue } + public static let a = Buttons(rawValue: 1 << 0) + public static let b = Buttons(rawValue: 1 << 1) + public static let x = Buttons(rawValue: 1 << 2) + public static let y = Buttons(rawValue: 1 << 3) + public static let l1 = Buttons(rawValue: 1 << 4) + public static let r1 = Buttons(rawValue: 1 << 5) + public static let l2 = Buttons(rawValue: 1 << 6) + public static let r2 = Buttons(rawValue: 1 << 7) + public static let l3 = Buttons(rawValue: 1 << 8) + public static let r3 = Buttons(rawValue: 1 << 9) + public static let dpadUp = Buttons(rawValue: 1 << 10) + public static let dpadDown = Buttons(rawValue: 1 << 11) + public static let dpadLeft = Buttons(rawValue: 1 << 12) + public static let dpadRight = Buttons(rawValue: 1 << 13) + public static let start = Buttons(rawValue: 1 << 14) + public static let select = Buttons(rawValue: 1 << 15) + public static let system = Buttons(rawValue: 1 << 16) + public static let touchpad = Buttons(rawValue: 1 << 17) + public static let aux1 = Buttons(rawValue: 1 << 18) + public static let aux2 = Buttons(rawValue: 1 << 19) + public static let aux3 = Buttons(rawValue: 1 << 20) + public static let aux4 = Buttons(rawValue: 1 << 21) + } + + public enum LightType: Int32 { + case playerNumber = 0 + case rgb = 1 + } + + public struct IntegratedMotionSensorFlags: OptionSet, Sendable { + public let rawValue: UInt32 + public init(rawValue: UInt32) { self.rawValue = rawValue } + public static let none = IntegratedMotionSensorFlags([]) + public static let accelerometer = IntegratedMotionSensorFlags(rawValue: 0x00000001) + public static let gyroscope = IntegratedMotionSensorFlags(rawValue: 0x00000002) + public static let indexFlag = IntegratedMotionSensorFlags(rawValue: 0x40000000) + } + + public struct VibrationData { + public var durationMs: Int32 + public var intensityLeft: Float + public var intensityRight: Float + public init(durationMs: Int32, intensityLeft: Float, intensityRight: Float) { + self.durationMs = durationMs + self.intensityLeft = intensityLeft + self.intensityRight = intensityRight + } + } +} +#endif \ No newline at end of file diff --git a/Sources/AndroidInput/InputEvent.swift b/Sources/AndroidInput/InputEvent.swift new file mode 100644 index 00000000..766bc3b5 --- /dev/null +++ b/Sources/AndroidInput/InputEvent.swift @@ -0,0 +1,584 @@ +// +// InputEvent.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if os(Android) +import Android +import AndroidNDK +#endif + +/// Input Event +/// +/// Represents an input event from the Android input system. This is an opaque handle that wraps +/// both key events and motion events (touch, mouse, joystick, etc.). +/// +/// [See Also](https://developer.android.com/ndk/reference/group/input#ainputevent) +public struct InputEvent: ~Copyable { + + // MARK: - Properties + + internal let pointer: OpaquePointer + + // MARK: - Initialization + + internal init(_ pointer: OpaquePointer) { + self.pointer = pointer + } + + // MARK: - Event Properties + + /// Get the input event type. + public var type: EventType { + EventType(rawValue: AInputEvent_getType(pointer)) + } + + /// Get the id for the device that an input event came from. + public var deviceId: Int32 { + AInputEvent_getDeviceId(pointer) + } + + /// Get the input event source. + public var source: EventSource { + EventSource(rawValue: AInputEvent_getSource(pointer)) + } +} + +// MARK: - Event Type + +public struct EventType: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + /// Indicates that the input event is a key event. + public static let key = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_KEY)) + + /// Indicates that the input event is a motion event. + public static let motion = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_MOTION)) + + /// Indicates that the input event is a focus event. + /// + /// Available since API level 28. + public static let focus = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_FOCUS)) + + /// Indicates that the input event is a capture event. + /// + /// Available since API level 28. + public static let capture = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_CAPTURE)) + + /// Indicates that the input event is a drag event. + /// + /// Available since API level 31. + public static let drag = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_DRAG)) + + /// Indicates that the input event is a touch mode event. + /// + /// Available since API level 31. + public static let touchMode = EventType(rawValue: Int32(AINPUT_EVENT_TYPE_TOUCH_MODE)) +} + +// MARK: - Event Source + +public struct EventSource: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + /// Unknown input source. + public static let unknown = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_UNKNOWN)) + + /// Keyboard input source. + public static let keyboard = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_KEYBOARD)) + + /// D-pad input source. + public static let dpad = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_DPAD)) + + /// Gamepad input source. + public static let gamepad = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_GAMEPAD)) + + /// Touchscreen input source. + public static let touchscreen = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_TOUCHSCREEN)) + + /// Mouse input source. + public static let mouse = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_MOUSE)) + + /// Stylus input source. + public static let stylus = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_STYLUS)) + + /// Bluetooth stylus input source. + public static let bluetoothStylus = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_BLUETOOTH_STYLUS)) + + /// Trackball input source. + public static let trackball = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_TRACKBALL)) + + /// Mouse relative input source. + public static let mouseRelative = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_MOUSE_RELATIVE)) + + /// Touchpad input source. + public static let touchpad = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_TOUCHPAD)) + + /// Touch navigation input source. + public static let touchNavigation = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_TOUCH_NAVIGATION)) + + /// Joystick input source. + public static let joystick = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_JOYSTICK)) + + /// HDMI input source. + public static let hdmi = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_HDMI)) + + /// Sensor input source. + public static let sensor = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_SENSOR)) + + /// Rotary encoder input source. + public static let rotaryEncoder = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_ROTARY_ENCODER)) + + /// Any input source. + public static let any = EventSource(rawValue: Int32(bitPattern: AINPUT_SOURCE_ANY)) +} + +// MARK: - Key Event + +public extension InputEvent { + + /// Get the key event action. + /// + /// Only valid for key events. + var keyAction: KeyAction { + KeyAction(AKeyEvent_getAction(pointer)) + } + + /// Get the key event flags. + /// + /// Only valid for key events. + var keyFlags: Int32 { + AKeyEvent_getFlags(pointer) + } + + /// Get the key code of the key event. + /// + /// Only valid for key events. + var keyCode: KeyCode { + KeyCode(AKeyEvent_getKeyCode(pointer)) + } + + /// Get the hardware key id of this key event. + /// + /// Only valid for key events. + var scanCode: Int32 { + AKeyEvent_getScanCode(pointer) + } + + /// Get the meta key state. + /// + /// Only valid for key events. + var metaState: Int32 { + AKeyEvent_getMetaState(pointer) + } + + /// Get the repeat count of the key event. + /// + /// Only valid for key events. + var repeatCount: Int32 { + AKeyEvent_getRepeatCount(pointer) + } + + /// Get the time of the most recent key down event, in the `java.lang.System.nanoTime()` time base. + /// + /// Only valid for key events. + var downTime: Int64 { + AKeyEvent_getDownTime(pointer) + } + + /// Get the time this event occurred, in the `java.lang.System.nanoTime()` time base. + /// + /// Only valid for key events. + var keyEventTime: Int64 { + AKeyEvent_getEventTime(pointer) + } +} + +// MARK: - Key Action + +public struct KeyAction: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + internal init(_ rawValue: Int32) { + self.rawValue = Int(rawValue) + } + + /// Key down action. + public static let down = KeyAction(rawValue: AKEY_EVENT_ACTION_DOWN) + + /// Key up action. + public static let up = KeyAction(rawValue: AKEY_EVENT_ACTION_UP) + + /// Multiple key action. + public static let multiple = KeyAction(rawValue: AKEY_EVENT_ACTION_MULTIPLE) +} + +// MARK: - Motion Event + +public extension InputEvent { + + /// Get the motion event action. + /// + /// Only valid for motion events. + var motionAction: MotionAction { + MotionAction(AMotionEvent_getAction(pointer)) + } + + /// Get the motion event flags. + /// + /// Only valid for motion events. + var motionFlags: Int32 { + AMotionEvent_getFlags(pointer) + } + + /// Get the combined motion event action code and pointer index. + /// + /// Only valid for motion events. + var actionWithPointerIndex: Int32 { + AMotionEvent_getAction(pointer) + } + + /// Get the meta key state. + /// + /// Only valid for motion events. + var motionMetaState: Int32 { + AMotionEvent_getMetaState(pointer) + } + + /// Get the button state of all buttons that are pressed. + /// + /// Only valid for motion events. + var buttonState: Int32 { + AMotionEvent_getButtonState(pointer) + } + + /// Get the edge flags of the motion event. + /// + /// Only valid for motion events. + var edgeFlags: Int32 { + AMotionEvent_getEdgeFlags(pointer) + } + + /// Get the time when the user originally pressed down to start a stream of position events. + /// + /// Only valid for motion events. + var motionDownTime: Int64 { + AMotionEvent_getDownTime(pointer) + } + + /// Get the time when this specific event was generated. + /// + /// Only valid for motion events. + var motionEventTime: Int64 { + AMotionEvent_getEventTime(pointer) + } + + /// Get the X coordinate offset. + /// + /// Only valid for motion events. + var xOffset: Float { + AMotionEvent_getXOffset(pointer) + } + + /// Get the Y coordinate offset. + /// + /// Only valid for motion events. + var yOffset: Float { + AMotionEvent_getYOffset(pointer) + } + + /// Get the precision of the X coordinates being reported. + /// + /// Only valid for motion events. + var xPrecision: Float { + AMotionEvent_getXPrecision(pointer) + } + + /// Get the precision of the Y coordinates being reported. + /// + /// Only valid for motion events. + var yPrecision: Float { + AMotionEvent_getYPrecision(pointer) + } + + /// Get the number of pointers of data contained in this event. + /// + /// Only valid for motion events. + var pointerCount: Int { + Int(AMotionEvent_getPointerCount(pointer)) + } + + /// Get the pointer identifier associated with a particular pointer data index in this event. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the identifier. + /// - Returns: The pointer identifier. + func getPointerId(at pointerIndex: Int) -> Int32 { + AMotionEvent_getPointerId(pointer, pointerIndex) + } + + /// Get the tool type of a pointer. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the tool type. + /// - Returns: The tool type. + func getToolType(at pointerIndex: Int) -> ToolType { + ToolType(AMotionEvent_getToolType(pointer, pointerIndex)) + } + + /// Get the original raw X coordinate of this event. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the X coordinate. + /// - Returns: The raw X coordinate. + func getRawX(at pointerIndex: Int) -> Float { + AMotionEvent_getRawX(pointer, pointerIndex) + } + + /// Get the original raw Y coordinate of this event. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the Y coordinate. + /// - Returns: The raw Y coordinate. + func getRawY(at pointerIndex: Int) -> Float { + AMotionEvent_getRawY(pointer, pointerIndex) + } + + /// Get the current X coordinate of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the X coordinate. + /// - Returns: The X coordinate. + func getX(at pointerIndex: Int) -> Float { + AMotionEvent_getX(pointer, pointerIndex) + } + + /// Get the current Y coordinate of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the Y coordinate. + /// - Returns: The Y coordinate. + func getY(at pointerIndex: Int) -> Float { + AMotionEvent_getY(pointer, pointerIndex) + } + + /// Get the current pressure of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the pressure. + /// - Returns: The pressure value. + func getPressure(at pointerIndex: Int) -> Float { + AMotionEvent_getPressure(pointer, pointerIndex) + } + + /// Get the current size of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the size. + /// - Returns: The size value. + func getSize(at pointerIndex: Int) -> Float { + AMotionEvent_getSize(pointer, pointerIndex) + } + + /// Get the current touch major value of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the touch major. + /// - Returns: The touch major value. + func getTouchMajor(at pointerIndex: Int) -> Float { + AMotionEvent_getTouchMajor(pointer, pointerIndex) + } + + /// Get the current touch minor value of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the touch minor. + /// - Returns: The touch minor value. + func getTouchMinor(at pointerIndex: Int) -> Float { + AMotionEvent_getTouchMinor(pointer, pointerIndex) + } + + /// Get the current tool major value of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the tool major. + /// - Returns: The tool major value. + func getToolMajor(at pointerIndex: Int) -> Float { + AMotionEvent_getToolMajor(pointer, pointerIndex) + } + + /// Get the current tool minor value of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the tool minor. + /// - Returns: The tool minor value. + func getToolMinor(at pointerIndex: Int) -> Float { + AMotionEvent_getToolMinor(pointer, pointerIndex) + } + + /// Get the current orientation of this event for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameter pointerIndex: The index of the pointer for which to retrieve the orientation. + /// - Returns: The orientation value. + func getOrientation(at pointerIndex: Int) -> Float { + AMotionEvent_getOrientation(pointer, pointerIndex) + } + + /// Get the value of the request axis for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameters: + /// - axis: The axis identifier. + /// - pointerIndex: The index of the pointer for which to retrieve the axis value. + /// - Returns: The axis value. + func getAxisValue(_ axis: Int32, at pointerIndex: Int) -> Float { + AMotionEvent_getAxisValue(pointer, axis, pointerIndex) + } + + /// Get the number of historical points in this event. + /// + /// Only valid for motion events. + var historySize: Int { + Int(AMotionEvent_getHistorySize(pointer)) + } + + /// Get the historical X coordinate for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameters: + /// - pointerIndex: The index of the pointer. + /// - historyIndex: The index of the historical point. + /// - Returns: The historical X coordinate. + func getHistoricalX(at pointerIndex: Int, historyIndex: Int) -> Float { + AMotionEvent_getHistoricalX(pointer, pointerIndex, historyIndex) + } + + /// Get the historical Y coordinate for the given pointer index. + /// + /// Only valid for motion events. + /// + /// - Parameters: + /// - pointerIndex: The index of the pointer. + /// - historyIndex: The index of the historical point. + /// - Returns: The historical Y coordinate. + func getHistoricalY(at pointerIndex: Int, historyIndex: Int) -> Float { + AMotionEvent_getHistoricalY(pointer, pointerIndex, historyIndex) + } +} + +// MARK: - Motion Action + +public struct MotionAction: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + internal init(_ rawValue: Int32) { + self.rawValue = Int(rawValue) + } + + /// Motion action down. + public static let down = MotionAction(rawValue: AMOTION_EVENT_ACTION_DOWN) + + /// Motion action up. + public static let up = MotionAction(rawValue: AMOTION_EVENT_ACTION_UP) + + /// Motion action move. + public static let move = MotionAction(rawValue: AMOTION_EVENT_ACTION_MOVE) + + /// Motion action cancel. + public static let cancel = MotionAction(rawValue: AMOTION_EVENT_ACTION_CANCEL) + + /// Motion action outside. + public static let outside = MotionAction(rawValue: AMOTION_EVENT_ACTION_OUTSIDE) + + /// Motion action pointer down. + public static let pointerDown = MotionAction(rawValue: AMOTION_EVENT_ACTION_POINTER_DOWN) + + /// Motion action pointer up. + public static let pointerUp = MotionAction(rawValue: AMOTION_EVENT_ACTION_POINTER_UP) + + /// Motion action hover move. + public static let hoverMove = MotionAction(rawValue: AMOTION_EVENT_ACTION_HOVER_MOVE) + + /// Motion action scroll. + public static let scroll = MotionAction(rawValue: AMOTION_EVENT_ACTION_SCROLL) + + /// Motion action hover enter. + public static let hoverEnter = MotionAction(rawValue: AMOTION_EVENT_ACTION_HOVER_ENTER) + + /// Motion action hover exit. + public static let hoverExit = MotionAction(rawValue: AMOTION_EVENT_ACTION_HOVER_EXIT) + + /// Motion action button press. + public static let buttonPress = MotionAction(rawValue: AMOTION_EVENT_ACTION_BUTTON_PRESS) + + /// Motion action button release. + public static let buttonRelease = MotionAction(rawValue: AMOTION_EVENT_ACTION_BUTTON_RELEASE) +} + +// MARK: - Tool Type + +public struct ToolType: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + internal init(_ rawValue: Int32) { + self.rawValue = Int(rawValue) + } + + /// Unknown tool type. + public static let unknown = ToolType(rawValue: AMOTION_EVENT_TOOL_TYPE_UNKNOWN) + + /// Finger tool type. + public static let finger = ToolType(rawValue: AMOTION_EVENT_TOOL_TYPE_FINGER) + + /// Stylus tool type. + public static let stylus = ToolType(rawValue: AMOTION_EVENT_TOOL_TYPE_STYLUS) + + /// Mouse tool type. + public static let mouse = ToolType(rawValue: AMOTION_EVENT_TOOL_TYPE_MOUSE) + + /// Eraser tool type. + public static let eraser = ToolType(rawValue: AMOTION_EVENT_TOOL_TYPE_ERASER) +} diff --git a/Sources/AndroidInput/InputQueue.swift b/Sources/AndroidInput/InputQueue.swift new file mode 100644 index 00000000..add60bc1 --- /dev/null +++ b/Sources/AndroidInput/InputQueue.swift @@ -0,0 +1,103 @@ +// +// InputQueue.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if os(Android) +import Android +import AndroidNDK +#endif +import AndroidLooper + +/// Input Queue +/// +/// Provides a mechanism for your native activity to retrieve and process input events from the Android input system. +/// AInputQueue is an opaque handle for the native input queue associated with a window. +/// +/// [See Also](https://developer.android.com/ndk/reference/group/input#ainputqueue) +public struct InputQueue: ~Copyable { + + // MARK: - Properties + + internal let pointer: OpaquePointer + + // MARK: - Initialization + + internal init(_ pointer: OpaquePointer) { + self.pointer = pointer + } + + // MARK: - Methods + + /// Add this input queue to a looper for processing. + /// + /// - Parameters: + /// - looper: The looper to use when invoking callbacks. + /// - identifier: The identifier to use when performing callbacks. + /// - callback: The function to call when an event is available. + /// - data: A private data pointer to supply to the callback. + public func attachLooper( + _ looper: borrowing Looper, + identifier: Int32, + callback: ALooper_callbackFunc?, + data: UnsafeMutableRawPointer? + ) { + looper.withUnsafePointer { looperPointer in + AInputQueue_attachLooper(self.pointer, looperPointer, identifier, callback, data) + } + } + + /// Remove the input queue from the looper it is currently attached to. + public func detachLooper() { + AInputQueue_detachLooper(pointer) + } + + /// Returns true if there are one or more events available in the input queue. + /// + /// Returns 1 if the queue has events; 0 if it does not have events; and a negative value if there is an error. + public func hasEvents() -> Int32 { + AInputQueue_hasEvents(pointer) + } + + /// Returns the next available event from the queue. + /// + /// Returns a negative value if no events are available or an error has occurred, otherwise returns a non-negative value indicating the number of events available. + /// + /// - Parameter outEvent: Will be set to the next input event. + /// - Returns: The result code. + @discardableResult + public func getEvent(_ outEvent: inout InputEvent?) -> Int32 { + var eventPointer: OpaquePointer? + let result = AInputQueue_getEvent(pointer, &eventPointer) + if result >= 0, let eventPointer { + outEvent = InputEvent(eventPointer) + } else { + outEvent = nil + } + return result + } + + /// Sends the key for standard pre-dispatching. + /// + /// Returns 0 if pre-dispatch was completed, 1 if the event should be pre-dispatched, or a negative value on error. + /// + /// - Parameter event: The input event to pre-dispatch. + /// - Returns: The result code. + @discardableResult + public func preDispatchEvent(_ event: borrowing InputEvent) -> Int32 { + AInputQueue_preDispatchEvent(pointer, event.pointer) + } + + /// Report that dispatching has finished with the given event. + /// + /// This must be called after receiving an event with `getEvent()`. + /// + /// - Parameters: + /// - event: The event that was handled. + /// - handled: Whether the event was handled (1) or not (0). + public func finishEvent(_ event: borrowing InputEvent, handled: Bool) { + AInputQueue_finishEvent(pointer, event.pointer, handled ? 1 : 0) + } +} diff --git a/Sources/AndroidInput/Keycodes.swift b/Sources/AndroidInput/Keycodes.swift new file mode 100644 index 00000000..a1ef9ba8 --- /dev/null +++ b/Sources/AndroidInput/Keycodes.swift @@ -0,0 +1,1035 @@ +// +// Keycodes.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if os(Android) +import Android +import AndroidNDK +#endif + +/// Key code identifying a physical key on a keyboard or virtual key from an input device. +/// +/// Key code constants from Android's `android/keycodes.h`. +/// +/// [See Also](https://developer.android.com/ndk/reference/group/input#anonymous-enum-3) +public struct KeyCode: RawRepresentable, Equatable, Hashable, Sendable { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + internal init(_ rawValue: Int32) { + self.rawValue = Int(rawValue) + } +} + +public extension KeyCode { + + // MARK: Basic + + /// Unknown key code. + static var unknown: KeyCode { KeyCode(rawValue: AKEYCODE_UNKNOWN) } + + /// Soft Left key. + static var softLeft: KeyCode { KeyCode(rawValue: AKEYCODE_SOFT_LEFT) } + + /// Soft Right key. + static var softRight: KeyCode { KeyCode(rawValue: AKEYCODE_SOFT_RIGHT) } + + /// Home key. + static var home: KeyCode { KeyCode(rawValue: AKEYCODE_HOME) } + + /// Back key. + static var back: KeyCode { KeyCode(rawValue: AKEYCODE_BACK) } + + /// Call key. + static var call: KeyCode { KeyCode(rawValue: AKEYCODE_CALL) } + + /// End Call key. + static var endCall: KeyCode { KeyCode(rawValue: AKEYCODE_ENDCALL) } + + // MARK: Number Row + + /// '0' key. + static var digit0: KeyCode { KeyCode(rawValue: AKEYCODE_0) } + + /// '1' key. + static var digit1: KeyCode { KeyCode(rawValue: AKEYCODE_1) } + + /// '2' key. + static var digit2: KeyCode { KeyCode(rawValue: AKEYCODE_2) } + + /// '3' key. + static var digit3: KeyCode { KeyCode(rawValue: AKEYCODE_3) } + + /// '4' key. + static var digit4: KeyCode { KeyCode(rawValue: AKEYCODE_4) } + + /// '5' key. + static var digit5: KeyCode { KeyCode(rawValue: AKEYCODE_5) } + + /// '6' key. + static var digit6: KeyCode { KeyCode(rawValue: AKEYCODE_6) } + + /// '7' key. + static var digit7: KeyCode { KeyCode(rawValue: AKEYCODE_7) } + + /// '8' key. + static var digit8: KeyCode { KeyCode(rawValue: AKEYCODE_8) } + + /// '9' key. + static var digit9: KeyCode { KeyCode(rawValue: AKEYCODE_9) } + + /// '*' key. + static var star: KeyCode { KeyCode(rawValue: AKEYCODE_STAR) } + + /// '#' key. + static var pound: KeyCode { KeyCode(rawValue: AKEYCODE_POUND) } + + // MARK: D-Pad + + /// Directional Pad Up key. + static var dpadUp: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_UP) } + + /// Directional Pad Down key. + static var dpadDown: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_DOWN) } + + /// Directional Pad Left key. + static var dpadLeft: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_LEFT) } + + /// Directional Pad Right key. + static var dpadRight: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_RIGHT) } + + /// Directional Pad Center key. + static var dpadCenter: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_CENTER) } + + /// Directional Pad Up-Left key. + static var dpadUpLeft: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_UP_LEFT) } + + /// Directional Pad Down-Left key. + static var dpadDownLeft: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_DOWN_LEFT) } + + /// Directional Pad Up-Right key. + static var dpadUpRight: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_UP_RIGHT) } + + /// Directional Pad Down-Right key. + static var dpadDownRight: KeyCode { KeyCode(rawValue: AKEYCODE_DPAD_DOWN_RIGHT) } + + // MARK: Volume / Power + + /// Volume Up key. + static var volumeUp: KeyCode { KeyCode(rawValue: AKEYCODE_VOLUME_UP) } + + /// Volume Down key. + static var volumeDown: KeyCode { KeyCode(rawValue: AKEYCODE_VOLUME_DOWN) } + + /// Volume Mute key. + static var volumeMute: KeyCode { KeyCode(rawValue: AKEYCODE_VOLUME_MUTE) } + + /// Power key. + static var power: KeyCode { KeyCode(rawValue: AKEYCODE_POWER) } + + /// Camera key. + static var camera: KeyCode { KeyCode(rawValue: AKEYCODE_CAMERA) } + + /// Clear key. + static var clear: KeyCode { KeyCode(rawValue: AKEYCODE_CLEAR) } + + // MARK: Letters + + /// 'A' key. + static var a: KeyCode { KeyCode(rawValue: AKEYCODE_A) } + + /// 'B' key. + static var b: KeyCode { KeyCode(rawValue: AKEYCODE_B) } + + /// 'C' key. + static var c: KeyCode { KeyCode(rawValue: AKEYCODE_C) } + + /// 'D' key. + static var d: KeyCode { KeyCode(rawValue: AKEYCODE_D) } + + /// 'E' key. + static var e: KeyCode { KeyCode(rawValue: AKEYCODE_E) } + + /// 'F' key. + static var f: KeyCode { KeyCode(rawValue: AKEYCODE_F) } + + /// 'G' key. + static var g: KeyCode { KeyCode(rawValue: AKEYCODE_G) } + + /// 'H' key. + static var h: KeyCode { KeyCode(rawValue: AKEYCODE_H) } + + /// 'I' key. + static var i: KeyCode { KeyCode(rawValue: AKEYCODE_I) } + + /// 'J' key. + static var j: KeyCode { KeyCode(rawValue: AKEYCODE_J) } + + /// 'K' key. + static var k: KeyCode { KeyCode(rawValue: AKEYCODE_K) } + + /// 'L' key. + static var l: KeyCode { KeyCode(rawValue: AKEYCODE_L) } + + /// 'M' key. + static var m: KeyCode { KeyCode(rawValue: AKEYCODE_M) } + + /// 'N' key. + static var n: KeyCode { KeyCode(rawValue: AKEYCODE_N) } + + /// 'O' key. + static var o: KeyCode { KeyCode(rawValue: AKEYCODE_O) } + + /// 'P' key. + static var p: KeyCode { KeyCode(rawValue: AKEYCODE_P) } + + /// 'Q' key. + static var q: KeyCode { KeyCode(rawValue: AKEYCODE_Q) } + + /// 'R' key. + static var r: KeyCode { KeyCode(rawValue: AKEYCODE_R) } + + /// 'S' key. + static var s: KeyCode { KeyCode(rawValue: AKEYCODE_S) } + + /// 'T' key. + static var t: KeyCode { KeyCode(rawValue: AKEYCODE_T) } + + /// 'U' key. + static var u: KeyCode { KeyCode(rawValue: AKEYCODE_U) } + + /// 'V' key. + static var v: KeyCode { KeyCode(rawValue: AKEYCODE_V) } + + /// 'W' key. + static var w: KeyCode { KeyCode(rawValue: AKEYCODE_W) } + + /// 'X' key. + static var x: KeyCode { KeyCode(rawValue: AKEYCODE_X) } + + /// 'Y' key. + static var y: KeyCode { KeyCode(rawValue: AKEYCODE_Y) } + + /// 'Z' key. + static var z: KeyCode { KeyCode(rawValue: AKEYCODE_Z) } + + // MARK: Punctuation / Symbols + + /// ',' key. + static var comma: KeyCode { KeyCode(rawValue: AKEYCODE_COMMA) } + + /// '.' key. + static var period: KeyCode { KeyCode(rawValue: AKEYCODE_PERIOD) } + + /// Left Alt modifier key. + static var altLeft: KeyCode { KeyCode(rawValue: AKEYCODE_ALT_LEFT) } + + /// Right Alt modifier key. + static var altRight: KeyCode { KeyCode(rawValue: AKEYCODE_ALT_RIGHT) } + + /// Left Shift modifier key. + static var shiftLeft: KeyCode { KeyCode(rawValue: AKEYCODE_SHIFT_LEFT) } + + /// Right Shift modifier key. + static var shiftRight: KeyCode { KeyCode(rawValue: AKEYCODE_SHIFT_RIGHT) } + + /// Tab key. + static var tab: KeyCode { KeyCode(rawValue: AKEYCODE_TAB) } + + /// Space key. + static var space: KeyCode { KeyCode(rawValue: AKEYCODE_SPACE) } + + /// Symbol modifier key. + static var sym: KeyCode { KeyCode(rawValue: AKEYCODE_SYM) } + + /// Explorer special function key. + static var explorer: KeyCode { KeyCode(rawValue: AKEYCODE_EXPLORER) } + + /// Envelope special function key. + static var envelope: KeyCode { KeyCode(rawValue: AKEYCODE_ENVELOPE) } + + /// Enter key. + static var enter: KeyCode { KeyCode(rawValue: AKEYCODE_ENTER) } + + /// Backspace key (labeled "DEL" on Android). + static var delete: KeyCode { KeyCode(rawValue: AKEYCODE_DEL) } + + /// '`' (backtick / grave accent) key. + static var grave: KeyCode { KeyCode(rawValue: AKEYCODE_GRAVE) } + + /// '-' key. + static var minus: KeyCode { KeyCode(rawValue: AKEYCODE_MINUS) } + + /// '=' key. + static var equals: KeyCode { KeyCode(rawValue: AKEYCODE_EQUALS) } + + /// '[' key. + static var leftBracket: KeyCode { KeyCode(rawValue: AKEYCODE_LEFT_BRACKET) } + + /// ']' key. + static var rightBracket: KeyCode { KeyCode(rawValue: AKEYCODE_RIGHT_BRACKET) } + + /// '\' key. + static var backslash: KeyCode { KeyCode(rawValue: AKEYCODE_BACKSLASH) } + + /// ';' key. + static var semicolon: KeyCode { KeyCode(rawValue: AKEYCODE_SEMICOLON) } + + /// '\'' (apostrophe) key. + static var apostrophe: KeyCode { KeyCode(rawValue: AKEYCODE_APOSTROPHE) } + + /// '/' key. + static var slash: KeyCode { KeyCode(rawValue: AKEYCODE_SLASH) } + + /// '@' key. + static var at: KeyCode { KeyCode(rawValue: AKEYCODE_AT) } + + /// Number modifier key. + static var num: KeyCode { KeyCode(rawValue: AKEYCODE_NUM) } + + /// Headset Hook key. + static var headsetHook: KeyCode { KeyCode(rawValue: AKEYCODE_HEADSETHOOK) } + + /// Camera Focus key. + static var focus: KeyCode { KeyCode(rawValue: AKEYCODE_FOCUS) } + + /// '+' key. + static var plus: KeyCode { KeyCode(rawValue: AKEYCODE_PLUS) } + + /// Menu key. + static var menu: KeyCode { KeyCode(rawValue: AKEYCODE_MENU) } + + /// Notification key. + static var notification: KeyCode { KeyCode(rawValue: AKEYCODE_NOTIFICATION) } + + /// Search key. + static var search: KeyCode { KeyCode(rawValue: AKEYCODE_SEARCH) } + + // MARK: Media + + /// Play/Pause media key. + static var mediaPlayPause: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_PLAY_PAUSE) } + + /// Stop media key. + static var mediaStop: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_STOP) } + + /// Play media key. + static var mediaPlay: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_PLAY) } + + /// Pause media key. + static var mediaPause: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_PAUSE) } + + /// Next media key. + static var mediaNext: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_NEXT) } + + /// Previous media key. + static var mediaPrevious: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_PREVIOUS) } + + /// Rewind media key. + static var mediaRewind: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_REWIND) } + + /// Fast Forward media key. + static var mediaFastForward: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_FAST_FORWARD) } + + /// Close media key. + static var mediaClose: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_CLOSE) } + + /// Eject media key. + static var mediaEject: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_EJECT) } + + /// Record media key. + static var mediaRecord: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_RECORD) } + + /// Audio Track media key. + static var mediaAudioTrack: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_AUDIO_TRACK) } + + /// Media Top Menu key. + static var mediaTopMenu: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_TOP_MENU) } + + /// Skip Forward media key. + static var mediaSkipForward: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_SKIP_FORWARD) } + + /// Skip Backward media key. + static var mediaSkipBackward: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_SKIP_BACKWARD) } + + /// Step Forward media key. + static var mediaStepForward: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_STEP_FORWARD) } + + /// Step Backward media key. + static var mediaStepBackward: KeyCode { KeyCode(rawValue: AKEYCODE_MEDIA_STEP_BACKWARD) } + + /// Mute key. + static var mute: KeyCode { KeyCode(rawValue: AKEYCODE_MUTE) } + + // MARK: Navigation + + /// Page Up key. + static var pageUp: KeyCode { KeyCode(rawValue: AKEYCODE_PAGE_UP) } + + /// Page Down key. + static var pageDown: KeyCode { KeyCode(rawValue: AKEYCODE_PAGE_DOWN) } + + /// Picture Symbols modifier key. + static var pictSymbols: KeyCode { KeyCode(rawValue: AKEYCODE_PICTSYMBOLS) } + + /// Switch Charset modifier key. + static var switchCharset: KeyCode { KeyCode(rawValue: AKEYCODE_SWITCH_CHARSET) } + + // MARK: Extended Keyboard + + /// Escape key. + static var escape: KeyCode { KeyCode(rawValue: AKEYCODE_ESCAPE) } + + /// Forward Delete key. + static var forwardDelete: KeyCode { KeyCode(rawValue: AKEYCODE_FORWARD_DEL) } + + /// Left Control modifier key. + static var controlLeft: KeyCode { KeyCode(rawValue: AKEYCODE_CTRL_LEFT) } + + /// Right Control modifier key. + static var controlRight: KeyCode { KeyCode(rawValue: AKEYCODE_CTRL_RIGHT) } + + /// Caps Lock key. + static var capsLock: KeyCode { KeyCode(rawValue: AKEYCODE_CAPS_LOCK) } + + /// Scroll Lock key. + static var scrollLock: KeyCode { KeyCode(rawValue: AKEYCODE_SCROLL_LOCK) } + + /// Left Meta modifier key. + static var metaLeft: KeyCode { KeyCode(rawValue: AKEYCODE_META_LEFT) } + + /// Right Meta modifier key. + static var metaRight: KeyCode { KeyCode(rawValue: AKEYCODE_META_RIGHT) } + + /// Function modifier key. + static var function: KeyCode { KeyCode(rawValue: AKEYCODE_FUNCTION) } + + /// System Request / Print Screen key. + static var sysRq: KeyCode { KeyCode(rawValue: AKEYCODE_SYSRQ) } + + /// Break / Pause key. + static var `break`: KeyCode { KeyCode(rawValue: AKEYCODE_BREAK) } + + /// Move to Beginning of Line key. + static var moveHome: KeyCode { KeyCode(rawValue: AKEYCODE_MOVE_HOME) } + + /// Move to End of Line key. + static var moveEnd: KeyCode { KeyCode(rawValue: AKEYCODE_MOVE_END) } + + /// Insert key. + static var insert: KeyCode { KeyCode(rawValue: AKEYCODE_INSERT) } + + /// Forward key. + static var forward: KeyCode { KeyCode(rawValue: AKEYCODE_FORWARD) } + + // MARK: Function Keys + + /// F1 key. + static var f1: KeyCode { KeyCode(rawValue: AKEYCODE_F1) } + + /// F2 key. + static var f2: KeyCode { KeyCode(rawValue: AKEYCODE_F2) } + + /// F3 key. + static var f3: KeyCode { KeyCode(rawValue: AKEYCODE_F3) } + + /// F4 key. + static var f4: KeyCode { KeyCode(rawValue: AKEYCODE_F4) } + + /// F5 key. + static var f5: KeyCode { KeyCode(rawValue: AKEYCODE_F5) } + + /// F6 key. + static var f6: KeyCode { KeyCode(rawValue: AKEYCODE_F6) } + + /// F7 key. + static var f7: KeyCode { KeyCode(rawValue: AKEYCODE_F7) } + + /// F8 key. + static var f8: KeyCode { KeyCode(rawValue: AKEYCODE_F8) } + + /// F9 key. + static var f9: KeyCode { KeyCode(rawValue: AKEYCODE_F9) } + + /// F10 key. + static var f10: KeyCode { KeyCode(rawValue: AKEYCODE_F10) } + + /// F11 key. + static var f11: KeyCode { KeyCode(rawValue: AKEYCODE_F11) } + + /// F12 key. + static var f12: KeyCode { KeyCode(rawValue: AKEYCODE_F12) } + + // MARK: Numpad + + /// Num Lock key. + static var numLock: KeyCode { KeyCode(rawValue: AKEYCODE_NUM_LOCK) } + + /// Numpad '0' key. + static var numpad0: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_0) } + + /// Numpad '1' key. + static var numpad1: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_1) } + + /// Numpad '2' key. + static var numpad2: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_2) } + + /// Numpad '3' key. + static var numpad3: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_3) } + + /// Numpad '4' key. + static var numpad4: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_4) } + + /// Numpad '5' key. + static var numpad5: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_5) } + + /// Numpad '6' key. + static var numpad6: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_6) } + + /// Numpad '7' key. + static var numpad7: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_7) } + + /// Numpad '8' key. + static var numpad8: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_8) } + + /// Numpad '9' key. + static var numpad9: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_9) } + + /// Numpad '/' key. + static var numpadDivide: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_DIVIDE) } + + /// Numpad '*' key. + static var numpadMultiply: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_MULTIPLY) } + + /// Numpad '-' key. + static var numpadSubtract: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_SUBTRACT) } + + /// Numpad '+' key. + static var numpadAdd: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_ADD) } + + /// Numpad '.' key. + static var numpadDot: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_DOT) } + + /// Numpad ',' key. + static var numpadComma: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_COMMA) } + + /// Numpad Enter key. + static var numpadEnter: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_ENTER) } + + /// Numpad '=' key. + static var numpadEquals: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_EQUALS) } + + /// Numpad '(' key. + static var numpadLeftParen: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_LEFT_PAREN) } + + /// Numpad ')' key. + static var numpadRightParen: KeyCode { KeyCode(rawValue: AKEYCODE_NUMPAD_RIGHT_PAREN) } + + // MARK: Gamepad (Named) + + /// A button on a gamepad. + static var buttonA: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_A) } + + /// B button on a gamepad. + static var buttonB: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_B) } + + /// C button on a gamepad. + static var buttonC: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_C) } + + /// X button on a gamepad. + static var buttonX: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_X) } + + /// Y button on a gamepad. + static var buttonY: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_Y) } + + /// Z button on a gamepad. + static var buttonZ: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_Z) } + + /// L1 button on a gamepad. + static var buttonL1: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_L1) } + + /// R1 button on a gamepad. + static var buttonR1: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_R1) } + + /// L2 button on a gamepad. + static var buttonL2: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_L2) } + + /// R2 button on a gamepad. + static var buttonR2: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_R2) } + + /// Left thumbstick button on a gamepad. + static var buttonThumbL: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_THUMBL) } + + /// Right thumbstick button on a gamepad. + static var buttonThumbR: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_THUMBR) } + + /// Start button on a gamepad. + static var buttonStart: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_START) } + + /// Select button on a gamepad. + static var buttonSelect: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_SELECT) } + + /// Mode button on a gamepad. + static var buttonMode: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_MODE) } + + // MARK: Gamepad (Generic 1-16) + + /// Generic gamepad button 1. + static var button1: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_1) } + + /// Generic gamepad button 2. + static var button2: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_2) } + + /// Generic gamepad button 3. + static var button3: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_3) } + + /// Generic gamepad button 4. + static var button4: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_4) } + + /// Generic gamepad button 5. + static var button5: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_5) } + + /// Generic gamepad button 6. + static var button6: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_6) } + + /// Generic gamepad button 7. + static var button7: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_7) } + + /// Generic gamepad button 8. + static var button8: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_8) } + + /// Generic gamepad button 9. + static var button9: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_9) } + + /// Generic gamepad button 10. + static var button10: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_10) } + + /// Generic gamepad button 11. + static var button11: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_11) } + + /// Generic gamepad button 12. + static var button12: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_12) } + + /// Generic gamepad button 13. + static var button13: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_13) } + + /// Generic gamepad button 14. + static var button14: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_14) } + + /// Generic gamepad button 15. + static var button15: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_15) } + + /// Generic gamepad button 16. + static var button16: KeyCode { KeyCode(rawValue: AKEYCODE_BUTTON_16) } + + // MARK: Language / Input Method + + /// Language Switch key. + static var languageSwitch: KeyCode { KeyCode(rawValue: AKEYCODE_LANGUAGE_SWITCH) } + + /// Manner Mode key. + static var mannerMode: KeyCode { KeyCode(rawValue: AKEYCODE_MANNER_MODE) } + + /// 3D Mode key. + static var mode3D: KeyCode { KeyCode(rawValue: AKEYCODE_3D_MODE) } + + /// Contacts special function key. + static var contacts: KeyCode { KeyCode(rawValue: AKEYCODE_CONTACTS) } + + /// Calendar special function key. + static var calendar: KeyCode { KeyCode(rawValue: AKEYCODE_CALENDAR) } + + /// Music special function key. + static var music: KeyCode { KeyCode(rawValue: AKEYCODE_MUSIC) } + + /// Calculator special function key. + static var calculator: KeyCode { KeyCode(rawValue: AKEYCODE_CALCULATOR) } + + // MARK: Japanese Keyboard + + /// Zenkaku/Hankaku key (full-width / half-width toggle). + static var zenkakuHankaku: KeyCode { KeyCode(rawValue: AKEYCODE_ZENKAKU_HANKAKU) } + + /// Eisu key (alphanumeric toggle). + static var eisu: KeyCode { KeyCode(rawValue: AKEYCODE_EISU) } + + /// Muhenkan key (non-conversion). + static var muhenkan: KeyCode { KeyCode(rawValue: AKEYCODE_MUHENKAN) } + + /// Henkan key (conversion). + static var henkan: KeyCode { KeyCode(rawValue: AKEYCODE_HENKAN) } + + /// Katakana / Hiragana key. + static var katakanaHiragana: KeyCode { KeyCode(rawValue: AKEYCODE_KATAKANA_HIRAGANA) } + + /// Yen key. + static var yen: KeyCode { KeyCode(rawValue: AKEYCODE_YEN) } + + /// Ro key. + static var ro: KeyCode { KeyCode(rawValue: AKEYCODE_RO) } + + /// Kana modifier key. + static var kana: KeyCode { KeyCode(rawValue: AKEYCODE_KANA) } + + // MARK: System / Accessibility + + /// Assist key. + static var assist: KeyCode { KeyCode(rawValue: AKEYCODE_ASSIST) } + + /// Brightness Down key. + static var brightnessDown: KeyCode { KeyCode(rawValue: AKEYCODE_BRIGHTNESS_DOWN) } + + /// Brightness Up key. + static var brightnessUp: KeyCode { KeyCode(rawValue: AKEYCODE_BRIGHTNESS_UP) } + + /// Sleep key. + static var sleep: KeyCode { KeyCode(rawValue: AKEYCODE_SLEEP) } + + /// Wakeup key. + static var wakeup: KeyCode { KeyCode(rawValue: AKEYCODE_WAKEUP) } + + /// Pairing key. + static var pairing: KeyCode { KeyCode(rawValue: AKEYCODE_PAIRING) } + + /// App Switch key. + static var appSwitch: KeyCode { KeyCode(rawValue: AKEYCODE_APP_SWITCH) } + + /// Voice Assist key. + static var voiceAssist: KeyCode { KeyCode(rawValue: AKEYCODE_VOICE_ASSIST) } + + /// Help key. + static var help: KeyCode { KeyCode(rawValue: AKEYCODE_HELP) } + + /// Navigate Previous key. + static var navigatePrevious: KeyCode { KeyCode(rawValue: AKEYCODE_NAVIGATE_PREVIOUS) } + + /// Navigate Next key. + static var navigateNext: KeyCode { KeyCode(rawValue: AKEYCODE_NAVIGATE_NEXT) } + + /// Navigate In key. + static var navigateIn: KeyCode { KeyCode(rawValue: AKEYCODE_NAVIGATE_IN) } + + /// Navigate Out key. + static var navigateOut: KeyCode { KeyCode(rawValue: AKEYCODE_NAVIGATE_OUT) } + + /// Soft Sleep key. + static var softSleep: KeyCode { KeyCode(rawValue: AKEYCODE_SOFT_SLEEP) } + + /// Cut key. + static var cut: KeyCode { KeyCode(rawValue: AKEYCODE_CUT) } + + /// Copy key. + static var copy: KeyCode { KeyCode(rawValue: AKEYCODE_COPY) } + + /// Paste key. + static var paste: KeyCode { KeyCode(rawValue: AKEYCODE_PASTE) } + + /// All Apps key. + static var allApps: KeyCode { KeyCode(rawValue: AKEYCODE_ALL_APPS) } + + /// Refresh key. + static var refresh: KeyCode { KeyCode(rawValue: AKEYCODE_REFRESH) } + + /// Thumbs Up key. + static var thumbsUp: KeyCode { KeyCode(rawValue: AKEYCODE_THUMBS_UP) } + + /// Thumbs Down key. + static var thumbsDown: KeyCode { KeyCode(rawValue: AKEYCODE_THUMBS_DOWN) } + + /// Profile Switch key. + static var profileSwitch: KeyCode { KeyCode(rawValue: AKEYCODE_PROFILE_SWITCH) } + + /// Recent Apps key. + static var recentApps: KeyCode { KeyCode(rawValue: AKEYCODE_RECENT_APPS) } + + /// Screenshot key. + static var screenshot: KeyCode { KeyCode(rawValue: AKEYCODE_SCREENSHOT) } + + /// Emoji Picker key. + static var emojiPicker: KeyCode { KeyCode(rawValue: AKEYCODE_EMOJI_PICKER) } + + // MARK: System Navigation Gestures + + /// System Navigation Up key. + static var systemNavigationUp: KeyCode { KeyCode(rawValue: AKEYCODE_SYSTEM_NAVIGATION_UP) } + + /// System Navigation Down key. + static var systemNavigationDown: KeyCode { KeyCode(rawValue: AKEYCODE_SYSTEM_NAVIGATION_DOWN) } + + /// System Navigation Left key. + static var systemNavigationLeft: KeyCode { KeyCode(rawValue: AKEYCODE_SYSTEM_NAVIGATION_LEFT) } + + /// System Navigation Right key. + static var systemNavigationRight: KeyCode { KeyCode(rawValue: AKEYCODE_SYSTEM_NAVIGATION_RIGHT) } + + // MARK: Wearable Stem Buttons + + /// Primary stem button on a wearable device. + static var stemPrimary: KeyCode { KeyCode(rawValue: AKEYCODE_STEM_PRIMARY) } + + /// Stem button 1 on a wearable device. + static var stem1: KeyCode { KeyCode(rawValue: AKEYCODE_STEM_1) } + + /// Stem button 2 on a wearable device. + static var stem2: KeyCode { KeyCode(rawValue: AKEYCODE_STEM_2) } + + /// Stem button 3 on a wearable device. + static var stem3: KeyCode { KeyCode(rawValue: AKEYCODE_STEM_3) } + + // MARK: TV + + /// Info key (TV remotes). + static var info: KeyCode { KeyCode(rawValue: AKEYCODE_INFO) } + + /// Channel Up key. + static var channelUp: KeyCode { KeyCode(rawValue: AKEYCODE_CHANNEL_UP) } + + /// Channel Down key. + static var channelDown: KeyCode { KeyCode(rawValue: AKEYCODE_CHANNEL_DOWN) } + + /// Zoom In key. + static var zoomIn: KeyCode { KeyCode(rawValue: AKEYCODE_ZOOM_IN) } + + /// Zoom Out key. + static var zoomOut: KeyCode { KeyCode(rawValue: AKEYCODE_ZOOM_OUT) } + + /// TV key. + static var tv: KeyCode { KeyCode(rawValue: AKEYCODE_TV) } + + /// Window key (picture-in-picture). + static var window: KeyCode { KeyCode(rawValue: AKEYCODE_WINDOW) } + + /// Guide key. + static var guide: KeyCode { KeyCode(rawValue: AKEYCODE_GUIDE) } + + /// DVR key. + static var dvr: KeyCode { KeyCode(rawValue: AKEYCODE_DVR) } + + /// Bookmark key. + static var bookmark: KeyCode { KeyCode(rawValue: AKEYCODE_BOOKMARK) } + + /// Toggle captions key. + static var captions: KeyCode { KeyCode(rawValue: AKEYCODE_CAPTIONS) } + + /// Settings key. + static var settings: KeyCode { KeyCode(rawValue: AKEYCODE_SETTINGS) } + + /// TV Power key. + static var tvPower: KeyCode { KeyCode(rawValue: AKEYCODE_TV_POWER) } + + /// TV Input key. + static var tvInput: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT) } + + /// Set-top-box Power key. + static var stbPower: KeyCode { KeyCode(rawValue: AKEYCODE_STB_POWER) } + + /// Set-top-box Input key. + static var stbInput: KeyCode { KeyCode(rawValue: AKEYCODE_STB_INPUT) } + + /// A/V Receiver Power key. + static var avrPower: KeyCode { KeyCode(rawValue: AKEYCODE_AVR_POWER) } + + /// A/V Receiver Input key. + static var avrInput: KeyCode { KeyCode(rawValue: AKEYCODE_AVR_INPUT) } + + /// Red programmable key. + static var progRed: KeyCode { KeyCode(rawValue: AKEYCODE_PROG_RED) } + + /// Green programmable key. + static var progGreen: KeyCode { KeyCode(rawValue: AKEYCODE_PROG_GREEN) } + + /// Yellow programmable key. + static var progYellow: KeyCode { KeyCode(rawValue: AKEYCODE_PROG_YELLOW) } + + /// Blue programmable key. + static var progBlue: KeyCode { KeyCode(rawValue: AKEYCODE_PROG_BLUE) } + + /// Last Channel key. + static var lastChannel: KeyCode { KeyCode(rawValue: AKEYCODE_LAST_CHANNEL) } + + /// TV Data Service key. + static var tvDataService: KeyCode { KeyCode(rawValue: AKEYCODE_TV_DATA_SERVICE) } + + /// TV Radio Service key. + static var tvRadioService: KeyCode { KeyCode(rawValue: AKEYCODE_TV_RADIO_SERVICE) } + + /// Teletext key. + static var tvTeletext: KeyCode { KeyCode(rawValue: AKEYCODE_TV_TELETEXT) } + + /// TV Number Entry key. + static var tvNumberEntry: KeyCode { KeyCode(rawValue: AKEYCODE_TV_NUMBER_ENTRY) } + + /// TV Terrestrial Analog key. + static var tvTerrestrialAnalog: KeyCode { KeyCode(rawValue: AKEYCODE_TV_TERRESTRIAL_ANALOG) } + + /// TV Terrestrial Digital key. + static var tvTerrestrialDigital: KeyCode { KeyCode(rawValue: AKEYCODE_TV_TERRESTRIAL_DIGITAL) } + + /// TV Satellite key. + static var tvSatellite: KeyCode { KeyCode(rawValue: AKEYCODE_TV_SATELLITE) } + + /// TV Satellite BS key. + static var tvSatelliteBS: KeyCode { KeyCode(rawValue: AKEYCODE_TV_SATELLITE_BS) } + + /// TV Satellite CS key. + static var tvSatelliteCS: KeyCode { KeyCode(rawValue: AKEYCODE_TV_SATELLITE_CS) } + + /// TV Satellite Service key. + static var tvSatelliteService: KeyCode { KeyCode(rawValue: AKEYCODE_TV_SATELLITE_SERVICE) } + + /// TV Network key. + static var tvNetwork: KeyCode { KeyCode(rawValue: AKEYCODE_TV_NETWORK) } + + /// TV Antenna/Cable key. + static var tvAntennaCable: KeyCode { KeyCode(rawValue: AKEYCODE_TV_ANTENNA_CABLE) } + + /// TV HDMI Input 1 key. + static var tvInputHDMI1: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_HDMI_1) } + + /// TV HDMI Input 2 key. + static var tvInputHDMI2: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_HDMI_2) } + + /// TV HDMI Input 3 key. + static var tvInputHDMI3: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_HDMI_3) } + + /// TV HDMI Input 4 key. + static var tvInputHDMI4: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_HDMI_4) } + + /// TV Composite Input 1 key. + static var tvInputComposite1: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_COMPOSITE_1) } + + /// TV Composite Input 2 key. + static var tvInputComposite2: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_COMPOSITE_2) } + + /// TV Component Input 1 key. + static var tvInputComponent1: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_COMPONENT_1) } + + /// TV Component Input 2 key. + static var tvInputComponent2: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_COMPONENT_2) } + + /// TV VGA Input 1 key. + static var tvInputVGA1: KeyCode { KeyCode(rawValue: AKEYCODE_TV_INPUT_VGA_1) } + + /// TV Audio Description key. + static var tvAudioDescription: KeyCode { KeyCode(rawValue: AKEYCODE_TV_AUDIO_DESCRIPTION) } + + /// TV Audio Description Mix Up key. + static var tvAudioDescriptionMixUp: KeyCode { KeyCode(rawValue: AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP) } + + /// TV Audio Description Mix Down key. + static var tvAudioDescriptionMixDown: KeyCode { KeyCode(rawValue: AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN) } + + /// TV Zoom Mode key. + static var tvZoomMode: KeyCode { KeyCode(rawValue: AKEYCODE_TV_ZOOM_MODE) } + + /// TV Contents Menu key. + static var tvContentsMenu: KeyCode { KeyCode(rawValue: AKEYCODE_TV_CONTENTS_MENU) } + + /// TV Media Context Menu key. + static var tvMediaContextMenu: KeyCode { KeyCode(rawValue: AKEYCODE_TV_MEDIA_CONTEXT_MENU) } + + /// TV Timer Programming key. + static var tvTimerProgramming: KeyCode { KeyCode(rawValue: AKEYCODE_TV_TIMER_PROGRAMMING) } + + /// TV remote '11' button. + static var key11: KeyCode { KeyCode(rawValue: AKEYCODE_11) } + + /// TV remote '12' button. + static var key12: KeyCode { KeyCode(rawValue: AKEYCODE_12) } + + // MARK: Video / Featured / Demo App Shortcuts + + /// Video App 1 shortcut key. + static var videoApp1: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_1) } + + /// Video App 2 shortcut key. + static var videoApp2: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_2) } + + /// Video App 3 shortcut key. + static var videoApp3: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_3) } + + /// Video App 4 shortcut key. + static var videoApp4: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_4) } + + /// Video App 5 shortcut key. + static var videoApp5: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_5) } + + /// Video App 6 shortcut key. + static var videoApp6: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_6) } + + /// Video App 7 shortcut key. + static var videoApp7: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_7) } + + /// Video App 8 shortcut key. + static var videoApp8: KeyCode { KeyCode(rawValue: AKEYCODE_VIDEO_APP_8) } + + /// Featured App 1 shortcut key. + static var featuredApp1: KeyCode { KeyCode(rawValue: AKEYCODE_FEATURED_APP_1) } + + /// Featured App 2 shortcut key. + static var featuredApp2: KeyCode { KeyCode(rawValue: AKEYCODE_FEATURED_APP_2) } + + /// Featured App 3 shortcut key. + static var featuredApp3: KeyCode { KeyCode(rawValue: AKEYCODE_FEATURED_APP_3) } + + /// Featured App 4 shortcut key. + static var featuredApp4: KeyCode { KeyCode(rawValue: AKEYCODE_FEATURED_APP_4) } + + /// Demo App 1 shortcut key. + static var demoApp1: KeyCode { KeyCode(rawValue: AKEYCODE_DEMO_APP_1) } + + /// Demo App 2 shortcut key. + static var demoApp2: KeyCode { KeyCode(rawValue: AKEYCODE_DEMO_APP_2) } + + /// Demo App 3 shortcut key. + static var demoApp3: KeyCode { KeyCode(rawValue: AKEYCODE_DEMO_APP_3) } + + /// Demo App 4 shortcut key. + static var demoApp4: KeyCode { KeyCode(rawValue: AKEYCODE_DEMO_APP_4) } + + // MARK: Keyboard Backlight + + /// Keyboard Backlight Down key. + static var keyboardBacklightDown: KeyCode { KeyCode(rawValue: AKEYCODE_KEYBOARD_BACKLIGHT_DOWN) } + + /// Keyboard Backlight Up key. + static var keyboardBacklightUp: KeyCode { KeyCode(rawValue: AKEYCODE_KEYBOARD_BACKLIGHT_UP) } + + /// Keyboard Backlight Toggle key. + static var keyboardBacklightToggle: KeyCode { KeyCode(rawValue: AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE) } + + // MARK: Stylus Buttons + + /// Primary stylus button. + static var stylusButtonPrimary: KeyCode { KeyCode(rawValue: AKEYCODE_STYLUS_BUTTON_PRIMARY) } + + /// Secondary stylus button. + static var stylusButtonSecondary: KeyCode { KeyCode(rawValue: AKEYCODE_STYLUS_BUTTON_SECONDARY) } + + /// Tertiary stylus button. + static var stylusButtonTertiary: KeyCode { KeyCode(rawValue: AKEYCODE_STYLUS_BUTTON_TERTIARY) } + + /// Tail stylus button. + static var stylusButtonTail: KeyCode { KeyCode(rawValue: AKEYCODE_STYLUS_BUTTON_TAIL) } + + // MARK: Macros + + /// Macro 1 key. + static var macro1: KeyCode { KeyCode(rawValue: AKEYCODE_MACRO_1) } + + /// Macro 2 key. + static var macro2: KeyCode { KeyCode(rawValue: AKEYCODE_MACRO_2) } + + /// Macro 3 key. + static var macro3: KeyCode { KeyCode(rawValue: AKEYCODE_MACRO_3) } + + /// Macro 4 key. + static var macro4: KeyCode { KeyCode(rawValue: AKEYCODE_MACRO_4) } +} diff --git a/Sources/AndroidInput/Syscalls.swift b/Sources/AndroidInput/Syscalls.swift new file mode 100644 index 00000000..51eb4c76 --- /dev/null +++ b/Sources/AndroidInput/Syscalls.swift @@ -0,0 +1,550 @@ +// +// Syscalls.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#endif + +#if !os(Android) + +func stub() -> Never { + fatalError("Not running on Android") +} + +// MARK: - AInputQueue + +func AInputQueue_attachLooper( + _ queue: OpaquePointer, + _ looper: OpaquePointer, + _ ident: Int32, + _ callback: (@convention(c) (Int32, Int32, UnsafeMutableRawPointer?) -> Int32)?, + _ data: UnsafeMutableRawPointer? +) { stub() } + +func AInputQueue_detachLooper(_ queue: OpaquePointer) { stub() } + +func AInputQueue_hasEvents(_ queue: OpaquePointer) -> Int32 { stub() } + +func AInputQueue_getEvent( + _ queue: OpaquePointer, + _ outEvent: UnsafeMutablePointer? +) -> Int32 { stub() } + +func AInputQueue_preDispatchEvent(_ queue: OpaquePointer, _ event: OpaquePointer) -> Int32 { stub() } + +func AInputQueue_finishEvent(_ queue: OpaquePointer, _ event: OpaquePointer, _ handled: Int32) { stub() } + +// MARK: - AInputEvent + +func AInputEvent_getType(_ event: OpaquePointer) -> Int32 { stub() } + +func AInputEvent_getDeviceId(_ event: OpaquePointer) -> Int32 { stub() } + +func AInputEvent_getSource(_ event: OpaquePointer) -> Int32 { stub() } + +func AInputEvent_getDisplayId(_ event: OpaquePointer) -> Int32 { stub() } + +// MARK: - AKeyEvent + +func AKeyEvent_getAction(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getFlags(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getKeyCode(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getScanCode(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getMetaState(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getRepeatCount(_ event: OpaquePointer) -> Int32 { stub() } + +func AKeyEvent_getDownTime(_ event: OpaquePointer) -> Int64 { stub() } + +func AKeyEvent_getEventTime(_ event: OpaquePointer) -> Int64 { stub() } + +// MARK: - AMotionEvent + +func AMotionEvent_getAction(_ event: OpaquePointer) -> Int32 { stub() } + +func AMotionEvent_getFlags(_ event: OpaquePointer) -> Int32 { stub() } + +func AMotionEvent_getMetaState(_ event: OpaquePointer) -> Int32 { stub() } + +func AMotionEvent_getButtonState(_ event: OpaquePointer) -> Int32 { stub() } + +func AMotionEvent_getEdgeFlags(_ event: OpaquePointer) -> Int32 { stub() } + +func AMotionEvent_getDownTime(_ event: OpaquePointer) -> Int64 { stub() } + +func AMotionEvent_getEventTime(_ event: OpaquePointer) -> Int64 { stub() } + +func AMotionEvent_getXOffset(_ event: OpaquePointer) -> Float { stub() } + +func AMotionEvent_getYOffset(_ event: OpaquePointer) -> Float { stub() } + +func AMotionEvent_getXPrecision(_ event: OpaquePointer) -> Float { stub() } + +func AMotionEvent_getYPrecision(_ event: OpaquePointer) -> Float { stub() } + +func AMotionEvent_getPointerCount(_ event: OpaquePointer) -> Int { stub() } + +func AMotionEvent_getPointerId(_ event: OpaquePointer, _ pointerIndex: Int) -> Int32 { stub() } + +func AMotionEvent_getToolType(_ event: OpaquePointer, _ pointerIndex: Int) -> Int32 { stub() } + +func AMotionEvent_getRawX(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getRawY(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getX(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getY(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getPressure(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getSize(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getTouchMajor(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getTouchMinor(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getToolMajor(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getToolMinor(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getOrientation(_ event: OpaquePointer, _ pointerIndex: Int) -> Float { stub() } + +func AMotionEvent_getAxisValue( + _ event: OpaquePointer, + _ axis: Int32, + _ pointerIndex: Int +) -> Float { stub() } + +func AMotionEvent_getHistorySize(_ event: OpaquePointer) -> Int { stub() } + +func AMotionEvent_getHistoricalX( + _ event: OpaquePointer, + _ pointerIndex: Int, + _ historyIndex: Int +) -> Float { stub() } + +func AMotionEvent_getHistoricalY( + _ event: OpaquePointer, + _ pointerIndex: Int, + _ historyIndex: Int +) -> Float { stub() } + +// MARK: - AInputEvent Constants + +let AINPUT_EVENT_TYPE_KEY: Int = 1 +let AINPUT_EVENT_TYPE_MOTION: Int = 2 +let AINPUT_EVENT_TYPE_FOCUS: Int = 3 +let AINPUT_EVENT_TYPE_CAPTURE: Int = 4 +let AINPUT_EVENT_TYPE_DRAG: Int = 5 +let AINPUT_EVENT_TYPE_TOUCH_MODE: Int = 6 + +let AINPUT_SOURCE_UNKNOWN: UInt32 = 0 +let AINPUT_SOURCE_KEYBOARD: UInt32 = 0x101 +let AINPUT_SOURCE_DPAD: UInt32 = 0x201 +let AINPUT_SOURCE_GAMEPAD: UInt32 = 0x401 +let AINPUT_SOURCE_TOUCHSCREEN: UInt32 = 0x1002 +let AINPUT_SOURCE_MOUSE: UInt32 = 0x2002 +let AINPUT_SOURCE_STYLUS: UInt32 = 0x4002 +let AINPUT_SOURCE_BLUETOOTH_STYLUS: UInt32 = 0x8002 +let AINPUT_SOURCE_TRACKBALL: UInt32 = 0x10004 +let AINPUT_SOURCE_MOUSE_RELATIVE: UInt32 = 0x20004 +let AINPUT_SOURCE_TOUCHPAD: UInt32 = 0x100008 +let AINPUT_SOURCE_TOUCH_NAVIGATION: UInt32 = 0x200000 +let AINPUT_SOURCE_JOYSTICK: UInt32 = 0x1000010 +let AINPUT_SOURCE_HDMI: UInt32 = 0x2000010 +let AINPUT_SOURCE_SENSOR: UInt32 = 0x4000000 +let AINPUT_SOURCE_ROTARY_ENCODER: UInt32 = 0x400000 +let AINPUT_SOURCE_ANY: UInt32 = 0xFFFFFFFF + +// MARK: - AKeyEvent Constants + +let AKEY_EVENT_ACTION_DOWN: Int32 = 0 +let AKEY_EVENT_ACTION_UP: Int32 = 1 +let AKEY_EVENT_ACTION_MULTIPLE: Int32 = 2 + +// MARK: - AMotionEvent Constants + +let AMOTION_EVENT_ACTION_DOWN: Int32 = 0 +let AMOTION_EVENT_ACTION_UP: Int32 = 1 +let AMOTION_EVENT_ACTION_MOVE: Int32 = 2 +let AMOTION_EVENT_ACTION_CANCEL: Int32 = 3 +let AMOTION_EVENT_ACTION_OUTSIDE: Int32 = 4 +let AMOTION_EVENT_ACTION_POINTER_DOWN: Int32 = 5 +let AMOTION_EVENT_ACTION_POINTER_UP: Int32 = 6 +let AMOTION_EVENT_ACTION_HOVER_MOVE: Int32 = 7 +let AMOTION_EVENT_ACTION_SCROLL: Int32 = 8 +let AMOTION_EVENT_ACTION_HOVER_ENTER: Int32 = 9 +let AMOTION_EVENT_ACTION_HOVER_EXIT: Int32 = 10 +let AMOTION_EVENT_ACTION_BUTTON_PRESS: Int32 = 11 +let AMOTION_EVENT_ACTION_BUTTON_RELEASE: Int32 = 12 + +let AMOTION_EVENT_TOOL_TYPE_UNKNOWN: Int32 = 0 +let AMOTION_EVENT_TOOL_TYPE_FINGER: Int32 = 1 +let AMOTION_EVENT_TOOL_TYPE_STYLUS: Int32 = 2 +let AMOTION_EVENT_TOOL_TYPE_MOUSE: Int32 = 3 +let AMOTION_EVENT_TOOL_TYPE_ERASER: Int32 = 4 + +// MARK: - AKEYCODE Constants + +let AKEYCODE_UNKNOWN: Int32 = 0 +let AKEYCODE_SOFT_LEFT: Int32 = 1 +let AKEYCODE_SOFT_RIGHT: Int32 = 2 +let AKEYCODE_HOME: Int32 = 3 +let AKEYCODE_BACK: Int32 = 4 +let AKEYCODE_CALL: Int32 = 5 +let AKEYCODE_ENDCALL: Int32 = 6 +let AKEYCODE_0: Int32 = 7 +let AKEYCODE_1: Int32 = 8 +let AKEYCODE_2: Int32 = 9 +let AKEYCODE_3: Int32 = 10 +let AKEYCODE_4: Int32 = 11 +let AKEYCODE_5: Int32 = 12 +let AKEYCODE_6: Int32 = 13 +let AKEYCODE_7: Int32 = 14 +let AKEYCODE_8: Int32 = 15 +let AKEYCODE_9: Int32 = 16 +let AKEYCODE_STAR: Int32 = 17 +let AKEYCODE_POUND: Int32 = 18 +let AKEYCODE_DPAD_UP: Int32 = 19 +let AKEYCODE_DPAD_DOWN: Int32 = 20 +let AKEYCODE_DPAD_LEFT: Int32 = 21 +let AKEYCODE_DPAD_RIGHT: Int32 = 22 +let AKEYCODE_DPAD_CENTER: Int32 = 23 +let AKEYCODE_VOLUME_UP: Int32 = 24 +let AKEYCODE_VOLUME_DOWN: Int32 = 25 +let AKEYCODE_POWER: Int32 = 26 +let AKEYCODE_CAMERA: Int32 = 27 +let AKEYCODE_CLEAR: Int32 = 28 +let AKEYCODE_A: Int32 = 29 +let AKEYCODE_B: Int32 = 30 +let AKEYCODE_C: Int32 = 31 +let AKEYCODE_D: Int32 = 32 +let AKEYCODE_E: Int32 = 33 +let AKEYCODE_F: Int32 = 34 +let AKEYCODE_G: Int32 = 35 +let AKEYCODE_H: Int32 = 36 +let AKEYCODE_I: Int32 = 37 +let AKEYCODE_J: Int32 = 38 +let AKEYCODE_K: Int32 = 39 +let AKEYCODE_L: Int32 = 40 +let AKEYCODE_M: Int32 = 41 +let AKEYCODE_N: Int32 = 42 +let AKEYCODE_O: Int32 = 43 +let AKEYCODE_P: Int32 = 44 +let AKEYCODE_Q: Int32 = 45 +let AKEYCODE_R: Int32 = 46 +let AKEYCODE_S: Int32 = 47 +let AKEYCODE_T: Int32 = 48 +let AKEYCODE_U: Int32 = 49 +let AKEYCODE_V: Int32 = 50 +let AKEYCODE_W: Int32 = 51 +let AKEYCODE_X: Int32 = 52 +let AKEYCODE_Y: Int32 = 53 +let AKEYCODE_Z: Int32 = 54 +let AKEYCODE_COMMA: Int32 = 55 +let AKEYCODE_PERIOD: Int32 = 56 +let AKEYCODE_ALT_LEFT: Int32 = 57 +let AKEYCODE_ALT_RIGHT: Int32 = 58 +let AKEYCODE_SHIFT_LEFT: Int32 = 59 +let AKEYCODE_SHIFT_RIGHT: Int32 = 60 +let AKEYCODE_TAB: Int32 = 61 +let AKEYCODE_SPACE: Int32 = 62 +let AKEYCODE_SYM: Int32 = 63 +let AKEYCODE_EXPLORER: Int32 = 64 +let AKEYCODE_ENVELOPE: Int32 = 65 +let AKEYCODE_ENTER: Int32 = 66 +let AKEYCODE_DEL: Int32 = 67 +let AKEYCODE_GRAVE: Int32 = 68 +let AKEYCODE_MINUS: Int32 = 69 +let AKEYCODE_EQUALS: Int32 = 70 +let AKEYCODE_LEFT_BRACKET: Int32 = 71 +let AKEYCODE_RIGHT_BRACKET: Int32 = 72 +let AKEYCODE_BACKSLASH: Int32 = 73 +let AKEYCODE_SEMICOLON: Int32 = 74 +let AKEYCODE_APOSTROPHE: Int32 = 75 +let AKEYCODE_SLASH: Int32 = 76 +let AKEYCODE_AT: Int32 = 77 +let AKEYCODE_NUM: Int32 = 78 +let AKEYCODE_HEADSETHOOK: Int32 = 79 +let AKEYCODE_FOCUS: Int32 = 80 +let AKEYCODE_PLUS: Int32 = 81 +let AKEYCODE_MENU: Int32 = 82 +let AKEYCODE_NOTIFICATION: Int32 = 83 +let AKEYCODE_SEARCH: Int32 = 84 +let AKEYCODE_MEDIA_PLAY_PAUSE: Int32 = 85 +let AKEYCODE_MEDIA_STOP: Int32 = 86 +let AKEYCODE_MEDIA_NEXT: Int32 = 87 +let AKEYCODE_MEDIA_PREVIOUS: Int32 = 88 +let AKEYCODE_MEDIA_REWIND: Int32 = 89 +let AKEYCODE_MEDIA_FAST_FORWARD: Int32 = 90 +let AKEYCODE_MUTE: Int32 = 91 +let AKEYCODE_PAGE_UP: Int32 = 92 +let AKEYCODE_PAGE_DOWN: Int32 = 93 +let AKEYCODE_PICTSYMBOLS: Int32 = 94 +let AKEYCODE_SWITCH_CHARSET: Int32 = 95 +let AKEYCODE_BUTTON_A: Int32 = 96 +let AKEYCODE_BUTTON_B: Int32 = 97 +let AKEYCODE_BUTTON_C: Int32 = 98 +let AKEYCODE_BUTTON_X: Int32 = 99 +let AKEYCODE_BUTTON_Y: Int32 = 100 +let AKEYCODE_BUTTON_Z: Int32 = 101 +let AKEYCODE_BUTTON_L1: Int32 = 102 +let AKEYCODE_BUTTON_R1: Int32 = 103 +let AKEYCODE_BUTTON_L2: Int32 = 104 +let AKEYCODE_BUTTON_R2: Int32 = 105 +let AKEYCODE_BUTTON_THUMBL: Int32 = 106 +let AKEYCODE_BUTTON_THUMBR: Int32 = 107 +let AKEYCODE_BUTTON_START: Int32 = 108 +let AKEYCODE_BUTTON_SELECT: Int32 = 109 +let AKEYCODE_BUTTON_MODE: Int32 = 110 +let AKEYCODE_ESCAPE: Int32 = 111 +let AKEYCODE_FORWARD_DEL: Int32 = 112 +let AKEYCODE_CTRL_LEFT: Int32 = 113 +let AKEYCODE_CTRL_RIGHT: Int32 = 114 +let AKEYCODE_CAPS_LOCK: Int32 = 115 +let AKEYCODE_SCROLL_LOCK: Int32 = 116 +let AKEYCODE_META_LEFT: Int32 = 117 +let AKEYCODE_META_RIGHT: Int32 = 118 +let AKEYCODE_FUNCTION: Int32 = 119 +let AKEYCODE_SYSRQ: Int32 = 120 +let AKEYCODE_BREAK: Int32 = 121 +let AKEYCODE_MOVE_HOME: Int32 = 122 +let AKEYCODE_MOVE_END: Int32 = 123 +let AKEYCODE_INSERT: Int32 = 124 +let AKEYCODE_FORWARD: Int32 = 125 +let AKEYCODE_MEDIA_PLAY: Int32 = 126 +let AKEYCODE_MEDIA_PAUSE: Int32 = 127 +let AKEYCODE_MEDIA_CLOSE: Int32 = 128 +let AKEYCODE_MEDIA_EJECT: Int32 = 129 +let AKEYCODE_MEDIA_RECORD: Int32 = 130 +let AKEYCODE_F1: Int32 = 131 +let AKEYCODE_F2: Int32 = 132 +let AKEYCODE_F3: Int32 = 133 +let AKEYCODE_F4: Int32 = 134 +let AKEYCODE_F5: Int32 = 135 +let AKEYCODE_F6: Int32 = 136 +let AKEYCODE_F7: Int32 = 137 +let AKEYCODE_F8: Int32 = 138 +let AKEYCODE_F9: Int32 = 139 +let AKEYCODE_F10: Int32 = 140 +let AKEYCODE_F11: Int32 = 141 +let AKEYCODE_F12: Int32 = 142 +let AKEYCODE_NUM_LOCK: Int32 = 143 +let AKEYCODE_NUMPAD_0: Int32 = 144 +let AKEYCODE_NUMPAD_1: Int32 = 145 +let AKEYCODE_NUMPAD_2: Int32 = 146 +let AKEYCODE_NUMPAD_3: Int32 = 147 +let AKEYCODE_NUMPAD_4: Int32 = 148 +let AKEYCODE_NUMPAD_5: Int32 = 149 +let AKEYCODE_NUMPAD_6: Int32 = 150 +let AKEYCODE_NUMPAD_7: Int32 = 151 +let AKEYCODE_NUMPAD_8: Int32 = 152 +let AKEYCODE_NUMPAD_9: Int32 = 153 +let AKEYCODE_NUMPAD_DIVIDE: Int32 = 154 +let AKEYCODE_NUMPAD_MULTIPLY: Int32 = 155 +let AKEYCODE_NUMPAD_SUBTRACT: Int32 = 156 +let AKEYCODE_NUMPAD_ADD: Int32 = 157 +let AKEYCODE_NUMPAD_DOT: Int32 = 158 +let AKEYCODE_NUMPAD_COMMA: Int32 = 159 +let AKEYCODE_NUMPAD_ENTER: Int32 = 160 +let AKEYCODE_NUMPAD_EQUALS: Int32 = 161 +let AKEYCODE_NUMPAD_LEFT_PAREN: Int32 = 162 +let AKEYCODE_NUMPAD_RIGHT_PAREN: Int32 = 163 +let AKEYCODE_VOLUME_MUTE: Int32 = 164 +let AKEYCODE_INFO: Int32 = 165 +let AKEYCODE_CHANNEL_UP: Int32 = 166 +let AKEYCODE_CHANNEL_DOWN: Int32 = 167 +let AKEYCODE_ZOOM_IN: Int32 = 168 +let AKEYCODE_ZOOM_OUT: Int32 = 169 +let AKEYCODE_TV: Int32 = 170 +let AKEYCODE_WINDOW: Int32 = 171 +let AKEYCODE_GUIDE: Int32 = 172 +let AKEYCODE_DVR: Int32 = 173 +let AKEYCODE_BOOKMARK: Int32 = 174 +let AKEYCODE_CAPTIONS: Int32 = 175 +let AKEYCODE_SETTINGS: Int32 = 176 +let AKEYCODE_TV_POWER: Int32 = 177 +let AKEYCODE_TV_INPUT: Int32 = 178 +let AKEYCODE_STB_POWER: Int32 = 179 +let AKEYCODE_STB_INPUT: Int32 = 180 +let AKEYCODE_AVR_POWER: Int32 = 181 +let AKEYCODE_AVR_INPUT: Int32 = 182 +let AKEYCODE_PROG_RED: Int32 = 183 +let AKEYCODE_PROG_GREEN: Int32 = 184 +let AKEYCODE_PROG_YELLOW: Int32 = 185 +let AKEYCODE_PROG_BLUE: Int32 = 186 +let AKEYCODE_APP_SWITCH: Int32 = 187 +let AKEYCODE_BUTTON_1: Int32 = 188 +let AKEYCODE_BUTTON_2: Int32 = 189 +let AKEYCODE_BUTTON_3: Int32 = 190 +let AKEYCODE_BUTTON_4: Int32 = 191 +let AKEYCODE_BUTTON_5: Int32 = 192 +let AKEYCODE_BUTTON_6: Int32 = 193 +let AKEYCODE_BUTTON_7: Int32 = 194 +let AKEYCODE_BUTTON_8: Int32 = 195 +let AKEYCODE_BUTTON_9: Int32 = 196 +let AKEYCODE_BUTTON_10: Int32 = 197 +let AKEYCODE_BUTTON_11: Int32 = 198 +let AKEYCODE_BUTTON_12: Int32 = 199 +let AKEYCODE_BUTTON_13: Int32 = 200 +let AKEYCODE_BUTTON_14: Int32 = 201 +let AKEYCODE_BUTTON_15: Int32 = 202 +let AKEYCODE_BUTTON_16: Int32 = 203 +let AKEYCODE_LANGUAGE_SWITCH: Int32 = 204 +let AKEYCODE_MANNER_MODE: Int32 = 205 +let AKEYCODE_3D_MODE: Int32 = 206 +let AKEYCODE_CONTACTS: Int32 = 207 +let AKEYCODE_CALENDAR: Int32 = 208 +let AKEYCODE_MUSIC: Int32 = 209 +let AKEYCODE_CALCULATOR: Int32 = 210 +let AKEYCODE_ZENKAKU_HANKAKU: Int32 = 211 +let AKEYCODE_EISU: Int32 = 212 +let AKEYCODE_MUHENKAN: Int32 = 213 +let AKEYCODE_HENKAN: Int32 = 214 +let AKEYCODE_KATAKANA_HIRAGANA: Int32 = 215 +let AKEYCODE_YEN: Int32 = 216 +let AKEYCODE_RO: Int32 = 217 +let AKEYCODE_KANA: Int32 = 218 +let AKEYCODE_ASSIST: Int32 = 219 +let AKEYCODE_BRIGHTNESS_DOWN: Int32 = 220 +let AKEYCODE_BRIGHTNESS_UP: Int32 = 221 +let AKEYCODE_MEDIA_AUDIO_TRACK: Int32 = 222 +let AKEYCODE_SLEEP: Int32 = 223 +let AKEYCODE_WAKEUP: Int32 = 224 +let AKEYCODE_PAIRING: Int32 = 225 +let AKEYCODE_MEDIA_TOP_MENU: Int32 = 226 +let AKEYCODE_11: Int32 = 227 +let AKEYCODE_12: Int32 = 228 +let AKEYCODE_LAST_CHANNEL: Int32 = 229 +let AKEYCODE_TV_DATA_SERVICE: Int32 = 230 +let AKEYCODE_VOICE_ASSIST: Int32 = 231 +let AKEYCODE_TV_RADIO_SERVICE: Int32 = 232 +let AKEYCODE_TV_TELETEXT: Int32 = 233 +let AKEYCODE_TV_NUMBER_ENTRY: Int32 = 234 +let AKEYCODE_TV_TERRESTRIAL_ANALOG: Int32 = 235 +let AKEYCODE_TV_TERRESTRIAL_DIGITAL: Int32 = 236 +let AKEYCODE_TV_SATELLITE: Int32 = 237 +let AKEYCODE_TV_SATELLITE_BS: Int32 = 238 +let AKEYCODE_TV_SATELLITE_CS: Int32 = 239 +let AKEYCODE_TV_SATELLITE_SERVICE: Int32 = 240 +let AKEYCODE_TV_NETWORK: Int32 = 241 +let AKEYCODE_TV_ANTENNA_CABLE: Int32 = 242 +let AKEYCODE_TV_INPUT_HDMI_1: Int32 = 243 +let AKEYCODE_TV_INPUT_HDMI_2: Int32 = 244 +let AKEYCODE_TV_INPUT_HDMI_3: Int32 = 245 +let AKEYCODE_TV_INPUT_HDMI_4: Int32 = 246 +let AKEYCODE_TV_INPUT_COMPOSITE_1: Int32 = 247 +let AKEYCODE_TV_INPUT_COMPOSITE_2: Int32 = 248 +let AKEYCODE_TV_INPUT_COMPONENT_1: Int32 = 249 +let AKEYCODE_TV_INPUT_COMPONENT_2: Int32 = 250 +let AKEYCODE_TV_INPUT_VGA_1: Int32 = 251 +let AKEYCODE_TV_AUDIO_DESCRIPTION: Int32 = 252 +let AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: Int32 = 253 +let AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: Int32 = 254 +let AKEYCODE_TV_ZOOM_MODE: Int32 = 255 +let AKEYCODE_TV_CONTENTS_MENU: Int32 = 256 +let AKEYCODE_TV_MEDIA_CONTEXT_MENU: Int32 = 257 +let AKEYCODE_TV_TIMER_PROGRAMMING: Int32 = 258 +let AKEYCODE_HELP: Int32 = 259 +let AKEYCODE_NAVIGATE_PREVIOUS: Int32 = 260 +let AKEYCODE_NAVIGATE_NEXT: Int32 = 261 +let AKEYCODE_NAVIGATE_IN: Int32 = 262 +let AKEYCODE_NAVIGATE_OUT: Int32 = 263 +let AKEYCODE_STEM_PRIMARY: Int32 = 264 +let AKEYCODE_STEM_1: Int32 = 265 +let AKEYCODE_STEM_2: Int32 = 266 +let AKEYCODE_STEM_3: Int32 = 267 +let AKEYCODE_DPAD_UP_LEFT: Int32 = 268 +let AKEYCODE_DPAD_DOWN_LEFT: Int32 = 269 +let AKEYCODE_DPAD_UP_RIGHT: Int32 = 270 +let AKEYCODE_DPAD_DOWN_RIGHT: Int32 = 271 +let AKEYCODE_MEDIA_SKIP_FORWARD: Int32 = 272 +let AKEYCODE_MEDIA_SKIP_BACKWARD: Int32 = 273 +let AKEYCODE_MEDIA_STEP_FORWARD: Int32 = 274 +let AKEYCODE_MEDIA_STEP_BACKWARD: Int32 = 275 +let AKEYCODE_SOFT_SLEEP: Int32 = 276 +let AKEYCODE_CUT: Int32 = 277 +let AKEYCODE_COPY: Int32 = 278 +let AKEYCODE_PASTE: Int32 = 279 +let AKEYCODE_SYSTEM_NAVIGATION_UP: Int32 = 280 +let AKEYCODE_SYSTEM_NAVIGATION_DOWN: Int32 = 281 +let AKEYCODE_SYSTEM_NAVIGATION_LEFT: Int32 = 282 +let AKEYCODE_SYSTEM_NAVIGATION_RIGHT: Int32 = 283 +let AKEYCODE_ALL_APPS: Int32 = 284 +let AKEYCODE_REFRESH: Int32 = 285 +let AKEYCODE_THUMBS_UP: Int32 = 286 +let AKEYCODE_THUMBS_DOWN: Int32 = 287 +let AKEYCODE_PROFILE_SWITCH: Int32 = 288 +let AKEYCODE_VIDEO_APP_1: Int32 = 289 +let AKEYCODE_VIDEO_APP_2: Int32 = 290 +let AKEYCODE_VIDEO_APP_3: Int32 = 291 +let AKEYCODE_VIDEO_APP_4: Int32 = 292 +let AKEYCODE_VIDEO_APP_5: Int32 = 293 +let AKEYCODE_VIDEO_APP_6: Int32 = 294 +let AKEYCODE_VIDEO_APP_7: Int32 = 295 +let AKEYCODE_VIDEO_APP_8: Int32 = 296 +let AKEYCODE_FEATURED_APP_1: Int32 = 297 +let AKEYCODE_FEATURED_APP_2: Int32 = 298 +let AKEYCODE_FEATURED_APP_3: Int32 = 299 +let AKEYCODE_FEATURED_APP_4: Int32 = 300 +let AKEYCODE_DEMO_APP_1: Int32 = 301 +let AKEYCODE_DEMO_APP_2: Int32 = 302 +let AKEYCODE_DEMO_APP_3: Int32 = 303 +let AKEYCODE_DEMO_APP_4: Int32 = 304 +let AKEYCODE_KEYBOARD_BACKLIGHT_DOWN: Int32 = 305 +let AKEYCODE_KEYBOARD_BACKLIGHT_UP: Int32 = 306 +let AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE: Int32 = 307 +let AKEYCODE_STYLUS_BUTTON_PRIMARY: Int32 = 308 +let AKEYCODE_STYLUS_BUTTON_SECONDARY: Int32 = 309 +let AKEYCODE_STYLUS_BUTTON_TERTIARY: Int32 = 310 +let AKEYCODE_STYLUS_BUTTON_TAIL: Int32 = 311 +let AKEYCODE_RECENT_APPS: Int32 = 312 +let AKEYCODE_MACRO_1: Int32 = 313 +let AKEYCODE_MACRO_2: Int32 = 314 +let AKEYCODE_MACRO_3: Int32 = 315 +let AKEYCODE_MACRO_4: Int32 = 316 +let AKEYCODE_EMOJI_PICKER: Int32 = 317 +let AKEYCODE_SCREENSHOT: Int32 = 318 + +// MARK: - JNI Types + +typealias JNIEnvironment = OpaquePointer +typealias jobject = OpaquePointer + +// MARK: - Paddleboat + +struct Paddleboat_Vibration_Data { + var duration_ms: Int32 + var left_motor_intensity: Float + var right_motor_intensity: Float + init(duration_ms: Int32, left_motor_intensity: Float, right_motor_intensity: Float) { + self.duration_ms = duration_ms + self.left_motor_intensity = left_motor_intensity + self.right_motor_intensity = right_motor_intensity + } +} + +func Paddleboat_init(_ env: JNIEnvironment, _ context: jobject) -> Int32 { stub() } +func Paddleboat_isInitialized() -> Bool { stub() } +func Paddleboat_destroy(_ env: JNIEnvironment) { stub() } +func Paddleboat_update(_ env: JNIEnvironment) { stub() } +func Paddleboat_setBackButtonConsumed(_ consume: Bool) { stub() } +func Paddleboat_getBackButtonConsumed() -> Bool { stub() } +func Paddleboat_getControllerStatus(_ index: Int32) -> Int32 { stub() } +func Paddleboat_getControllerName(_ index: Int32, _ bufferSize: Int32, _ buffer: UnsafeMutablePointer) -> Int32 { stub() } +func Paddleboat_setControllerLight(_ index: Int32, _ type: Int32, _ data: UInt32, _ env: JNIEnvironment) -> Int32 { stub() } +func Paddleboat_setControllerVibrationData(_ index: Int32, _ data: UnsafeMutablePointer, _ env: JNIEnvironment) -> Int32 { stub() } +func Paddleboat_getIntegratedMotionSensorFlags() -> UInt32 { stub() } + +#endif diff --git a/Sources/AndroidKit/AndroidKit.swift b/Sources/AndroidKit/AndroidKit.swift index a244c9ef..a219357c 100644 --- a/Sources/AndroidKit/AndroidKit.swift +++ b/Sources/AndroidKit/AndroidKit.swift @@ -31,4 +31,7 @@ import AndroidNDK @_exported import AndroidWebKit @_exported import AndroidLogging @_exported import AndroidLooper +@_exported import AndroidHardware @_exported import AndroidFileManager +@_exported import AndroidNativeActivity +@_exported import AndroidInput diff --git a/Sources/AndroidNativeActivity/NativeActivity.swift b/Sources/AndroidNativeActivity/NativeActivity.swift new file mode 100644 index 00000000..d031cb83 --- /dev/null +++ b/Sources/AndroidNativeActivity/NativeActivity.swift @@ -0,0 +1,233 @@ +// +// NativeActivity.swift +// SwiftAndroid +// +// Created by Alsey Coleman Miller on 2/27/26. +// + +#if os(Android) +import Android +import AndroidNDK +#endif +import AndroidLooper +import AndroidFileManager +import SystemPackage + +/// Native Activity +/// +/// This structure defines the native side of an android.app.NativeActivity. +/// It is created by the framework, and handed to the application's native code as it is being launched. +/// +/// [See Also](https://developer.android.com/ndk/reference/group/native-activity#anativeactivity) +public final class NativeActivity { + + // MARK: - Properties + + internal let pointer: UnsafeMutablePointer + + // MARK: - Initialization + + internal init(_ pointer: UnsafeMutablePointer) { + self.pointer = pointer + } + + deinit { + ANativeActivity_finish(pointer) + } + + // MARK: - Accessors + + /// Pointer to the callback function table of the native application. + /// + /// You can set the functions here to your own callbacks. The callbacks pointer itself is not immutable, so you must not call them directly. We recommend copying the callbacks to your own unique callbacks table and using those directly. + public var callbacks: UnsafeMutablePointer { + pointer.pointee.callbacks + } + + /// The NativeActivity object handle. + /// + /// This is the native instance of the android.app.NativeActivity Java class. + public var javaActivity: jobject { + pointer.pointee.clazz + } + + /// Path to this application's internal data directory. + public var internalDataPath: FilePath { + FilePath(String(cString: pointer.pointee.internalDataPath)) + } + + /// Path to this application's external (removable/mountable) data directory. + public var externalDataPath: FilePath { + FilePath(String(cString: pointer.pointee.externalDataPath)) + } + + /// The platform's SDK version code. + public var sdkVersion: Int32 { + pointer.pointee.sdkVersion + } + + /// This is the native instance of the application. + /// + /// It is not used by the framework, but can be set by the application to its own instance state. + public var instance: UnsafeMutableRawPointer? { + get { pointer.pointee.instance } + set { pointer.pointee.instance = newValue } + } + + /// Pointer to the Asset Manager instance for the application. + /// + /// The application uses this to access binary assets bundled inside its own .apk file. + public var assetManager: AndroidFileManager.AssetManager { + AndroidFileManager.AssetManager(pointer.pointee.assetManager) + } + + /// Available starting with Honeycomb: path to the directory containing the application's OBB files (if any). + /// + /// If the app doesn't have any OBB files, this directory may not exist. + public var obbPath: FilePath? { + guard let path = pointer.pointee.obbPath else { + return nil + } + return FilePath(String(cString: path)) + } +} + +// MARK: - Native Activity Callbacks + +/// These are the callbacks the framework makes into a native application. +/// +/// All of these callbacks happen on the main thread of the application. By default, all callbacks are NULL; set to a pointer to your own function to have it called. +/// +/// [See Also](https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks) +public struct NativeActivityCallbacks: Sendable { + + /// NativeActivity has started. + /// + /// See Java documentation for Activity.onStart() for more information. + public var onStart: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// NativeActivity has resumed. + /// + /// See Java documentation for Activity.onResume() for more information. + public var onResume: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// Framework is asking NativeActivity to save its current instance state. + /// + /// See Java documentation for Activity.onSaveInstanceState() for more information. + /// The returned pointer needs to be created with malloc(); the framework will call free() on it for you. + /// You also must fill in outSize with the number of bytes in the allocation. Note that the saved state will be persisted, so it can not contain any active entities (pointers to memory, file descriptors, etc). + public var onSaveInstanceState: (@convention(c) (UnsafeMutablePointer, UnsafeMutablePointer) -> UnsafeMutableRawPointer?)? + + /// NativeActivity has paused. + /// + /// See Java documentation for Activity.onPause() for more information. + public var onPause: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// NativeActivity has stopped. + /// + /// See Java documentation for Activity.onStop() for more information. + public var onStop: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// NativeActivity is being destroyed. + /// + /// See Java documentation for Activity.onDestroy() for more information. + public var onDestroy: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// Focus has changed in this NativeActivity's window. + /// + /// This is often used, for example, to pause a game when it loses input focus. + public var onWindowFocusChanged: (@convention(c) (UnsafeMutablePointer, Int32) -> Void)? + + /// The drawing window for this native activity has been created. + /// + /// You can use the window pointer to draw. + public var onNativeWindowCreated: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The drawing window for this native activity has been resized. + /// + /// You should retrieve the new size from the window and ensure that your rendering in it now matches. + public var onNativeWindowResized: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The drawing window for this native activity needs to be redrawn. + /// + /// To avoid transient artifacts during screen changes (such as orientation change), applications should not return from this function until they have finished drawing their window in its current state. + public var onNativeWindowRedrawNeeded: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The drawing window for this native activity is going to be destroyed. + /// + /// You MUST ensure that you do not touch the window object after returning from this function: in the common case of drawing to the window from another thread, that means the implementation of this callback must properly synchronize with the other thread to stop its drawing before returning from here. + public var onNativeWindowDestroyed: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The input queue for this native activity's window has been created. + /// + /// You can use it to monitor user input events. + public var onInputQueueCreated: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The input queue for this native activity's window is being destroyed. + /// + /// You should no longer try to reference it. Pending events may still be delivered. + public var onInputQueueDestroyed: (@convention(c) (UnsafeMutablePointer, OpaquePointer?) -> Void)? + + /// The rectangle in the window in which content should be placed has changed. + public var onContentRectChanged: (@convention(c) (UnsafeMutablePointer, UnsafePointer?) -> Void)? + + /// The current device AConfiguration has changed. + /// + /// The new configuration can be retrieved from assetManager. + public var onConfigurationChanged: (@convention(c) (UnsafeMutablePointer) -> Void)? + + /// The system is running low on memory. + /// + /// Try to reduce your memory use. + public var onLowMemory: (@convention(c) (UnsafeMutablePointer) -> Void)? +} + +// MARK: - Native Activity Functions + +public extension NativeActivity { + + /// Change the window format of the given activity. + /// + /// Calls getWindow().setFormat() of the given activity. + /// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place. + func setWindowFormat(_ format: Int32) { + ANativeActivity_setWindowFormat(pointer, format) + } + + /// Change the window flags of the given activity. + /// + /// Calls getWindow().setFlags() of the given activity. + /// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place. See window.h for flag constants. + func setWindowFlags(addFlags: UInt32, removeFlags: UInt32) { + ANativeActivity_setWindowFlags(pointer, addFlags, removeFlags) + } + + /// Show the IME while in the given activity. + /// + /// Calls InputMethodManager.showSoftInput() for the given activity. + /// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place. + func showSoftInput(flags: UInt32) { + ANativeActivity_showSoftInput(pointer, flags) + } + + /// Hide the IME while in the given activity. + /// + /// Calls InputMethodManager.hideSoftInput() for the given activity. + /// Note that this method can be called from any thread; it will send a message to the main thread of the process where the Java finish call will take place. + func hideSoftInput(flags: UInt32) { + ANativeActivity_hideSoftInput(pointer, flags) + } +} + +#if !os(Android) +// Stubs for non-Android platforms +private func ANativeActivity_setWindowFormat(_ activity: UnsafeMutablePointer, _ format: Int32) { fatalError("stub") } +private func ANativeActivity_setWindowFlags(_ activity: UnsafeMutablePointer, _ addFlags: UInt32, _ removeFlags: UInt32) { fatalError("stub") } +private func ANativeActivity_showSoftInput(_ activity: UnsafeMutablePointer, _ flags: UInt32) { fatalError("stub") } +private func ANativeActivity_hideSoftInput(_ activity: UnsafeMutablePointer, _ flags: UInt32) { fatalError("stub") } +private func ANativeActivity_finish(_ activity: UnsafeMutablePointer) { fatalError("stub") } + +public typealias ANativeActivity = OpaquePointer +public typealias ANativeActivityCallbacks = OpaquePointer +public typealias ARect = OpaquePointer +#endif