158 lines
4.0 KiB
Swift
158 lines
4.0 KiB
Swift
import Foundation
|
|
import SDL2
|
|
|
|
|
|
public class GamePad
|
|
{
|
|
public enum Axes
|
|
{
|
|
case leftStickX, leftStickY
|
|
case rightStickX, rightStickY
|
|
case leftTrigger, rightTrigger
|
|
}
|
|
|
|
public enum Buttons
|
|
{
|
|
case east, south, north, west
|
|
case select, start, guide, mic, touchPad
|
|
case leftStick, rightStick
|
|
case leftBumper, rightBumper
|
|
case dpadLeft, dpadRight, dpadUp, dpadDown
|
|
case paddle1, paddle2, paddle3, paddle4
|
|
}
|
|
|
|
public struct State
|
|
{
|
|
public func down(_ btn: Buttons) -> Bool { btnState(btn) & GamePad._DOWN == GamePad._DOWN }
|
|
public func pressed(_ btn: Buttons) -> Bool { btnState(btn) == GamePad._PRESS }
|
|
public func released(_ btn: Buttons) -> Bool { btnState(btn) == GamePad._RELEASE }
|
|
|
|
public func axis(_ axis: Axes) -> Float
|
|
{
|
|
let axisRescale = 1.0 / Float(Int16.max)
|
|
return Float(rawAxis(axis)) * axisRescale
|
|
}
|
|
|
|
@inline(__always) func rawAxis(_ axis: Axes) -> Int16
|
|
{
|
|
_axes[Int(axis.sdlEnum.rawValue)]
|
|
}
|
|
|
|
@inline(__always) private func btnState(_ btn: Buttons) -> UInt8
|
|
{
|
|
_btns[Int(btn.sdlEnum.rawValue)]
|
|
}
|
|
|
|
private let _btns: [UInt8], _axes: [Int16]
|
|
|
|
internal init(btns: [UInt8], axes: [Int16])
|
|
{
|
|
self._btns = btns
|
|
self._axes = axes
|
|
}
|
|
}
|
|
|
|
public var state: State
|
|
{
|
|
.init(btns: _btns, axes: _axes)
|
|
}
|
|
|
|
@inline(__always) public static var current: GamePad?
|
|
{
|
|
let input = Input.instance
|
|
return if let id = input.firstPadID { input.getPad(id: id) } else { nil }
|
|
}
|
|
|
|
private static let _UP = UInt8(0b00), _DOWN = UInt8(0b10), _IMPULSE = UInt8(0b01)
|
|
private static let _PRESS = _DOWN | _IMPULSE
|
|
private static let _RELEASE = _UP | _IMPULSE
|
|
|
|
private var _btns = [UInt8](repeating: 0, count: Int(SDL_CONTROLLER_BUTTON_MAX.rawValue))
|
|
private var _axes = [Int16](repeating: 0, count: Int(SDL_CONTROLLER_AXIS_MAX.rawValue))
|
|
private var _sdlPad: OpaquePointer
|
|
|
|
internal init(pad: OpaquePointer)
|
|
{
|
|
self._sdlPad = pad
|
|
}
|
|
|
|
internal func newTick()
|
|
{
|
|
_btns = _btns.map({ $0 & ~Self._IMPULSE })
|
|
}
|
|
|
|
internal func close()
|
|
{
|
|
SDL_GameControllerClose(_sdlPad)
|
|
}
|
|
|
|
internal func buttonPressEvent(_ btn: UInt8)
|
|
{
|
|
_btns[Int(btn)] = Self._PRESS
|
|
}
|
|
|
|
internal func buttonReleaseEvent(_ btn: UInt8)
|
|
{
|
|
_btns[Int(btn)] = Self._RELEASE
|
|
}
|
|
|
|
internal func axisEvent(_ axis: UInt8, _ value: Int16)
|
|
{
|
|
_axes[Int(axis)] = value
|
|
}
|
|
}
|
|
|
|
public extension GamePad.State
|
|
{
|
|
var leftStick: Vec2f { Vec2f(axis(.leftStickX), axis(.leftStickY)) }
|
|
var rightStick: Vec2f { Vec2f(axis(.rightStickX), axis(.rightStickY)) }
|
|
}
|
|
|
|
|
|
internal extension GamePad.Axes
|
|
{
|
|
var sdlEnum: SDL_GameControllerAxis
|
|
{
|
|
switch self
|
|
{
|
|
case .leftStickX: SDL_CONTROLLER_AXIS_LEFTX
|
|
case .leftStickY: SDL_CONTROLLER_AXIS_LEFTY
|
|
case .rightStickX: SDL_CONTROLLER_AXIS_RIGHTX
|
|
case .rightStickY: SDL_CONTROLLER_AXIS_RIGHTY
|
|
case .leftTrigger: SDL_CONTROLLER_AXIS_TRIGGERLEFT
|
|
case .rightTrigger: SDL_CONTROLLER_AXIS_TRIGGERRIGHT
|
|
}
|
|
}
|
|
}
|
|
|
|
internal extension GamePad.Buttons
|
|
{
|
|
var sdlEnum: SDL_GameControllerButton
|
|
{
|
|
switch self
|
|
{
|
|
case .east: SDL_CONTROLLER_BUTTON_B
|
|
case .south: SDL_CONTROLLER_BUTTON_A
|
|
case .west: SDL_CONTROLLER_BUTTON_Y
|
|
case .north: SDL_CONTROLLER_BUTTON_X
|
|
case .start: SDL_CONTROLLER_BUTTON_START
|
|
case .select: SDL_CONTROLLER_BUTTON_BACK
|
|
case .guide: SDL_CONTROLLER_BUTTON_GUIDE
|
|
case .mic: SDL_CONTROLLER_BUTTON_MISC1
|
|
case .touchPad: SDL_CONTROLLER_BUTTON_TOUCHPAD
|
|
case .leftStick: SDL_CONTROLLER_BUTTON_LEFTSTICK
|
|
case .rightStick: SDL_CONTROLLER_BUTTON_RIGHTSTICK
|
|
case .leftBumper: SDL_CONTROLLER_BUTTON_LEFTSHOULDER
|
|
case .rightBumper: SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
|
|
case .dpadUp: SDL_CONTROLLER_BUTTON_DPAD_UP
|
|
case .dpadDown: SDL_CONTROLLER_BUTTON_DPAD_DOWN
|
|
case .dpadLeft: SDL_CONTROLLER_BUTTON_DPAD_LEFT
|
|
case .dpadRight: SDL_CONTROLLER_BUTTON_DPAD_RIGHT
|
|
case .paddle1: SDL_CONTROLLER_BUTTON_PADDLE1
|
|
case .paddle2: SDL_CONTROLLER_BUTTON_PADDLE2
|
|
case .paddle3: SDL_CONTROLLER_BUTTON_PADDLE3
|
|
case .paddle4: SDL_CONTROLLER_BUTTON_PADDLE4
|
|
}
|
|
}
|
|
}
|