Finish input handling and revamp it
This commit is contained in:
parent
1b0945fed8
commit
959d85b2fb
1 changed files with 225 additions and 85 deletions
|
|
@ -22,7 +22,11 @@ export JOYSTICK_MAX, JOYSTICK_MIN
|
||||||
type
|
type
|
||||||
InputError* = object of Exception
|
InputError* = object of Exception
|
||||||
ControllerSelectError* = object of InputError
|
ControllerSelectError* = object of InputError
|
||||||
|
VibrationError* = object of InputError
|
||||||
|
VibrationInitError* = object of InputError
|
||||||
|
ControllerMergeError* = object of InputError
|
||||||
|
|
||||||
|
####################### Shared memory data ################################
|
||||||
TouchScreenHeader* = ref object
|
TouchScreenHeader* = ref object
|
||||||
timestampTicks*: uint64
|
timestampTicks*: uint64
|
||||||
numEntries*: uint64
|
numEntries*: uint64
|
||||||
|
|
@ -150,65 +154,84 @@ type
|
||||||
controllerSerials*: Buffer[uint8]
|
controllerSerials*: Buffer[uint8]
|
||||||
controllers*: Buffer[ControllerSection]
|
controllers*: Buffer[ControllerSection]
|
||||||
|
|
||||||
VibrationDeviceInfo* = ref object
|
####################### END Shared memory data ################################
|
||||||
unk_x0*: uint32
|
|
||||||
unk_x4*: uint32 ## /< 0x1 for left-joycon, 0x2 for right-joycon.
|
|
||||||
|
|
||||||
VibrationValue* = ref object
|
VibrationDeviceInfo* = HidVibrationDeviceInfo
|
||||||
ampLow*: float ## /< Low Band amplitude. 1.0f: Max amplitude.
|
|
||||||
freqLow*: float ## /< Low Band frequency in Hz.
|
VibrationValue* = HidVibrationValue
|
||||||
ampHigh*: float ## /< High Band amplitude. 1.0f: Max amplitude.
|
|
||||||
freqHigh*: float ## /< High Band frequency in Hz.
|
VibrationDevice* = uint32
|
||||||
|
|
||||||
|
JoyconMode {.pure.} = enum
|
||||||
|
Single, Dual
|
||||||
|
|
||||||
|
|
||||||
proc init*(): Result = hidInitialize().newResult
|
proc init*(): Result = hidInitialize().newResult
|
||||||
proc exit*() = hidExit()
|
proc exit*() = hidExit()
|
||||||
proc reset*() = hidReset()
|
proc reset*() = hidReset()
|
||||||
|
|
||||||
|
|
||||||
proc getSessionService*(): Service =
|
proc getSessionService*(): Service =
|
||||||
newService(hidGetSessionService()[])
|
newService(hidGetSessionService()[])
|
||||||
|
|
||||||
|
|
||||||
proc getSharedMemory*(): ptr HidSharedMemory =
|
proc getSharedMemory*(): ptr HidSharedMemory =
|
||||||
result = cast[ptr HidSharedMemory](hidGetSharedMemAddr())
|
result = cast[ptr HidSharedMemory](hidGetSharedMemAddr())
|
||||||
|
|
||||||
proc setControllerLayout*(id: Controller, layoutType: ControllerLayoutType) =
|
|
||||||
hidSetControllerLayout(HidControllerID(id), HidControllerLayoutType(layoutType))
|
|
||||||
|
|
||||||
proc getControllerLayout*(id: Controller): ControllerLayoutType =
|
proc `layout=`*(controller: Controller, layoutType: ControllerLayoutType) =
|
||||||
hidGetControllerLayout(HidControllerID(id)).ControllerLayoutType
|
hidSetControllerLayout(
|
||||||
|
HidControllerID(controller),
|
||||||
|
HidControllerLayoutType(layoutType)
|
||||||
|
)
|
||||||
|
|
||||||
proc scanInput*() = hidScanInput()
|
|
||||||
|
|
||||||
proc keysHeld*(id: Controller): HashSet[ControllerKey] =
|
proc layout*(controller: Controller): ControllerLayoutType =
|
||||||
|
hidGetControllerLayout(HidControllerID(controller)).ControllerLayoutType
|
||||||
|
|
||||||
|
|
||||||
|
proc scanInput*() =
|
||||||
|
## Call this once per frame to make the rest of the procs
|
||||||
|
## in here poll controller data
|
||||||
|
hidScanInput()
|
||||||
|
|
||||||
|
|
||||||
|
proc keysHeld*(controller: Controller): HashSet[ControllerKey] =
|
||||||
|
## Gets the keys held by the `controller`
|
||||||
result = initSet[ControllerKey]()
|
result = initSet[ControllerKey]()
|
||||||
|
|
||||||
var raw = hidKeysHeld(HidControllerID(id))
|
var raw = hidKeysHeld(HidControllerID(controller))
|
||||||
for i in 0 ..< ControllerKey.size:
|
for i in 0 ..< ControllerKey.size:
|
||||||
let bit = raw and 0x1
|
let bit = raw and 0x1
|
||||||
if bit == 1:
|
if bit == 1:
|
||||||
result.incl(ControllerKey(BIT(i)))
|
result.incl(ControllerKey(BIT(i)))
|
||||||
raw = raw shr 1
|
raw = raw shr 1
|
||||||
|
|
||||||
proc keysDown*(id: Controller): HashSet[ControllerKey] =
|
|
||||||
|
proc keysDown*(controller: Controller): HashSet[ControllerKey] =
|
||||||
|
## Gets the keys that are pressed at the moment by the `controller`
|
||||||
result = initSet[ControllerKey]()
|
result = initSet[ControllerKey]()
|
||||||
|
|
||||||
var raw = hidKeysDown(HidControllerID(id))
|
var raw = hidKeysDown(HidControllerID(controller))
|
||||||
for i in 0 ..< ControllerKey.size:
|
for i in 0 ..< ControllerKey.size:
|
||||||
let bit = raw and 0x1
|
let bit = raw and 0x1
|
||||||
if bit == 1:
|
if bit == 1:
|
||||||
result.incl(ControllerKey(BIT(i)))
|
result.incl(ControllerKey(BIT(i)))
|
||||||
raw = raw shr 1
|
raw = raw shr 1
|
||||||
|
|
||||||
proc keysUp*(id: Controller): HashSet[ControllerKey] =
|
|
||||||
|
proc keysUp*(controller: Controller): HashSet[ControllerKey] =
|
||||||
|
## Gets the keys that are not pressed at the moment by the `controller`
|
||||||
result = initSet[ControllerKey]()
|
result = initSet[ControllerKey]()
|
||||||
|
|
||||||
var raw = hidKeysUp(HidControllerID(id))
|
var raw = hidKeysUp(HidControllerID(controller))
|
||||||
for i in 0 ..< ControllerKey.size:
|
for i in 0 ..< ControllerKey.size:
|
||||||
let bit = raw and 0x1
|
let bit = raw and 0x1
|
||||||
if bit == 1:
|
if bit == 1:
|
||||||
result.incl(ControllerKey(BIT(i)))
|
result.incl(ControllerKey(BIT(i)))
|
||||||
raw = raw shr 1
|
raw = raw shr 1
|
||||||
|
|
||||||
|
|
||||||
proc mouseButtonsHeld*(): HashSet[MouseButton] =
|
proc mouseButtonsHeld*(): HashSet[MouseButton] =
|
||||||
result = initSet[MouseButton]()
|
result = initSet[MouseButton]()
|
||||||
|
|
||||||
|
|
@ -240,107 +263,224 @@ proc mouseButtonsUp*(): HashSet[MouseButton] =
|
||||||
result.incl(MouseButton(BIT(i)))
|
result.incl(MouseButton(BIT(i)))
|
||||||
raw = raw shr 1
|
raw = raw shr 1
|
||||||
|
|
||||||
proc mouseRead*(): MousePosition =
|
|
||||||
var pos: ptr MousePosition
|
proc readMouse*(): MousePosition =
|
||||||
hidMouseRead(pos)
|
hidMouseRead(result.addr)
|
||||||
result = pos[]
|
|
||||||
|
|
||||||
proc keyboardModifierHeld*(modifier: KeyboardModifier): bool =
|
proc keyboardModifierHeld*(modifier: KeyboardModifier): bool =
|
||||||
hidKeyboardModifierHeld(modifier.HidKeyboardModifier)
|
hidKeyboardModifierHeld(modifier.HidKeyboardModifier)
|
||||||
|
|
||||||
|
|
||||||
proc keyboardModifierDown*(modifier: KeyboardModifier): bool =
|
proc keyboardModifierDown*(modifier: KeyboardModifier): bool =
|
||||||
hidKeyboardModifierDown(modifier.HidKeyboardModifier)
|
hidKeyboardModifierDown(modifier.HidKeyboardModifier)
|
||||||
|
|
||||||
|
|
||||||
proc keyboardModifierUp*(modifier: KeyboardModifier): bool =
|
proc keyboardModifierUp*(modifier: KeyboardModifier): bool =
|
||||||
hidKeyboardModifierUp(modifier.HidKeyboardModifier)
|
hidKeyboardModifierUp(modifier.HidKeyboardModifier)
|
||||||
|
|
||||||
|
|
||||||
proc keyboardHeld*(key: KeyboardKey): bool =
|
proc keyboardHeld*(key: KeyboardKey): bool =
|
||||||
hidKeyboardHeld(key.HidKeyboardScancode)
|
hidKeyboardHeld(key.HidKeyboardScancode)
|
||||||
|
|
||||||
|
|
||||||
proc keyboardDown*(key: KeyboardKey): bool =
|
proc keyboardDown*(key: KeyboardKey): bool =
|
||||||
hidKeyboardDown(key.HidKeyboardScancode)
|
hidKeyboardDown(key.HidKeyboardScancode)
|
||||||
|
|
||||||
|
|
||||||
proc keyboardUp*(key: KeyboardKey): bool =
|
proc keyboardUp*(key: KeyboardKey): bool =
|
||||||
hidKeyboardUp(key.HidKeyboardScancode)
|
hidKeyboardUp(key.HidKeyboardScancode)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyboardKeysDown*(): HashSet[KeyboardKey] =
|
||||||
|
## Get all keyboard keys currently down, excluding modifiers
|
||||||
|
result = initSet[KeyboardKey]()
|
||||||
|
|
||||||
|
for i in KeyboardKey.low..KeyboardKey.high:
|
||||||
|
let key = KeyboardKey(i)
|
||||||
|
if keyboardDown(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyboardKeysUp*(): HashSet[KeyboardKey] =
|
||||||
|
## Get all keyboard keys currently up, excluding modifiers
|
||||||
|
result = initSet[KeyboardKey]()
|
||||||
|
|
||||||
|
for i in KeyboardKey.low..KeyboardKey.high:
|
||||||
|
let key = KeyboardKey(i)
|
||||||
|
if keyboardUp(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyboardKeysHeld*(): HashSet[KeyboardKey] =
|
||||||
|
## Get all keyboard keys currently held, excluding modifiers
|
||||||
|
result = initSet[KeyboardKey]()
|
||||||
|
|
||||||
|
for i in KeyboardKey.low..KeyboardKey.high:
|
||||||
|
let key = KeyboardKey(i)
|
||||||
|
if keyboardHeld(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyboardModifiersHeld*(): HashSet[KeyboardModifier] =
|
||||||
|
## Get all keyboard modifiers currently held
|
||||||
|
result = initSet[KeyboardModifier]()
|
||||||
|
|
||||||
|
for i in 0..KeyboardModifier.size:
|
||||||
|
let key = KeyboardModifier(BIT(i))
|
||||||
|
if keyboardModifierHeld(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyboardModifiersDown*(): HashSet[KeyboardModifier] =
|
||||||
|
## Get all keyboard modifiers currently down
|
||||||
|
result = initSet[KeyboardModifier]()
|
||||||
|
|
||||||
|
for i in 0..KeyboardModifier.size:
|
||||||
|
let key = KeyboardModifier(BIT(i))
|
||||||
|
if keyboardModifierDown(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
proc keyboardModifiersUp*(): HashSet[KeyboardModifier] =
|
||||||
|
## Get all keyboard modifiers currently up
|
||||||
|
result = initSet[KeyboardModifier]()
|
||||||
|
|
||||||
|
for i in 0..KeyboardModifier.size:
|
||||||
|
let key = KeyboardModifier(BIT(i))
|
||||||
|
if keyboardModifierUp(key):
|
||||||
|
result.incl(key)
|
||||||
|
|
||||||
|
|
||||||
proc touchCount*(): uint32 =
|
proc touchCount*(): uint32 =
|
||||||
hidTouchCount()
|
hidTouchCount()
|
||||||
|
|
||||||
proc touchRead*(pointId: uint32): TouchPosition =
|
|
||||||
var touch: ptr TouchPosition
|
|
||||||
hidTouchRead(touch, pointId)
|
|
||||||
result = touch[]
|
|
||||||
|
|
||||||
proc joystickRead*(id: Controller, stick: ControllerJoystick): JoystickPosition =
|
proc readTouch*(pointId: uint32): TouchPosition =
|
||||||
var pos: ptr JoystickPosition
|
hidTouchRead(result.addr, pointId)
|
||||||
hidJoystickRead(pos, id.HidControllerID, stick.HidControllerJoystick)
|
|
||||||
result = pos[]
|
|
||||||
|
|
||||||
## / This can be used to check what CONTROLLER_P1_AUTO uses.
|
|
||||||
## / Returns 0 when CONTROLLER_PLAYER_1 is connected, otherwise returns 1 for
|
proc readJoystick*(id: Controller, stick: ControllerJoystick): JoystickPosition =
|
||||||
## handheld-mode.
|
hidJoystickRead(result.addr, id.HidControllerID, stick.HidControllerJoystick)
|
||||||
proc getHandheldMode*(): bool =
|
|
||||||
|
|
||||||
|
proc isHandheldMode*(): bool =
|
||||||
|
## / This can be used to check what CONTROLLER_P1_AUTO uses.
|
||||||
|
## / Returns 0 when CONTROLLER_PLAYER_1 is connected, otherwise returns 1 for
|
||||||
|
## handheld-mode.
|
||||||
hidGetHandheldMode()
|
hidGetHandheldMode()
|
||||||
|
|
||||||
## / Use this if you want to use a single joy-con as a dedicated CONTROLLER_PLAYER_*.
|
|
||||||
## / When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1
|
proc `joyconMode=`*(id: Controller, mode: JoyconMode) =
|
||||||
## and CONTROLLER_PLAYER_2 for example).
|
## Sets the joycon mode to either single or dual
|
||||||
## / id must be CONTROLLER_PLAYER_*.
|
|
||||||
proc setJoyConModeSingle*(id: Controller): Result =
|
|
||||||
if id notin {Controller.Player1 .. Controller.Player8}:
|
if id notin {Controller.Player1 .. Controller.Player8}:
|
||||||
raiseEx(ControllerSelectError, "Must be controller 1-8")
|
raiseEx(ControllerSelectError, "Must be controller 1-8")
|
||||||
hidSetNpadJoyAssignmentModeSingleByDefault(id.HidControllerId).newResult
|
|
||||||
|
|
||||||
## / Use this if you want to use a pair of joy-cons as a single CONTROLLER_PLAYER_*.
|
var rc: Result
|
||||||
## Only necessary if you want to use this mode in your application after \ref
|
|
||||||
## hidSetNpadJoyAssignmentModeSingleByDefault was used with this pair of joy-cons.
|
|
||||||
## / Used automatically during app startup/exit for all controllers.
|
|
||||||
## / When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1
|
|
||||||
## and CONTROLLER_PLAYER_2 for example).
|
|
||||||
## / id must be CONTROLLER_PLAYER_*.
|
|
||||||
proc setJoyconModeDual*(id: Controller): Result =
|
|
||||||
if id notin {Controller.Player1 .. Controller.Player8}:
|
|
||||||
raiseEx(ControllerSelectError, "Must be controller 1-8")
|
|
||||||
hidSetNpadJoyAssignmentModeDual(id.HidControllerId).newResult
|
|
||||||
|
|
||||||
## / Merge two single joy-cons into a dual-mode controller. Use this after \ref
|
case mode:
|
||||||
## hidSetNpadJoyAssignmentModeDual, when \ref hidSetNpadJoyAssignmentModeSingleByDefault
|
of JoyconMode.Single:
|
||||||
## was previously used (this includes using this manually at application exit).
|
rc = hidSetNpadJoyAssignmentModeSingleByDefault(id.HidControllerId).newResult
|
||||||
proc mergeSingleJoyAsDualJoy*(id1: Controller; id2: Controller): Result =
|
of JoyconMode.Dual:
|
||||||
hidMergeSingleJoyAsDualJoy(id1.HidControllerID, id2.HidControllerId).newResult
|
rc = hidSetNpadJoyAssignmentModeDual(id.HidControllerId).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(ControllerMergeError, "Could not set joycon mode to " & $mode, rc)
|
||||||
|
|
||||||
|
|
||||||
proc initializeVibrationDevices*(VibrationDeviceHandles: ptr uint32;
|
proc mergeJoycons*(id1: Controller; id2: Controller) =
|
||||||
total_handles: csize; id: HidControllerID;
|
## / Merge two single joy-cons into a dual-mode controller. Use this after \ref
|
||||||
`type`: HidControllerType): Result =
|
## hidSetNpadJoyAssignmentModeDual, when \ref hidSetNpadJoyAssignmentModeSingleByDefault
|
||||||
discard
|
## was previously used (this includes using this manually at application exit).
|
||||||
|
let rc = hidMergeSingleJoyAsDualJoy(
|
||||||
|
id1.HidControllerID,
|
||||||
|
id2.HidControllerID
|
||||||
|
).newResult
|
||||||
|
|
||||||
## / Gets HidVibrationDeviceInfo for the specified VibrationDeviceHandle.
|
if rc.failed:
|
||||||
proc getVibrationDeviceInfo*(VibrationDeviceHandle: ptr uint32;
|
raiseEx(ControllerMergeError, "Could not merge joycons", rc)
|
||||||
VibrationDeviceInfo: ptr HidVibrationDeviceInfo): Result =
|
|
||||||
newResult(0)
|
|
||||||
|
|
||||||
## / Send the VibrationValue to the specified VibrationDeviceHandle.
|
|
||||||
proc sendVibrationValue*(VibrationDeviceHandle: ptr uint32;
|
|
||||||
VibrationValue: ptr HidVibrationValue): Result =
|
|
||||||
discard
|
|
||||||
|
|
||||||
## / Gets the current HidVibrationValue for the specified VibrationDeviceHandle.
|
proc initializeVibrationDevices*(
|
||||||
proc getActualVibrationValue*(VibrationDeviceHandle: ptr uint32;
|
controller: Controller,
|
||||||
VibrationValue: ptr HidVibrationValue): Result =
|
controllerTypes: openArray[ControllerType]
|
||||||
discard
|
): seq[VibrationDevice] =
|
||||||
|
result = @[]
|
||||||
|
|
||||||
## / Sets whether vibration is allowed, this also affects the config displayed by
|
for ctype in controllerTypes:
|
||||||
## System Settings.
|
var devs: array[2, VibrationDevice]
|
||||||
proc permitVibration*(flag: bool): Result =
|
var numDevices = 2
|
||||||
discard
|
|
||||||
|
|
||||||
## / Gets whether vibration is allowed.
|
if ctype == ControllerType.JoyconLeft or ctype == ControllerType.JoyconRight:
|
||||||
proc isVibrationPermitted*(flag: ptr bool): Result =
|
numDevices = 1
|
||||||
discard
|
|
||||||
|
|
||||||
## / Send VibrationValues[index] to VibrationDeviceHandles[index], where count is the
|
let rc = hidInitializeVibrationDevices(
|
||||||
## number of entries in the VibrationDeviceHandles/VibrationValues arrays.
|
devs[0].addr, numDevices, HidControllerID(controller),
|
||||||
proc sendVibrationValues*(VibrationDeviceHandles: ptr uint32;
|
HidControllerType(ctype)
|
||||||
VibrationValues: ptr HidVibrationValue; count: csize): Result =
|
).newResult
|
||||||
discard
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(
|
||||||
|
VibrationInitError,
|
||||||
|
"Could not init vibration for controller #$ with type #$" %
|
||||||
|
[$controller, $ctype]
|
||||||
|
)
|
||||||
|
for i in 0 ..< numDevices:
|
||||||
|
result.add(devs[i])
|
||||||
|
|
||||||
|
|
||||||
|
proc info*(device: VibrationDevice): VibrationDeviceInfo =
|
||||||
|
## / Gets HidVibrationDeviceInfo for the specified VibrationDeviceHandle.
|
||||||
|
let rc = hidGetVibrationDeviceInfo(device.unsafeAddr, result.addr).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Could not get vibration device info", rc)
|
||||||
|
|
||||||
|
proc `vibration=`*(device: VibrationDevice, value: VibrationValue) =
|
||||||
|
## / Send the value to the specified handle.
|
||||||
|
let rc = hidSendVibrationValue(device.unsafeAddr, value.unsafeAddr).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Could not send vibration value", rc)
|
||||||
|
|
||||||
|
proc vibration*(device: VibrationDevice): VibrationValue =
|
||||||
|
## / Gets the current HidVibrationValue for the specified VibrationDeviceHandle.
|
||||||
|
let rc = hidGetActualVibrationValue(device.unsafeAddr, result.addr).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Could not get vibration value", rc)
|
||||||
|
|
||||||
|
proc permitVibration*(flag: bool) =
|
||||||
|
## / Sets whether vibration is allowed, this also affects the config displayed by
|
||||||
|
## System Settings.
|
||||||
|
let rc = hidPermitVibration(flag).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Unable to permit vibration", rc)
|
||||||
|
|
||||||
|
proc isVibrationPermitted*(): bool =
|
||||||
|
## / Gets whether vibration is allowed.
|
||||||
|
let rc = hidIsVibrationPermitted(result.addr).newResult
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Error getting vibration information", rc)
|
||||||
|
|
||||||
|
proc sendVibrationValues*(
|
||||||
|
devices: openArray[VibrationDevice],
|
||||||
|
values: openArray[VibrationValue]) =
|
||||||
|
## / Send VibrationValues[index] to VibrationDeviceHandles[index], where count is the
|
||||||
|
## number of entries in the VibrationDeviceHandles/VibrationValues arrays.
|
||||||
|
let sizeH = len(devices)
|
||||||
|
let sizeV = len(values)
|
||||||
|
|
||||||
|
if sizeH != sizeV:
|
||||||
|
raiseEx(
|
||||||
|
VibrationError,
|
||||||
|
"Vibration arrays must be the same size. handles $# != values $#" %
|
||||||
|
[$sizeH, $sizeV]
|
||||||
|
)
|
||||||
|
|
||||||
|
let rc = hidSendVibrationValues(
|
||||||
|
devices[0].unsafeAddr, values[0].unsafeAddr, sizeH
|
||||||
|
).newResult
|
||||||
|
|
||||||
|
if rc.failed:
|
||||||
|
raiseEx(VibrationError, "Unable to send vibration error", rc)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue