-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathGamepad.cs
415 lines (335 loc) · 12.8 KB
/
Gamepad.cs
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Targets;
using Nefarius.ViGEm.Client.Targets.DualShock4;
using Nefarius.ViGEm.Client.Targets.Xbox360;
namespace AutomaticGamepad
{
public abstract class Gamepad : IDisposable
{
public const string Name = "gamepad";
public const int Duration = 200;
[DllImport("user32.dll")]
protected static extern bool SetForegroundWindow(IntPtr hWnd);
public static Gamepad Instance { private set; get; }
public IntPtr Handle { set; get; }
public bool AbortThread { set; get; }
public int DelayTime { set; get; } = 100;
public abstract GamepadType GamepadType { get; }
public abstract string BindApplicationName { get; }
public abstract string PictureName { get; }
protected abstract IVirtualGamepad Internal_Gamepad { set; get; }
protected abstract Dictionary<string, GamepadProperty> GamepadPropertyDic { get; }
protected ViGEmClient Client { set; get; }
public Gamepad()
{
Instance = this;
Client = new ViGEmClient();
Console.WriteLine("Gamepad New");
}
public void Dispose()
{
OnDispose();
// 不要调Disconnect,会导致驱动释放异常
// 正确的释放会在下面 Client.Dipose 中处理
//Internal_Gamepad?.Disconnect();
Internal_Gamepad = null;
Client?.Dispose();
Client = null;
Instance = null;
Console.WriteLine("Gamepad Dispose");
}
public void Connect()
{
try
{
Internal_Gamepad.Connect();
Console.WriteLine("Connect Gamepad");
Thread.Sleep(200);
}
catch (Exception ex)
{
throw new Exception("虚拟手柄连接错误!\n" + ex);
}
}
public virtual void OnDispose()
{
}
public virtual void SetForeground(double milliseconds)
{
if (Handle != IntPtr.Zero)
{
SetForegroundWindow(Handle);
Thread.Sleep((int)milliseconds);
}
}
#region JS Interface
public void sleep(double milliseconds) { SetSleep(milliseconds); }
public void setdelay(double delay) { DelayTime = (int)delay; }
public void button(string name, double duration = Duration) { SetButton(name, duration); }
public void dpad(string name, double duration = Duration) { SetDPad(name, duration); }
public void trigger(string name, double value, double duration = Duration) { SetTrigger(name, value, duration); }
public void axis(string name, double value, double duration = Duration) { SetAxis(name, value, duration); }
public void axis2(string name1, string name2, double value1, double value2, double duration = Duration) { SetAxis2(name1, name2, value1, value2, duration); }
public void buttonstate(string name, bool state) { SetButtonState(name, state); }
public void dpadstate(string name, bool state) { SetDPadState(name, state); }
public void triggerstate(string name, double value) { SetTriggerState(name, value); }
public void axisstate(string name, double value) { SetAxisState(name, value); }
public void axis2state(string name1, string name2, double value1, double value2) { SetAxis2State(name1, name2, value1, value2); }
#endregion
public virtual void SetSleep(double milliseconds)
{
var stopwatch = Stopwatch.StartNew();
while (true)
{
if (AbortThread || stopwatch.ElapsedMilliseconds >= milliseconds)
break;
Thread.Sleep(1);
}
}
public virtual void CallMethod(params string[] args)
{
SetForeground(200);
var argLength = args?.Length ?? 0;
if (argLength == 0)
return;
var arg1 = args[0];
var arg2 = 0D;
var arg3 = 0D;
if (!GamepadPropertyDic.TryGetValue(arg1, out var property))
return;
if (argLength >= 2)
double.TryParse(args[1], out arg2);
if (argLength >= 3)
double.TryParse(args[2], out arg3);
var enabledDelay = false;
switch (argLength)
{
case 1:
if (property is GamepadButton button)
SetButton(button, Duration, enabledDelay);
else if (property is GamepadDPad dPad)
SetDPad(dPad, Duration, enabledDelay);
break;
case 3:
if (property is GamepadTrigger slider)
SetTrigger(slider, arg2, arg3, enabledDelay);
else if (property is GamepadAxis axis)
SetAxis(axis, arg2, arg3, enabledDelay);
break;
default:
throw new Exception("未实现 CallMethod 接口");
}
}
public T GetProperty<T>(string name) where T : GamepadProperty
{
GamepadPropertyDic.TryGetValue(name, out var property);
return property as T;
}
protected void SetButton(GamepadButton button, double duration, bool enabledDelay = true)
{
if (button == null)
return;
SetButtonState(button, true);
SetSleep(duration);
SetButtonState(button, false);
if (enabledDelay)
SetSleep(DelayTime);
}
protected void SetDPad(GamepadDPad dPad, double duration, bool enabledDelay = true)
{
if (dPad == null)
return;
SetDPadState(dPad, true);
SetSleep(duration);
SetDPadState(dPad, false);
if (enabledDelay)
SetSleep(DelayTime);
}
protected void SetTrigger(GamepadTrigger trigger, double value, double duration, bool enabledDelay = true)
{
if (trigger == null)
return;
SetTriggerState(trigger, value);
SetSleep(duration);
SetTriggerState(trigger, 0);
if (enabledDelay)
SetSleep(DelayTime);
}
protected void SetAxis(GamepadAxis axis, double value, double duration, bool enabledDelay = true)
{
if (axis == null)
return;
SetAxisState(axis, value);
SetSleep(duration);
SetAxisState(axis, 0);
if (enabledDelay)
SetSleep(DelayTime);
}
protected void SetAxis2(GamepadAxis axis1, GamepadAxis axis2, double value1, double value2, double duration, bool enabledDelay = true)
{
if (axis1 == null || axis2 == null)
return;
SetAxis2State(axis1, axis2, value1, value2);
SetSleep(duration);
SetAxis2State(axis1, axis2, 0, 0);
if (enabledDelay)
SetSleep(DelayTime);
}
protected void SetButtonState(GamepadButton button, bool state)
{
var gamepad = Internal_Gamepad;
gamepad.AutoSubmitReport = true;
gamepad.SetButtonState(button, state);
}
protected void SetDPadState(GamepadDPad dPad, bool state)
{
var gamepad = Internal_Gamepad;
gamepad.AutoSubmitReport = true;
if (gamepad is IDualShock4Controller controller)
{
if (state)
controller.SetDPadDirection((DualShock4DPadDirection)dPad.DualShock4);
else
controller.SetDPadDirection(DualShock4DPadDirection.None);
}
else
{
gamepad.SetButtonState(dPad, state);
}
}
protected void SetTriggerState(GamepadTrigger trigger, double value)
{
var gamepad = Internal_Gamepad;
gamepad.AutoSubmitReport = false;
// PS4下需要调用 SetButtonState 才会生效
if (trigger.DualShock4 == DualShock4Slider.LeftTrigger)
gamepad.SetButtonState(DualShock4Button.TriggerLeft.Id, value > 0);
else if (trigger.DualShock4 == DualShock4Slider.RightTrigger)
gamepad.SetButtonState(DualShock4Button.TriggerRight.Id, value > 0);
gamepad.SetSliderValue(trigger, ToByte(value));
gamepad.SubmitReport();
}
protected void SetAxisState(GamepadAxis axis, double value)
{
var gamepad = Internal_Gamepad;
gamepad.AutoSubmitReport = true;
value = FixedAxisValue(axis, value);
gamepad.SetAxisValue(axis, ToShort(value));
}
protected void SetAxis2State(GamepadAxis axis1, GamepadAxis axis2, double value1, double value2)
{
var gamepad = Internal_Gamepad;
gamepad.AutoSubmitReport = false;
value1 = FixedAxisValue(axis1, value1);
value2 = FixedAxisValue(axis2, value2);
gamepad.SetAxisValue(axis1, ToShort(value1));
gamepad.SetAxisValue(axis2, ToShort(value2));
gamepad.SubmitReport();
}
protected byte ToByte(double value)
{
return (byte)(value * byte.MaxValue);
}
protected short ToShort(double value)
{
return (short)(value * short.MaxValue);
}
protected double FixedAxisValue(GamepadAxis axis, double value)
{
if (axis?.DualShock4 == DualShock4Axis.LeftThumbY ||
axis?.DualShock4 == DualShock4Axis.RightThumbY)
return value * -1;
return value;
}
}
public enum GamepadType
{
Xbox = 0,
PlayStation = 1,
}
public class GamepadProperty
{
public Xbox360Property Xbox360 { protected set; get; }
public DualShock4Property DualShock4 { protected set; get; }
public int Index
{
get
{
if (Xbox360 != null)
return Xbox360.Id;
if (DualShock4 != null)
return DualShock4.Id;
throw new Exception("Gamepad Button 无效");
}
}
public static implicit operator int(GamepadProperty property)
{
return property.Index;
}
}
public class GamepadButton : GamepadProperty
{
public static implicit operator GamepadButton(Xbox360Button button)
{
return new GamepadButton() { Xbox360 = button };
}
public static implicit operator GamepadButton(DualShock4Button button)
{
return new GamepadButton() { DualShock4 = button };
}
public static implicit operator GamepadButton(string name)
{
return Gamepad.Instance.GetProperty<GamepadButton>(name);
}
}
public class GamepadDPad : GamepadProperty
{
public static implicit operator GamepadDPad(Xbox360Button button)
{
return new GamepadDPad() { Xbox360 = button };
}
public static implicit operator GamepadDPad(DualShock4DPadDirection button)
{
return new GamepadDPad() { DualShock4 = button };
}
public static implicit operator GamepadDPad(string name)
{
return Gamepad.Instance.GetProperty<GamepadDPad>(name);
}
}
public class GamepadTrigger : GamepadProperty
{
public static implicit operator GamepadTrigger(Xbox360Slider slider)
{
return new GamepadTrigger() { Xbox360 = slider };
}
public static implicit operator GamepadTrigger(DualShock4Slider slider)
{
return new GamepadTrigger() { DualShock4 = slider };
}
public static implicit operator GamepadTrigger(string name)
{
return Gamepad.Instance.GetProperty<GamepadTrigger>(name);
}
}
public class GamepadAxis : GamepadProperty
{
public static implicit operator GamepadAxis(Xbox360Axis button)
{
return new GamepadAxis() { Xbox360 = button };
}
public static implicit operator GamepadAxis(DualShock4Axis button)
{
return new GamepadAxis() { DualShock4 = button };
}
public static implicit operator GamepadAxis(string name)
{
return Gamepad.Instance.GetProperty<GamepadAxis>(name);
}
}
}