From 847c4f067aebffd619c9fdbd18b99df01e07b8dc Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 24 Jun 2022 20:03:56 +0900 Subject: [PATCH] internal/gamepad: make nativeGamepad(s) interfaces This is a preparation to switch the gamepad implementation for Xbox. Updates #2084 --- internal/gamepad/api_ios.go | 22 +++---- internal/gamepad/extern_android.go | 35 ++++++----- internal/gamepad/gamepad.go | 24 +++++++- internal/gamepad/gamepad_android.go | 32 +++++----- internal/gamepad/gamepad_cbackend.go | 55 +++++++++-------- internal/gamepad/gamepad_darwin.go | 90 +++++++++++++++------------- internal/gamepad/gamepad_ios.go | 32 +++++----- internal/gamepad/gamepad_js.go | 44 ++++++++------ internal/gamepad/gamepad_linux.go | 73 ++++++++++++---------- internal/gamepad/gamepad_windows.go | 77 +++++++++++++----------- 10 files changed, 279 insertions(+), 205 deletions(-) diff --git a/internal/gamepad/api_ios.go b/internal/gamepad/api_ios.go index 32f8433b2..4fd278271 100644 --- a/internal/gamepad/api_ios.go +++ b/internal/gamepad/api_ios.go @@ -407,14 +407,16 @@ func (g *gamepads) addIOSGamepad(controller C.uintptr_t, prop *C.struct_Controll name := C.GoString(&prop.name[0]) sdlID := C.GoStringN(&prop.guid[0], 16) gp := g.add(name, sdlID) - gp.native.controller = uintptr(controller) - gp.native.axes = make([]float64, prop.nAxes) - gp.native.buttons = make([]bool, prop.nButtons+prop.nHats*4) - gp.native.hats = make([]int, prop.nHats) - gp.native.buttonMask = uint16(prop.buttonMask) - gp.native.hasDualshockTouchpad = bool(prop.hasDualshockTouchpad) - gp.native.hasXboxPaddles = bool(prop.hasXboxPaddles) - gp.native.hasXboxShareButton = bool(prop.hasXboxShareButton) + gp.native = &nativeGamepadImpl{ + controller: uintptr(controller), + axes: make([]float64, prop.nAxes), + buttons: make([]bool, prop.nButtons+prop.nHats*4), + hats: make([]int, prop.nHats), + buttonMask: uint16(prop.buttonMask), + hasDualshockTouchpad: bool(prop.hasDualshockTouchpad), + hasXboxPaddles: bool(prop.hasXboxPaddles), + hasXboxShareButton: bool(prop.hasXboxShareButton), + } } func (g *gamepads) removeIOSGamepad(controller C.uintptr_t) { @@ -422,7 +424,7 @@ func (g *gamepads) removeIOSGamepad(controller C.uintptr_t) { defer g.m.Unlock() g.remove(func(gamepad *Gamepad) bool { - return gamepad.native.controller == uintptr(controller) + return gamepad.native.(*nativeGamepadImpl).controller == uintptr(controller) }) } @@ -430,7 +432,7 @@ func initializeIOSGamepads() { C.initializeGamepads() } -func (g *nativeGamepad) updateIOSGamepad() { +func (g *nativeGamepadImpl) updateIOSGamepad() { var state C.struct_ControllerState C.getControllerState(C.uintptr_t(g.controller), &state, C.uint16_t(g.buttonMask), C.uint8_t(len(g.hats)), C.bool(g.hasDualshockTouchpad), C.bool(g.hasXboxPaddles), C.bool(g.hasXboxShareButton)) diff --git a/internal/gamepad/extern_android.go b/internal/gamepad/extern_android.go index cfd68cc2c..30608e740 100644 --- a/internal/gamepad/extern_android.go +++ b/internal/gamepad/extern_android.go @@ -53,10 +53,12 @@ func (g *gamepads) addAndroidGamepad(androidDeviceID int, name, sdlID string, ax defer g.m.Unlock() gp := g.add(name, sdlID) - gp.native.androidDeviceID = androidDeviceID - gp.native.axes = make([]float64, axisCount) - gp.native.buttons = make([]bool, buttonCount) - gp.native.hats = make([]int, hatCount) + gp.native = &nativeGamepadImpl{ + androidDeviceID: androidDeviceID, + axes: make([]float64, axisCount), + buttons: make([]bool, buttonCount), + hats: make([]int, hatCount), + } } func (g *gamepads) removeAndroidGamepad(androidDeviceID int) { @@ -64,7 +66,7 @@ func (g *gamepads) removeAndroidGamepad(androidDeviceID int) { defer g.m.Unlock() g.remove(func(gamepad *Gamepad) bool { - return gamepad.native.androidDeviceID == androidDeviceID + return gamepad.native.(*nativeGamepadImpl).androidDeviceID == androidDeviceID }) } @@ -73,7 +75,7 @@ func (g *gamepads) updateAndroidGamepadAxis(androidDeviceID int, axis int, value defer g.m.Unlock() gp := g.find(func(gamepad *Gamepad) bool { - return gamepad.native.androidDeviceID == androidDeviceID + return gamepad.native.(*nativeGamepadImpl).androidDeviceID == androidDeviceID }) if gp == nil { return @@ -86,7 +88,7 @@ func (g *gamepads) updateAndroidGamepadButton(androidDeviceID int, button Button defer g.m.Unlock() gp := g.find(func(gamepad *Gamepad) bool { - return gamepad.native.androidDeviceID == androidDeviceID + return gamepad.native.(*nativeGamepadImpl).androidDeviceID == androidDeviceID }) if gp == nil { return @@ -99,7 +101,7 @@ func (g *gamepads) updateAndroidGamepadHat(androidDeviceID int, hat int, dir And defer g.m.Unlock() gp := g.find(func(gamepad *Gamepad) bool { - return gamepad.native.androidDeviceID == androidDeviceID + return gamepad.native.(*nativeGamepadImpl).androidDeviceID == androidDeviceID }) if gp == nil { return @@ -111,30 +113,33 @@ func (g *Gamepad) updateAndroidGamepadAxis(axis int, value float64) { g.m.Lock() defer g.m.Unlock() - if axis < 0 || axis >= len(g.native.axes) { + n := g.native.(*nativeGamepadImpl) + if axis < 0 || axis >= len(n.axes) { return } - g.native.axes[axis] = value + n.axes[axis] = value } func (g *Gamepad) updateAndroidGamepadButton(button Button, pressed bool) { g.m.Lock() defer g.m.Unlock() - if button < 0 || int(button) >= len(g.native.buttons) { + n := g.native.(*nativeGamepadImpl) + if button < 0 || int(button) >= len(n.buttons) { return } - g.native.buttons[button] = pressed + n.buttons[button] = pressed } func (g *Gamepad) updateAndroidGamepadHat(hat int, dir AndroidHatDirection, value int) { g.m.Lock() defer g.m.Unlock() - if hat < 0 || hat >= len(g.native.hats) { + n := g.native.(*nativeGamepadImpl) + if hat < 0 || hat >= len(n.hats) { return } - v := g.native.hats[hat] + v := n.hats[hat] switch dir { case AndroidHatDirectionX: switch { @@ -161,5 +166,5 @@ func (g *Gamepad) updateAndroidGamepadHat(hat int, dir AndroidHatDirection, valu default: panic(fmt.Sprintf("gamepad: invalid direction: %d", dir)) } - g.native.hats[hat] = v + n.hats[hat] = v } diff --git a/internal/gamepad/gamepad.go b/internal/gamepad/gamepad.go index fccfce655..f71d3c30e 100644 --- a/internal/gamepad/gamepad.go +++ b/internal/gamepad/gamepad.go @@ -43,7 +43,14 @@ type gamepads struct { native nativeGamepads } -var theGamepads gamepads +type nativeGamepads interface { + init(gamepads *gamepads) error + update(gamepads *gamepads) error +} + +var theGamepads = gamepads{ + native: newNativeGamepadsImpl(), +} // AppendGamepadIDs is concurrent-safe. func AppendGamepadIDs(ids []ID) []ID { @@ -166,7 +173,7 @@ func (g *gamepads) setNativeWindow(nativeWindow uintptr) { g.m.Lock() defer g.m.Unlock() - var n interface{} = &g.native + var n interface{} = g.native if n, ok := n.(interface{ setNativeWindow(uintptr) }); ok { n.setNativeWindow(nativeWindow) } @@ -180,6 +187,19 @@ type Gamepad struct { native nativeGamepad } +type nativeGamepad interface { + update(gamepads *gamepads) error + hasOwnStandardLayoutMapping() bool + axisCount() int + buttonCount() int + hatCount() int + axisValue(axis int) float64 + buttonValue(button int) float64 + isButtonPressed(button int) bool + hatState(hat int) int + vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) +} + func (g *Gamepad) update(gamepads *gamepads) error { g.m.Lock() defer g.m.Unlock() diff --git a/internal/gamepad/gamepad_android.go b/internal/gamepad/gamepad_android.go index 3fef5946e..3cf0bfd68 100644 --- a/internal/gamepad/gamepad_android.go +++ b/internal/gamepad/gamepad_android.go @@ -21,17 +21,21 @@ import ( "time" ) -type nativeGamepads struct{} +type nativeGamepadsImpl struct{} -func (*nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (*nativeGamepadsImpl) init(gamepads *gamepads) error { return nil } -func (*nativeGamepads) update(gamepads *gamepads) error { +func (*nativeGamepadsImpl) update(gamepads *gamepads) error { return nil } -type nativeGamepad struct { +type nativeGamepadImpl struct { androidDeviceID int axes []float64 @@ -39,52 +43,52 @@ type nativeGamepad struct { hats []int } -func (*nativeGamepad) update(gamepad *gamepads) error { +func (*nativeGamepadImpl) update(gamepad *gamepads) error { // Do nothing. The state of gamepads are given via APIs in extern_android.go. return nil } -func (*nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return false } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return len(g.axes) } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return len(g.buttons) } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return len(g.hats) } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if axis < 0 || axis >= len(g.axes) { return 0 } return g.axes[axis] } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if button < 0 || button >= len(g.buttons) { return false } return g.buttons[button] } -func (*nativeGamepad) buttonValue(button int) float64 { +func (*nativeGamepadImpl) buttonValue(button int) float64 { panic("gamepad: buttonValue is not implemented") } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { if hat < 0 || hat >= len(g.hats) { return 0 } return g.hats[hat] } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // TODO: Implement this (#1452) } diff --git a/internal/gamepad/gamepad_cbackend.go b/internal/gamepad/gamepad_cbackend.go index 4d1514bf7..cad389dd2 100644 --- a/internal/gamepad/gamepad_cbackend.go +++ b/internal/gamepad/gamepad_cbackend.go @@ -23,16 +23,20 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/cbackend" ) -type nativeGamepads struct { +type nativeGamepadsImpl struct { gamepads []cbackend.Gamepad ids map[int]struct{} } -func (*nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (*nativeGamepadsImpl) init(gamepads *gamepads) error { return nil } -func (g *nativeGamepads) update(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) update(gamepads *gamepads) error { g.gamepads = g.gamepads[:0] g.gamepads = cbackend.AppendGamepads(g.gamepads) @@ -47,34 +51,37 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { g.ids[gp.ID] = struct{}{} gamepad := gamepads.find(func(gamepad *Gamepad) bool { - return gamepad.native.id == gp.ID + return gamepad.native.(*nativeGamepadImpl).id == gp.ID }) if gamepad == nil { gamepad = gamepads.add("", "") - gamepad.native.id = gp.ID - gamepad.native.standard = gp.Standard - gamepad.native.axisValues = make([]float64, gp.AxisCount) - gamepad.native.buttonPressed = make([]bool, gp.ButtonCount) - gamepad.native.buttonValues = make([]float64, gp.ButtonCount) + gamepad.native = &nativeGamepadImpl{ + id: gp.ID, + standard: gp.Standard, + axisValues: make([]float64, gp.AxisCount), + buttonPressed: make([]bool, gp.ButtonCount), + buttonValues: make([]float64, gp.ButtonCount), + } } gamepad.m.Lock() - copy(gamepad.native.axisValues, gp.AxisValues[:]) - copy(gamepad.native.buttonValues, gp.ButtonValues[:]) - copy(gamepad.native.buttonPressed, gp.ButtonPressed[:]) + n := gamepad.native.(*nativeGamepadImpl) + copy(n.axisValues, gp.AxisValues[:]) + copy(n.buttonValues, gp.ButtonValues[:]) + copy(n.buttonPressed, gp.ButtonPressed[:]) gamepad.m.Unlock() } // Remove an unused gamepads. gamepads.remove(func(gamepad *Gamepad) bool { - _, ok := g.ids[gamepad.native.id] + _, ok := g.ids[gamepad.native.(*nativeGamepadImpl).id] return !ok }) return nil } -type nativeGamepad struct { +type nativeGamepadImpl struct { id int standard bool @@ -83,51 +90,51 @@ type nativeGamepad struct { buttonValues []float64 } -func (*nativeGamepad) update(gamepad *gamepads) error { +func (*nativeGamepadImpl) update(gamepad *gamepads) error { return nil } -func (g *nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return g.standard } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return len(g.axisValues) } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return len(g.buttonValues) } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return 0 } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if axis < 0 || axis >= len(g.axisValues) { return 0 } return g.axisValues[axis] } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if button < 0 || button >= len(g.buttonPressed) { return false } return g.buttonPressed[button] } -func (g *nativeGamepad) buttonValue(button int) float64 { +func (g *nativeGamepadImpl) buttonValue(button int) float64 { if button < 0 || button >= len(g.buttonValues) { return 0 } return g.buttonValues[button] } -func (*nativeGamepad) hatState(hat int) int { +func (*nativeGamepadImpl) hatState(hat int) int { return hatCentered } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { cbackend.VibrateGamepad(g.id, duration, strongMagnitude, weakMagnitude) } diff --git a/internal/gamepad/gamepad_darwin.go b/internal/gamepad/gamepad_darwin.go index 869ca64ea..5b0c13bdd 100644 --- a/internal/gamepad/gamepad_darwin.go +++ b/internal/gamepad/gamepad_darwin.go @@ -59,14 +59,18 @@ import ( // void ebitenGamepadRemovalCallback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef device); import "C" -type nativeGamepads struct { +type nativeGamepadsImpl struct { hidManager C.IOHIDManagerRef devicesToAdd []C.IOHIDDeviceRef devicesToRemove []C.IOHIDDeviceRef devicesM sync.Mutex } -func (g *nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (g *nativeGamepadsImpl) init(gamepads *gamepads) error { var dicts []C.CFDictionaryRef page := C.kHIDPage_GenericDesktop @@ -135,28 +139,31 @@ func (g *nativeGamepads) init(gamepads *gamepads) error { //export ebitenGamepadMatchingCallback func ebitenGamepadMatchingCallback(ctx unsafe.Pointer, res C.IOReturn, sender unsafe.Pointer, device C.IOHIDDeviceRef) { - theGamepads.native.devicesM.Lock() - defer theGamepads.native.devicesM.Unlock() - theGamepads.native.devicesToAdd = append(theGamepads.native.devicesToAdd, device) + n := theGamepads.native.(*nativeGamepadsImpl) + n.devicesM.Lock() + defer n.devicesM.Unlock() + n.devicesToAdd = append(n.devicesToAdd, device) } //export ebitenGamepadRemovalCallback func ebitenGamepadRemovalCallback(ctx unsafe.Pointer, res C.IOReturn, sender unsafe.Pointer, device C.IOHIDDeviceRef) { - theGamepads.native.devicesM.Lock() - defer theGamepads.native.devicesM.Unlock() - theGamepads.native.devicesToRemove = append(theGamepads.native.devicesToRemove, device) + n := theGamepads.native.(*nativeGamepadsImpl) + n.devicesM.Lock() + defer n.devicesM.Unlock() + n.devicesToRemove = append(n.devicesToRemove, device) } -func (g *nativeGamepads) update(gamepads *gamepads) error { - theGamepads.native.devicesM.Lock() - defer theGamepads.native.devicesM.Unlock() +func (g *nativeGamepadsImpl) update(gamepads *gamepads) error { + n := theGamepads.native.(*nativeGamepadsImpl) + n.devicesM.Lock() + defer n.devicesM.Unlock() for _, device := range g.devicesToAdd { g.addDevice(device, gamepads) } for _, device := range g.devicesToRemove { gamepads.remove(func(g *Gamepad) bool { - return g.native.device == device + return g.native.(*nativeGamepadImpl).device == device }) } g.devicesToAdd = g.devicesToAdd[:0] @@ -164,9 +171,9 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { return nil } -func (g *nativeGamepads) addDevice(device C.IOHIDDeviceRef, gamepads *gamepads) { +func (g *nativeGamepadsImpl) addDevice(device C.IOHIDDeviceRef, gamepads *gamepads) { if gamepads.find(func(g *Gamepad) bool { - return g.native.device == device + return g.native.(*nativeGamepadImpl).device == device }) != nil { return } @@ -211,8 +218,11 @@ func (g *nativeGamepads) addDevice(device C.IOHIDDeviceRef, gamepads *gamepads) elements := C.IOHIDDeviceCopyMatchingElements(device, 0, C.kIOHIDOptionsTypeNone) defer C.CFRelease(C.CFTypeRef(elements)) + n := &nativeGamepadImpl{ + device: device, + } gp := gamepads.add(name, sdlID) - gp.native.device = device + gp.native = n for i := C.CFIndex(0); i < C.CFArrayGetCount(elements); i++ { native := (C.IOHIDElementRef)(C.CFArrayGetValueAtIndex(elements, i)) @@ -236,27 +246,27 @@ func (g *nativeGamepads) addDevice(device C.IOHIDDeviceRef, gamepads *gamepads) case C.kHIDUsage_GD_X, C.kHIDUsage_GD_Y, C.kHIDUsage_GD_Z, C.kHIDUsage_GD_Rx, C.kHIDUsage_GD_Ry, C.kHIDUsage_GD_Rz, C.kHIDUsage_GD_Slider, C.kHIDUsage_GD_Dial, C.kHIDUsage_GD_Wheel: - gp.native.axes = append(gp.native.axes, element{ + n.axes = append(n.axes, element{ native: native, usage: int(usage), - index: len(gp.native.axes), + index: len(n.axes), minimum: int(C.IOHIDElementGetLogicalMin(native)), maximum: int(C.IOHIDElementGetLogicalMax(native)), }) case C.kHIDUsage_GD_Hatswitch: - gp.native.hats = append(gp.native.hats, element{ + n.hats = append(n.hats, element{ native: native, usage: int(usage), - index: len(gp.native.hats), + index: len(n.hats), minimum: int(C.IOHIDElementGetLogicalMin(native)), maximum: int(C.IOHIDElementGetLogicalMax(native)), }) case C.kHIDUsage_GD_DPadUp, C.kHIDUsage_GD_DPadRight, C.kHIDUsage_GD_DPadDown, C.kHIDUsage_GD_DPadLeft, C.kHIDUsage_GD_SystemMainMenu, C.kHIDUsage_GD_Select, C.kHIDUsage_GD_Start: - gp.native.buttons = append(gp.native.buttons, element{ + n.buttons = append(n.buttons, element{ native: native, usage: int(usage), - index: len(gp.native.buttons), + index: len(n.buttons), minimum: int(C.IOHIDElementGetLogicalMin(native)), maximum: int(C.IOHIDElementGetLogicalMax(native)), }) @@ -264,28 +274,28 @@ func (g *nativeGamepads) addDevice(device C.IOHIDDeviceRef, gamepads *gamepads) case C.kHIDPage_Simulation: switch usage { case C.kHIDUsage_Sim_Accelerator, C.kHIDUsage_Sim_Brake, C.kHIDUsage_Sim_Throttle, C.kHIDUsage_Sim_Rudder, C.kHIDUsage_Sim_Steering: - gp.native.axes = append(gp.native.axes, element{ + n.axes = append(n.axes, element{ native: native, usage: int(usage), - index: len(gp.native.axes), + index: len(n.axes), minimum: int(C.IOHIDElementGetLogicalMin(native)), maximum: int(C.IOHIDElementGetLogicalMax(native)), }) } case C.kHIDPage_Button, C.kHIDPage_Consumer: - gp.native.buttons = append(gp.native.buttons, element{ + n.buttons = append(n.buttons, element{ native: native, usage: int(usage), - index: len(gp.native.buttons), + index: len(n.buttons), minimum: int(C.IOHIDElementGetLogicalMin(native)), maximum: int(C.IOHIDElementGetLogicalMax(native)), }) } } - sort.Stable(gp.native.axes) - sort.Stable(gp.native.buttons) - sort.Stable(gp.native.hats) + sort.Stable(n.axes) + sort.Stable(n.buttons) + sort.Stable(n.hats) } type element struct { @@ -316,7 +326,7 @@ func (e elements) Swap(i, j int) { e[i], e[j] = e[j], e[i] } -type nativeGamepad struct { +type nativeGamepadImpl struct { device C.IOHIDDeviceRef axes elements buttons elements @@ -327,7 +337,7 @@ type nativeGamepad struct { hatValues []int } -func (g *nativeGamepad) elementValue(e *element) int { +func (g *nativeGamepadImpl) elementValue(e *element) int { var valueRef C.IOHIDValueRef if C.IOHIDDeviceGetValue(g.device, e.native, &valueRef) == C.kIOReturnSuccess { return int(C.IOHIDValueGetIntegerValue(valueRef)) @@ -336,7 +346,7 @@ func (g *nativeGamepad) elementValue(e *element) int { return 0 } -func (g *nativeGamepad) update(gamepads *gamepads) error { +func (g *nativeGamepadImpl) update(gamepads *gamepads) error { if cap(g.axisValues) < len(g.axes) { g.axisValues = make([]float64, len(g.axes)) } @@ -392,47 +402,47 @@ func (g *nativeGamepad) update(gamepads *gamepads) error { return nil } -func (g *nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return false } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return len(g.axisValues) } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return len(g.buttonValues) } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return len(g.hatValues) } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if axis < 0 || axis >= len(g.axisValues) { return 0 } return g.axisValues[axis] } -func (g *nativeGamepad) buttonValue(button int) float64 { +func (g *nativeGamepadImpl) buttonValue(button int) float64 { panic("gamepad: buttonValue is not implemented") } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if button < 0 || button >= len(g.buttonValues) { return false } return g.buttonValues[button] } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { if hat < 0 || hat >= len(g.hatValues) { return hatCentered } return g.hatValues[hat] } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // TODO: Implement this (#1452) } diff --git a/internal/gamepad/gamepad_ios.go b/internal/gamepad/gamepad_ios.go index 9c0415dd8..2209a9247 100644 --- a/internal/gamepad/gamepad_ios.go +++ b/internal/gamepad/gamepad_ios.go @@ -21,18 +21,22 @@ import ( "time" ) -type nativeGamepads struct{} +type nativeGamepadsImpl struct{} -func (*nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (*nativeGamepadsImpl) init(gamepads *gamepads) error { initializeIOSGamepads() return nil } -func (*nativeGamepads) update(gamepads *gamepads) error { +func (*nativeGamepadsImpl) update(gamepads *gamepads) error { return nil } -type nativeGamepad struct { +type nativeGamepadImpl struct { controller uintptr buttonMask uint16 hasDualshockTouchpad bool @@ -44,52 +48,52 @@ type nativeGamepad struct { hats []int } -func (g *nativeGamepad) update(gamepad *gamepads) error { +func (g *nativeGamepadImpl) update(gamepad *gamepads) error { g.updateIOSGamepad() return nil } -func (*nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return false } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return len(g.axes) } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return len(g.buttons) } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return len(g.hats) } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if axis < 0 || axis >= len(g.axes) { return 0 } return g.axes[axis] } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if button < 0 || button >= len(g.buttons) { return false } return g.buttons[button] } -func (*nativeGamepad) buttonValue(button int) float64 { +func (*nativeGamepadImpl) buttonValue(button int) float64 { panic("gamepad: buttonValue is not implemented") } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { if hat < 0 || hat >= len(g.hats) { return 0 } return g.hats[hat] } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // TODO: Implement this (#1452) } diff --git a/internal/gamepad/gamepad_js.go b/internal/gamepad/gamepad_js.go index eda28e67b..eb3aca8e9 100644 --- a/internal/gamepad/gamepad_js.go +++ b/internal/gamepad/gamepad_js.go @@ -25,15 +25,19 @@ var ( go2cpp = js.Global().Get("go2cpp") ) -type nativeGamepads struct { +type nativeGamepadsImpl struct { indices map[int]struct{} } -func (g *nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (g *nativeGamepadsImpl) init(gamepads *gamepads) error { return nil } -func (g *nativeGamepads) update(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) update(gamepads *gamepads) error { // TODO: Use the gamepad events instead of navigator.getGamepads after go2cpp is removed. defer func() { @@ -73,7 +77,7 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { // The gamepad is not registered yet, register this. gamepad := gamepads.find(func(gamepad *Gamepad) bool { - return index == gamepad.native.index + return index == gamepad.native.(*nativeGamepadImpl).index }) if gamepad == nil { name := gp.Get("id").String() @@ -84,28 +88,30 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { copy(sdlID[:], []byte(name)) gamepad = gamepads.add(name, hex.EncodeToString(sdlID[:])) - gamepad.native.index = index - gamepad.native.mapping = gp.Get("mapping").String() + gamepad.native = &nativeGamepadImpl{ + index: index, + mapping: gp.Get("mapping").String(), + } } - gamepad.native.value = gp + gamepad.native.(*nativeGamepadImpl).value = gp } // Remove an unused gamepads. gamepads.remove(func(gamepad *Gamepad) bool { - _, ok := g.indices[gamepad.native.index] + _, ok := g.indices[gamepad.native.(*nativeGamepadImpl).index] return !ok }) return nil } -type nativeGamepad struct { +type nativeGamepadImpl struct { value js.Value index int mapping string } -func (g *nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { // With go2cpp, the controller must have the standard if go2cpp.Truthy() { return true @@ -113,23 +119,23 @@ func (g *nativeGamepad) hasOwnStandardLayoutMapping() bool { return g.mapping == "standard" } -func (g *nativeGamepad) update(gamepads *gamepads) error { +func (g *nativeGamepadImpl) update(gamepads *gamepads) error { return nil } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return g.value.Get("axes").Length() } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return g.value.Get("buttons").Length() } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return 0 } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { axes := g.value.Get("axes") if axis < 0 || axis >= axes.Length() { return 0 @@ -137,7 +143,7 @@ func (g *nativeGamepad) axisValue(axis int) float64 { return axes.Index(axis).Float() } -func (g *nativeGamepad) buttonValue(button int) float64 { +func (g *nativeGamepadImpl) buttonValue(button int) float64 { buttons := g.value.Get("buttons") if button < 0 || button >= buttons.Length() { return 0 @@ -145,7 +151,7 @@ func (g *nativeGamepad) buttonValue(button int) float64 { return buttons.Index(button).Get("value").Float() } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { buttons := g.value.Get("buttons") if button < 0 || button >= buttons.Length() { return false @@ -153,11 +159,11 @@ func (g *nativeGamepad) isButtonPressed(button int) bool { return buttons.Index(button).Get("pressed").Bool() } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { return hatCentered } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // vibrationActuator is avaialble on Chrome. if va := g.value.Get("vibrationActuator"); va.Truthy() { if !va.Get("playEffect").Truthy() { diff --git a/internal/gamepad/gamepad_linux.go b/internal/gamepad/gamepad_linux.go index 37a9eb5c9..95f2cf558 100644 --- a/internal/gamepad/gamepad_linux.go +++ b/internal/gamepad/gamepad_linux.go @@ -37,12 +37,16 @@ func isBitSet(s []byte, bit int) bool { return s[bit/8]&(1<<(bit%8)) != 0 } -type nativeGamepads struct { +type nativeGamepadsImpl struct { inotify int watch int } -func (g *nativeGamepads) init(gamepads *gamepads) error { +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + +func (g *nativeGamepadsImpl) init(gamepads *gamepads) error { // Check the existence of the directory `dirName`. var stat unix.Stat_t if err := unix.Stat(dirName, &stat); err != nil { @@ -90,9 +94,9 @@ func (g *nativeGamepads) init(gamepads *gamepads) error { return nil } -func (*nativeGamepads) openGamepad(gamepads *gamepads, path string) (err error) { +func (*nativeGamepadsImpl) openGamepad(gamepads *gamepads, path string) (err error) { if gamepads.find(func(gamepad *Gamepad) bool { - return gamepad.native.path == path + return gamepad.native.(*nativeGamepadImpl).path == path }) != nil { return nil } @@ -164,11 +168,14 @@ func (*nativeGamepads) openGamepad(gamepads *gamepads, path string) (err error) bs[0], bs[1], bs[2], bs[3], bs[4], bs[5], bs[6], bs[7], bs[8], bs[9], bs[10], bs[11]) } + n := &nativeGamepadImpl{ + path: path, + fd: fd, + } gp := gamepads.add(name, sdlID) - gp.native.path = path - gp.native.fd = fd + gp.native = n runtime.SetFinalizer(gp, func(gp *Gamepad) { - gp.native.close() + n.close() }) var axisCount int @@ -178,40 +185,40 @@ func (*nativeGamepads) openGamepad(gamepads *gamepads, path string) (err error) if !isBitSet(keyBits, code) { continue } - gp.native.keyMap[code-_BTN_MISC] = buttonCount + n.keyMap[code-_BTN_MISC] = buttonCount buttonCount++ } for code := 0; code < _ABS_CNT; code++ { - gp.native.absMap[code] = -1 + n.absMap[code] = -1 if !isBitSet(absBits, code) { continue } if code >= _ABS_HAT0X && code <= _ABS_HAT3Y { - gp.native.absMap[code] = hatCount + n.absMap[code] = hatCount hatCount++ // Skip Y. code++ continue } - if err := ioctl(gp.native.fd, uint(_EVIOCGABS(uint(code))), unsafe.Pointer(&gp.native.absInfo[code])); err != nil { + if err := ioctl(n.fd, uint(_EVIOCGABS(uint(code))), unsafe.Pointer(&n.absInfo[code])); err != nil { return fmt.Errorf("gamepad: ioctl for an abs at openGamepad failed: %w", err) } - gp.native.absMap[code] = axisCount + n.absMap[code] = axisCount axisCount++ } - gp.native.axisCount_ = axisCount - gp.native.buttonCount_ = buttonCount - gp.native.hatCount_ = hatCount + n.axisCount_ = axisCount + n.buttonCount_ = buttonCount + n.hatCount_ = hatCount - if err := gp.native.pollAbsState(); err != nil { + if err := n.pollAbsState(); err != nil { return err } return nil } -func (g *nativeGamepads) update(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) update(gamepads *gamepads) error { if g.inotify <= 0 { return nil } @@ -248,9 +255,9 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { } if e.Mask&unix.IN_DELETE != 0 { if gp := gamepads.find(func(gamepad *Gamepad) bool { - return gamepad.native.path == path + return gamepad.native.(*nativeGamepadImpl).path == path }); gp != nil { - gp.native.close() + gp.native.(*nativeGamepadImpl).close() gamepads.remove(func(gamepad *Gamepad) bool { return gamepad == gp }) @@ -262,7 +269,7 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { return nil } -type nativeGamepad struct { +type nativeGamepadImpl struct { fd int path string keyMap [_KEY_CNT - _BTN_MISC]int @@ -279,14 +286,14 @@ type nativeGamepad struct { hatCount_ int } -func (g *nativeGamepad) close() { +func (g *nativeGamepadImpl) close() { if g.fd != 0 { unix.Close(g.fd) } g.fd = 0 } -func (g *nativeGamepad) update(gamepad *gamepads) error { +func (g *nativeGamepadImpl) update(gamepad *gamepads) error { if g.fd == 0 { return nil } @@ -344,7 +351,7 @@ func (g *nativeGamepad) update(gamepad *gamepads) error { return nil } -func (g *nativeGamepad) pollAbsState() error { +func (g *nativeGamepadImpl) pollAbsState() error { for code := 0; code < _ABS_CNT; code++ { if g.absMap[code] < 0 { continue @@ -357,7 +364,7 @@ func (g *nativeGamepad) pollAbsState() error { return nil } -func (g *nativeGamepad) handleAbsEvent(code int, value int32) { +func (g *nativeGamepadImpl) handleAbsEvent(code int, value int32) { index := g.absMap[code] if code >= _ABS_HAT0X && code <= _ABS_HAT3Y { @@ -399,47 +406,47 @@ func (g *nativeGamepad) handleAbsEvent(code int, value int32) { g.axes[index] = v } -func (*nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return false } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { return g.axisCount_ } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { return g.buttonCount_ } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { return g.hatCount_ } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if axis < 0 || axis >= g.axisCount_ { return 0 } return g.axes[axis] } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if button < 0 || button >= g.buttonCount_ { return false } return g.buttons[button] } -func (*nativeGamepad) buttonValue(button int) float64 { +func (*nativeGamepadImpl) buttonValue(button int) float64 { panic("gamepad: buttonValue is not implemented") } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { if hat < 0 || hat >= g.hatCount_ { return hatCentered } return g.hats[hat] } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // TODO: Implement this (#1452) } diff --git a/internal/gamepad/gamepad_windows.go b/internal/gamepad/gamepad_windows.go index d9c36ca27..b44b26a01 100644 --- a/internal/gamepad/gamepad_windows.go +++ b/internal/gamepad/gamepad_windows.go @@ -99,7 +99,7 @@ var xinputButtons = []uint16{ _XINPUT_GAMEPAD_RIGHT_THUMB, } -type nativeGamepads struct { +type nativeGamepadsImpl struct { dinput8 windows.Handle dinput8API *_IDirectInput8W xinput windows.Handle @@ -118,6 +118,10 @@ type nativeGamepads struct { err error } +func newNativeGamepadsImpl() nativeGamepads { + return &nativeGamepadsImpl{} +} + type dinputObject struct { objectType dinputObjectType index int @@ -132,7 +136,7 @@ type enumObjectsContext struct { povCount int } -func (g *nativeGamepads) init(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) init(gamepads *gamepads) error { // As there is no guarantee that the DLL exists, NewLazySystemDLL is not available. // TODO: Is there a 'system' version of LoadLibrary? if h, err := windows.LoadLibrary("dinput8.dll"); err == nil { @@ -194,7 +198,7 @@ func (g *nativeGamepads) init(gamepads *gamepads) error { return nil } -func (g *nativeGamepads) directInput8Create(hinst uintptr, dwVersion uint32, riidltf *windows.GUID, ppvOut **_IDirectInput8W, punkOuter unsafe.Pointer) error { +func (g *nativeGamepadsImpl) directInput8Create(hinst uintptr, dwVersion uint32, riidltf *windows.GUID, ppvOut **_IDirectInput8W, punkOuter unsafe.Pointer) error { r, _, _ := syscall.Syscall6(g.procDirectInput8Create, 5, hinst, uintptr(dwVersion), uintptr(unsafe.Pointer(riidltf)), uintptr(unsafe.Pointer(ppvOut)), uintptr(punkOuter), 0) @@ -204,7 +208,7 @@ func (g *nativeGamepads) directInput8Create(hinst uintptr, dwVersion uint32, rii return nil } -func (g *nativeGamepads) xinputGetCapabilities(dwUserIndex uint32, dwFlags uint32, pCapabilities *_XINPUT_CAPABILITIES) error { +func (g *nativeGamepadsImpl) xinputGetCapabilities(dwUserIndex uint32, dwFlags uint32, pCapabilities *_XINPUT_CAPABILITIES) error { // XInputGetCapabilities doesn't call SetLastError and returns an error code directly. r, _, _ := syscall.Syscall(g.procXInputGetCapabilities, 3, uintptr(dwUserIndex), uintptr(dwFlags), uintptr(unsafe.Pointer(pCapabilities))) @@ -214,7 +218,7 @@ func (g *nativeGamepads) xinputGetCapabilities(dwUserIndex uint32, dwFlags uint3 return nil } -func (g *nativeGamepads) xinputGetState(dwUserIndex uint32, pState *_XINPUT_STATE) error { +func (g *nativeGamepadsImpl) xinputGetState(dwUserIndex uint32, pState *_XINPUT_STATE) error { // XInputGetState doesn't call SetLastError and returns an error code directly. r, _, _ := syscall.Syscall(g.procXInputGetState, 2, uintptr(dwUserIndex), uintptr(unsafe.Pointer(pState)), 0) @@ -224,7 +228,7 @@ func (g *nativeGamepads) xinputGetState(dwUserIndex uint32, pState *_XINPUT_STAT return nil } -func (g *nativeGamepads) detectConnection(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) detectConnection(gamepads *gamepads) error { if g.dinput8 != 0 { if g.enumDevicesCallback == 0 { g.enumDevicesCallback = windows.NewCallback(g.dinput8EnumDevicesCallback) @@ -241,7 +245,8 @@ func (g *nativeGamepads) detectConnection(gamepads *gamepads) error { for i := 0; i < xuserMaxCount; i++ { if gamepads.find(func(g *Gamepad) bool { - return g.native.dinputDevice == nil && g.native.xinputIndex == i + n := g.native.(*nativeGamepadImpl) + return n.dinputDevice == nil && n.xinputIndex == i }) != nil { continue } @@ -278,13 +283,15 @@ func (g *nativeGamepads) detectConnection(gamepads *gamepads) error { } gp := gamepads.add(name, sdlID) - gp.native.xinputIndex = i + gp.native = &nativeGamepadImpl{ + xinputIndex: i, + } } } return nil } -func (g *nativeGamepads) dinput8EnumDevicesCallback(lpddi *_DIDEVICEINSTANCEW, pvRef unsafe.Pointer) uintptr { +func (g *nativeGamepadsImpl) dinput8EnumDevicesCallback(lpddi *_DIDEVICEINSTANCEW, pvRef unsafe.Pointer) uintptr { gamepads := (*gamepads)(pvRef) if g.err != nil { @@ -292,7 +299,7 @@ func (g *nativeGamepads) dinput8EnumDevicesCallback(lpddi *_DIDEVICEINSTANCEW, p } if gamepads.find(func(g *Gamepad) bool { - return g.native.dinputGUID == lpddi.guidInstance + return g.native.(*nativeGamepadImpl).dinputGUID == lpddi.guidInstance }) != nil { return _DIENUM_CONTINUE } @@ -389,12 +396,14 @@ func (g *nativeGamepads) dinput8EnumDevicesCallback(lpddi *_DIDEVICEINSTANCEW, p } gp := gamepads.add(name, sdlID) - gp.native.dinputDevice = device - gp.native.dinputObjects = ctx.objects - gp.native.dinputGUID = lpddi.guidInstance - gp.native.dinputAxes = make([]float64, ctx.axisCount+ctx.sliderCount) - gp.native.dinputButtons = make([]bool, ctx.buttonCount) - gp.native.dinputHats = make([]int, ctx.povCount) + gp.native = &nativeGamepadImpl{ + dinputDevice: device, + dinputObjects: ctx.objects, + dinputGUID: lpddi.guidInstance, + dinputAxes: make([]float64, ctx.axisCount+ctx.sliderCount), + dinputButtons: make([]bool, ctx.buttonCount), + dinputHats: make([]int, ctx.povCount), + } return _DIENUM_CONTINUE } @@ -443,7 +452,7 @@ func supportsXInput(guid windows.GUID) (bool, error) { return false, nil } -func (g *nativeGamepads) dinputDevice8EnumObjectsCallback(lpddoi *_DIDEVICEOBJECTINSTANCEW, pvRef unsafe.Pointer) uintptr { +func (g *nativeGamepadsImpl) dinputDevice8EnumObjectsCallback(lpddoi *_DIDEVICEOBJECTINSTANCEW, pvRef unsafe.Pointer) uintptr { ctx := (*enumObjectsContext)(pvRef) switch { @@ -511,7 +520,7 @@ func (g *nativeGamepads) dinputDevice8EnumObjectsCallback(lpddoi *_DIDEVICEOBJEC return _DIENUM_CONTINUE } -func (g *nativeGamepads) update(gamepads *gamepads) error { +func (g *nativeGamepadsImpl) update(gamepads *gamepads) error { if g.err != nil { return g.err } @@ -537,7 +546,7 @@ func (g *nativeGamepads) update(gamepads *gamepads) error { return nil } -func (g *nativeGamepads) wndProc(hWnd uintptr, uMsg uint32, wParam, lParam uintptr) uintptr { +func (g *nativeGamepadsImpl) wndProc(hWnd uintptr, uMsg uint32, wParam, lParam uintptr) uintptr { switch uMsg { case _WM_DEVICECHANGE: atomic.StoreInt32(&g.deviceChanged, 1) @@ -545,11 +554,11 @@ func (g *nativeGamepads) wndProc(hWnd uintptr, uMsg uint32, wParam, lParam uintp return _CallWindowProcW(g.origWndProc, hWnd, uMsg, wParam, lParam) } -func (g *nativeGamepads) setNativeWindow(nativeWindow uintptr) { +func (g *nativeGamepadsImpl) setNativeWindow(nativeWindow uintptr) { g.nativeWindow = windows.HWND(nativeWindow) } -type nativeGamepad struct { +type nativeGamepadImpl struct { dinputDevice *_IDirectInputDevice8W dinputObjects []dinputObject dinputGUID windows.GUID @@ -561,22 +570,22 @@ type nativeGamepad struct { xinputState _XINPUT_STATE } -func (*nativeGamepad) hasOwnStandardLayoutMapping() bool { +func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool { return false } -func (g *nativeGamepad) usesDInput() bool { +func (g *nativeGamepadImpl) usesDInput() bool { return g.dinputDevice != nil } -func (g *nativeGamepad) update(gamepads *gamepads) (err error) { +func (g *nativeGamepadImpl) update(gamepads *gamepads) (err error) { var disconnected bool defer func() { if !disconnected && err == nil { return } gamepads.remove(func(gamepad *Gamepad) bool { - return &gamepad.native == g + return gamepad.native == g }) }() @@ -666,7 +675,7 @@ func (g *nativeGamepad) update(gamepads *gamepads) (err error) { } var state _XINPUT_STATE - if err := gamepads.native.xinputGetState(uint32(g.xinputIndex), &state); err != nil { + if err := gamepads.native.(*nativeGamepadsImpl).xinputGetState(uint32(g.xinputIndex), &state); err != nil { if !errors.Is(err, windows.ERROR_DEVICE_NOT_CONNECTED) { return err } @@ -677,28 +686,28 @@ func (g *nativeGamepad) update(gamepads *gamepads) (err error) { return nil } -func (g *nativeGamepad) axisCount() int { +func (g *nativeGamepadImpl) axisCount() int { if g.usesDInput() { return len(g.dinputAxes) } return 6 } -func (g *nativeGamepad) buttonCount() int { +func (g *nativeGamepadImpl) buttonCount() int { if g.usesDInput() { return len(g.dinputButtons) } return len(xinputButtons) } -func (g *nativeGamepad) hatCount() int { +func (g *nativeGamepadImpl) hatCount() int { if g.usesDInput() { return len(g.dinputHats) } return 1 } -func (g *nativeGamepad) axisValue(axis int) float64 { +func (g *nativeGamepadImpl) axisValue(axis int) float64 { if g.usesDInput() { if axis < 0 || axis >= len(g.dinputAxes) { return 0 @@ -724,7 +733,7 @@ func (g *nativeGamepad) axisValue(axis int) float64 { return v } -func (g *nativeGamepad) isButtonPressed(button int) bool { +func (g *nativeGamepadImpl) isButtonPressed(button int) bool { if g.usesDInput() { if button < 0 || button >= len(g.dinputButtons) { return false @@ -738,11 +747,11 @@ func (g *nativeGamepad) isButtonPressed(button int) bool { return g.xinputState.Gamepad.wButtons&xinputButtons[button] != 0 } -func (g *nativeGamepad) buttonValue(button int) float64 { +func (g *nativeGamepadImpl) buttonValue(button int) float64 { panic("gamepad: buttonValue is not implemented") } -func (g *nativeGamepad) hatState(hat int) int { +func (g *nativeGamepadImpl) hatState(hat int) int { if g.usesDInput() { if hat < 0 || hat >= len(g.dinputHats) { return 0 @@ -769,6 +778,6 @@ func (g *nativeGamepad) hatState(hat int) int { return v } -func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { +func (g *nativeGamepadImpl) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) { // TODO: Implement this (#1452) }