internal/gamepad: implement gamepad detection callbacks for Xbox

Updates #2084
This commit is contained in:
Hajime Hoshi 2022-06-29 00:10:27 +09:00
parent 8cb023e3c8
commit 97039ff714
2 changed files with 151 additions and 1 deletions

View File

@ -19,6 +19,8 @@ package gamepad
import (
"fmt"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
@ -30,6 +32,53 @@ var (
procGameInputCreate = gameInput.NewProc("GameInputCreate")
)
type _GameInputEnumerationKind int32
const (
_GameInputNoEnumeration _GameInputEnumerationKind = 0
_GameInputAsyncEnumeration _GameInputEnumerationKind = 1
_GameInputBlockingEnumeration _GameInputEnumerationKind = 2
)
type _GameInputCallbackToken uint64
type _GameInputDeviceStatus int32
const (
_GameInputDeviceNoStatus _GameInputDeviceStatus = 0x00000000
_GameInputDeviceConnected _GameInputDeviceStatus = 0x00000001
_GameInputDeviceInputEnabled _GameInputDeviceStatus = 0x00000002
_GameInputDeviceOutputEnabled _GameInputDeviceStatus = 0x00000004
_GameInputDeviceRawIoEnabled _GameInputDeviceStatus = 0x00000008
_GameInputDeviceAudioCapture _GameInputDeviceStatus = 0x00000010
_GameInputDeviceAudioRender _GameInputDeviceStatus = 0x00000020
_GameInputDeviceSynchronized _GameInputDeviceStatus = 0x00000040
_GameInputDeviceWireless _GameInputDeviceStatus = 0x00000080
_GameInputDeviceUserIdle _GameInputDeviceStatus = 0x00100000
_GameInputDeviceAnyStatus _GameInputDeviceStatus = 0x00FFFFFF
)
type _GameInputKind int32
const (
_GameInputKindUnknown _GameInputKind = 0x00000000
_GameInputKindRawDeviceReport _GameInputKind = 0x00000001
_GameInputKindControllerAxis _GameInputKind = 0x00000002
_GameInputKindControllerButton _GameInputKind = 0x00000004
_GameInputKindControllerSwitch _GameInputKind = 0x00000008
_GameInputKindController _GameInputKind = 0x0000000E
_GameInputKindKeyboard _GameInputKind = 0x00000010
_GameInputKindMouse _GameInputKind = 0x00000020
_GameInputKindTouch _GameInputKind = 0x00000100
_GameInputKindMotion _GameInputKind = 0x00001000
_GameInputKindArcadeStick _GameInputKind = 0x00010000
_GameInputKindFlightStick _GameInputKind = 0x00020000
_GameInputKindGamepad _GameInputKind = 0x00040000
_GameInputKindRacingWheel _GameInputKind = 0x00080000
_GameInputKindUiNavigation _GameInputKind = 0x01000000
_GameInputKindAny _GameInputKind = 0x0FFFFFFF
)
func _GameInputCreate() (*_IGameInput, error) {
var gameInput *_IGameInput
r, _, _ := procGameInputCreate.Call(uintptr(unsafe.Pointer(&gameInput)))
@ -47,4 +96,72 @@ type _IGameInput_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetCurrentTimestamp uintptr
GetCurrentReading uintptr
GetNextReading uintptr
GetPreviousReading uintptr
GetTemporalReading uintptr
RegisterReadingCallback uintptr
RegisterDeviceCallback uintptr
RegisterGuideButtonCallback uintptr
RegisterKeyboardLayoutCallback uintptr
StopCallback uintptr
UnregisterCallback uintptr
CreateDispatcher uintptr
CreateAggregateDevice uintptr
FindDeviceFromId uintptr
FindDeviceFromObject uintptr
FindDeviceFromPlatformHandle uintptr
FindDeviceFromPlatformString uintptr
EnableOemDeviceSupport uintptr
SetFocusPolicy uintptr
}
func (i *_IGameInput) RegisterDeviceCallback(device *_IGameInputDevice,
inputKind _GameInputKind,
statusFilter _GameInputDeviceStatus,
enumerationKind _GameInputEnumerationKind,
context unsafe.Pointer,
callbackFunc uintptr,
callbackToken *_GameInputCallbackToken) error {
r, _, _ := syscall.Syscall9(i.vtbl.RegisterDeviceCallback, 8, uintptr(unsafe.Pointer(i)),
uintptr(unsafe.Pointer(device)), uintptr(inputKind), uintptr(statusFilter),
uintptr(enumerationKind), uintptr(context), callbackFunc,
uintptr(unsafe.Pointer(callbackToken)), 0)
runtime.KeepAlive(device)
runtime.KeepAlive(callbackToken)
if uint32(r) != uint32(windows.S_OK) {
return fmt.Errorf("gamepad: IGameInput::RegisterDeviceCallback failed: HRESULT(%d)", uint32(r))
}
return nil
}
type _IGameInputDevice struct {
vtbl *_IGameInputDevice_Vtbl
}
type _IGameInputDevice_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetDeviceInfo uintptr
GetDeviceStatus uintptr
GetBatteryState uintptr
CreateForceFeedbackEffect uintptr
IsForceFeedbackMotorPoweredOn uintptr
SetForceFeedbackMotorGain uintptr
SetHapticMotorState uintptr
SetRumbleState uintptr
SetInputSynchronizationState uintptr
SendInputSynchronizationHint uintptr
PowerOff uintptr
CreateRawDeviceReport uintptr
GetRawDeviceFeature uintptr
SetRawDeviceFeature uintptr
SendRawDeviceOutput uintptr
ExecuteRawDeviceIoControl uintptr
AcquireExclusiveRawDeviceAccess uintptr
ReleaseExclusiveRawDeviceAccess uintptr
}

View File

@ -17,8 +17,27 @@
package gamepad
import (
"unsafe"
"golang.org/x/sys/windows"
)
type nativeGamepadsXbox struct {
gameInput *_IGameInput
gameInput *_IGameInput
deviceCallbackPtr uintptr
token _GameInputCallbackToken
}
func xboxDeviceCallback(
callbackToken _GameInputCallbackToken,
context unsafe.Pointer,
device *_IGameInputDevice,
timestamp uint64,
currentStatus _GameInputDeviceStatus,
previousStatus _GameInputDeviceStatus) uintptr {
// TODO: Implement this.
return 0
}
func (n *nativeGamepadsXbox) init(gamepads *gamepads) error {
@ -26,7 +45,21 @@ func (n *nativeGamepadsXbox) init(gamepads *gamepads) error {
if err != nil {
return err
}
n.gameInput = g
n.deviceCallbackPtr = windows.NewCallbackCDecl(xboxDeviceCallback)
if err := n.gameInput.RegisterDeviceCallback(
nil,
_GameInputKindGamepad,
_GameInputDeviceConnected,
_GameInputBlockingEnumeration,
nil,
n.deviceCallbackPtr,
&n.token,
); err != nil {
return err
}
return nil
}