forked from 0xcafed00d/joystick
-
Notifications
You must be signed in to change notification settings - Fork 4
/
joystick_windows.go
219 lines (186 loc) · 4.83 KB
/
joystick_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// +build windows
package joystick
import (
"fmt"
"golang.org/x/sys/windows"
"math"
"unsafe"
)
var PrintFunc func(x, y int, s string)
const (
_MAXPNAMELEN = 32
_MAX_JOYSTICKOEMVXDNAME = 260
_MAX_AXIS = 6
_JOY_RETURNX = 1
_JOY_RETURNY = 2
_JOY_RETURNZ = 4
_JOY_RETURNR = 8
_JOY_RETURNU = 16
_JOY_RETURNV = 32
_JOY_RETURNPOV = 64
_JOY_RETURNBUTTONS = 128
_JOY_RETURNRAWDATA = 256
_JOY_RETURNPOVCTS = 512
_JOY_RETURNCENTERED = 1024
_JOY_USEDEADZONE = 2048
_JOY_RETURNALL = (_JOY_RETURNX | _JOY_RETURNY | _JOY_RETURNZ | _JOY_RETURNR | _JOY_RETURNU | _JOY_RETURNV | _JOY_RETURNPOV | _JOY_RETURNBUTTONS)
_JOYCAPS_HASZ = 0x1
_JOYCAPS_HASR = 0x2
_JOYCAPS_HASU = 0x4
_JOYCAPS_HASV = 0x8
_JOYCAPS_HASPOV = 0x10
_JOYCAPS_POV4DIR = 0x20
_JOYCAPS_POVCTS = 0x40
)
type JOYCAPS struct {
wMid uint16
wPid uint16
szPname [_MAXPNAMELEN]uint16
wXmin uint32
wXmax uint32
wYmin uint32
wYmax uint32
wZmin uint32
wZmax uint32
wNumButtons uint32
wPeriodMin uint32
wPeriodMax uint32
wRmin uint32
wRmax uint32
wUmin uint32
wUmax uint32
wVmin uint32
wVmax uint32
wCaps uint32
wMaxAxes uint32
wNumAxes uint32
wMaxButtons uint32
szRegKey [_MAXPNAMELEN]uint16
szOEMVxD [_MAX_JOYSTICKOEMVXDNAME]uint16
}
type JOYINFOEX struct {
dwSize uint32
dwFlags uint32
dwAxis [_MAX_AXIS]uint32
dwButtons uint32
dwButtonNumber uint32
dwPOV uint32
dwReserved1 uint32
dwReserved2 uint32
}
var (
winmmdll = windows.MustLoadDLL("Winmm.dll")
joyGetPosEx = winmmdll.MustFindProc("joyGetPosEx")
joyGetDevCaps = winmmdll.MustFindProc("joyGetDevCapsW")
)
type axisLimit struct {
min, max uint32
}
type joystickImpl struct {
id int
axisCount int
povAxisCount int
buttonCount int
name string
state State
axisLimits []axisLimit
}
func mapValue(val, srcMin, srcMax, dstMin, dstMax int64) int64 {
return (val-srcMin)*(dstMax-dstMin)/(srcMax-srcMin) + dstMin
}
// Open opens the Joystick for reading, with the supplied id
//
// Under linux the id is used to construct the joystick device name:
// for example: id 0 will open device: "/dev/input/js0"
//
// Under Windows the id is the actual numeric id of the joystick
//
// If successful, a Joystick interface is returned which can be used to
// read the state of the joystick, else an error is returned
func Open(id int) (Joystick, error) {
js := &joystickImpl{}
js.id = id
err := js.getJoyCaps()
if err == nil {
return js, nil
}
return nil, err
}
func (js *joystickImpl) getJoyCaps() error {
var caps JOYCAPS
ret, _, _ := joyGetDevCaps.Call(uintptr(js.id), uintptr(unsafe.Pointer(&caps)), unsafe.Sizeof(caps))
if ret != 0 {
return fmt.Errorf("Failed to read Joystick %d", js.id)
} else {
js.axisCount = int(caps.wNumAxes)
js.buttonCount = int(caps.wNumButtons)
js.name = windows.UTF16ToString(caps.szPname[:])
if caps.wCaps&_JOYCAPS_HASPOV != 0 {
js.povAxisCount = 2
}
js.state.AxisData = make([]int, js.axisCount+js.povAxisCount, js.axisCount+js.povAxisCount)
js.axisLimits = []axisLimit{
{caps.wXmin, caps.wXmax},
{caps.wYmin, caps.wYmax},
{caps.wZmin, caps.wZmax},
{caps.wRmin, caps.wRmax},
{caps.wUmin, caps.wUmax},
{caps.wVmin, caps.wVmax},
}
return nil
}
}
func axisFromPov(povVal float64) int {
switch {
case povVal < -0.5:
return -32767
case povVal > 0.5:
return 32768
default:
return 0
}
}
func (js *joystickImpl) getJoyPosEx() error {
var info JOYINFOEX
info.dwSize = uint32(unsafe.Sizeof(info))
info.dwFlags = _JOY_RETURNALL
ret, _, _ := joyGetPosEx.Call(uintptr(js.id), uintptr(unsafe.Pointer(&info)))
if ret != 0 {
return fmt.Errorf("Failed to read Joystick %d", js.id)
} else {
js.state.Buttons = info.dwButtons
for i := 0; i < js.axisCount; i++ {
js.state.AxisData[i] = int(mapValue(int64(info.dwAxis[i]),
int64(js.axisLimits[i].min), int64(js.axisLimits[i].max), -32767, 32768))
}
if js.povAxisCount > 0 {
angleDeg := float64(info.dwPOV) / 100.0
if angleDeg > 359.0 {
js.state.AxisData[js.axisCount] = 0
js.state.AxisData[js.axisCount+1] = 0
return nil
}
angleRad := angleDeg * math.Pi / 180.0
sin, cos := math.Sincos(angleRad)
js.state.AxisData[js.axisCount] = axisFromPov(sin)
js.state.AxisData[js.axisCount+1] = axisFromPov(-cos)
}
return nil
}
}
func (js *joystickImpl) AxisCount() int {
return js.axisCount + js.povAxisCount
}
func (js *joystickImpl) ButtonCount() int {
return js.buttonCount
}
func (js *joystickImpl) Name() string {
return js.name
}
func (js *joystickImpl) Read() (State, error) {
err := js.getJoyPosEx()
return js.state, err
}
func (js *joystickImpl) Close() {
// no impl under windows
}