-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclsAdaptiveHID.cls
1441 lines (1438 loc) · 77.2 KB
/
clsAdaptiveHID.cls
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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "clsAdaptiveHID"
Attribute VB_GlobalNameSpace = True
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
'Set these to match the values in the device's firmware and INF file.
'
'Vendor 'Nintendo' &H57E
'Product 'Joy-Con (L)' &H2006
'Product 'Joy-Con (R)' &H2007
'
'Vendor 'Scuf Gaming' &H2E95
'Product 'Instinct Pro' &H504 - 'Xbox Controller' &H7725
Private Const VendorID As Long = &H57E
Private Const productIdJoyConL As Long = &H2006
Private Const productIdJoyConR As Long = &H2007
Private Const HIDP_INPUT As Integer = 0
Private Const HIDP_OUTPUT As Integer = 1
Private Const HIDP_FEATURE As Integer = 2
Private Const DIGCF_PRESENT As Long = &H2 'setupapi.h
Private Const DIGCF_DEVICEINTERFACE As Long = &H10
Private Const FILE_FLAG_OVERLAPPED As Long = &H40000000
Private Const FILE_SHARE_READ As Long = &H1
Private Const FILE_SHARE_WRITE As Long = &H2
Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000
Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const OPEN_EXISTING As Long = &H3
Private Const WAIT_ABANDONED As Long = &H80
Private Const WAIT_FAILED As Long = &HFFFFFFFF
Private Const WAIT_OBJECT_0 As Long = &H0
Private Const WAIT_TIMEOUT As Long = &H102
Private Const INFINITE As Long = &HFFFF
Private Const ERROR_SUCCESS As Long = &H0
'
'LEFT JOYCON bit constants
Private Const VK_PAD_LTHUMB_RIGHT As Long = &H0
Private Const VK_PAD_LTHUMB_DOWNRIGHT As Long = &H1
Private Const VK_PAD_LTHUMB_DOWN As Long = &H2
Private Const VK_PAD_LTHUMB_DOWNLEFT As Long = &H3
Private Const VK_PAD_LTHUMB_LEFT As Long = &H4
Private Const VK_PAD_LTHUMB_UPLEFT As Long = &H5
Private Const VK_PAD_LTHUMB_UP As Long = &H6
Private Const VK_PAD_LTHUMB_UPRIGHT As Long = &H7
Private Const VK_PAD_LTHUMB_DEAD As Long = &H8
Private Const VK_PAD_MINUS As Long = &H1
Private Const VK_PAD_LTHUMB_PRESS As Long = &H8
Private Const VK_PAD_BACK As Long = &H2
Private Const VK_PAD_LSHOULDER As Long = &H4
Private Const VK_PAD_LTRIGGER As Long = &H8
'initial mode only
'Private Const VK_PAD_DPAD_LEFT As Long = &H1
'Private Const VK_PAD_DPAD_DOWN As Long = &H2
'Private Const VK_PAD_DPAD_UP As Long = &H4
'Private Const VK_PAD_DPAD_RIGHT As Long = &H8
'Private Const VK_PAD_LTHUMB_PRESS As Long = &H4
'Private Const VK_PAD_SL1 As Long = &H1
'Private Const VK_PAD_SR1 As Long = &H2
'
Private Const VK_PAD_DPAD_DOWN As Long = &H1
Private Const VK_PAD_DPAD_UP As Long = &H2
Private Const VK_PAD_DPAD_RIGHT As Long = &H4
Private Const VK_PAD_DPAD_LEFT As Long = &H8
Private Const VK_PAD_SL1 As Long = &H2
Private Const VK_PAD_SR1 As Long = &H1
'
'RIGHT JOYCON bit Private Const ants
Private Const VK_PAD_RTHUMB_LEFT As Long = &H0
Private Const VK_PAD_RTHUMB_UPLEFT As Long = &H1
Private Const VK_PAD_RTHUMB_UP As Long = &H2
Private Const VK_PAD_RTHUMB_UPRIGHT As Long = &H3
Private Const VK_PAD_RTHUMB_RIGHT As Long = &H4
Private Const VK_PAD_RTHUMB_DOWNRIGHT As Long = &H5
Private Const VK_PAD_RTHUMB_DOWN As Long = &H6
Private Const VK_PAD_RTHUMB_DOWNLEFT As Long = &H7
Private Const VK_PAD_RTHUMB_DEAD As Long = &H8
Private Const VK_PAD_PLUS As Long = &H2
Private Const VK_PAD_RTHUMB_PRESS As Long = &H4
Private Const VK_PAD_START As Long = &H1
Private Const VK_PAD_RSHOULDER As Long = &H4
Private Const VK_PAD_RTRIGGER As Long = &H8
Private Const VK_PAD_B As Long = &H1
Private Const VK_PAD_Y As Long = &H2
Private Const VK_PAD_A As Long = &H4
Private Const VK_PAD_X As Long = &H8
Private Const VK_PAD_SL2 As Long = &H2
Private Const VK_PAD_SR2 As Long = &H1
Private Type GUID
data1 As Long
data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Type HIDD_ATTRIBUTES
Size As Long
VendorID As Integer
ProductID As Integer
VersionNumber As Integer
End Type
Private Type HIDP_CAPS
usage As Integer
UsagePage As Integer
InputReportByteLength As Integer
OutputReportByteLength As Integer
FeatureReportByteLength As Integer
reserved(0 To 16) As Integer
NumberLinkCollectionNodes As Integer
NumberInputButtonCaps As Integer
NumberInputValueCaps As Integer
NumberInputDataIndices As Integer
NumberOutputButtonCaps As Integer
NumberOutputValueCaps As Integer
NumberOutputDataIndices As Integer
NumberFeatureButtonCaps As Integer
NumberFeatureValueCaps As Integer
NumberFeatureDataIndices As Integer
End Type
Private Type HIDP_VALUE_CAPS
UsagePage As Integer 'USAGE
ReportID As Byte
IsAlias As Byte
BitField As Integer
LinkCollection As Integer ' A unique internal index pointer
LinkUsage As Integer 'USAGE
LinkUsagePage As Integer 'USAGE
IsRange As Byte 'If IsRange is false, UsageMin is the Usage and UsageMax is unused.
IsStringRange As Byte 'If IsStringRange is false, StringMin is the string index and StringMax is unused.
IsDesignatorRange As Byte 'If IsDesignatorRange is false, DesignatorMin is the designator index and DesignatorMax is unused.
IsAbsolute As Byte
HasNull As Byte ' Does this channel have a null report union
reserved As Byte
BitSize As Integer ' How many bits are devoted to this value?
ReportCount As Integer ' See Note below. Usually set to 1.
Reserved2(0 To 4) As Integer
UnitsExp As Long 'Specifies the usage's exponent, as described by the USB HID standard.
units As Long 'Specifies the usage's units, as described by the USB HID Standard.
LogicalMin As Long
LogicalMax As Long
PhysicalMin As Long
PhysicalMax As Long
UsageOrUsageMin As Integer
UsageMax As Integer
StringMinOrIndex As Integer
StringMax As Integer
DesignatorMinOrIndex As Integer
DesignatorMax As Integer
DataIndexMinOrIndex As Integer
DataIndexMax As Integer
End Type
Private Type OVERLAPPED
Internal As Long
InternalHigh As Long
offset As Long
OffsetHigh As Long
hEvent As Long
End Type
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type SP_DEVICE_INTERFACE_DATA
cbSize As Long
InterfaceClassGuid As GUID
Flags As Long
reserved As Long
End Type
Private Type SP_DEVICE_INTERFACE_DETAIL_DATA
cbSize As Long
DevicePath As Byte
End Type
Private Type SP_DEVINFO_DATA
cbSize As Long
ClassGuid As GUID
devInst As Long
reserved As Long
End Type
Private Declare Function apiIIDFromString Lib "ole32.dll" Alias "IIDFromString" (ByVal lpsz As Long, ByRef lpiid As GUID) As Long
Private Declare Function apiCancelIo Lib "kernel32" Alias "CancelIo" (ByVal hFile As Long) As Long
Private Declare Function apiCloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Long) As Long
Private Declare Function apiCreateEvent Lib "kernel32" Alias "CreateEventA" (ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As String) As Long
Private Declare Function apiCreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function apiFormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, ByRef lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageZId As Long, ByVal lpBuffer As String, ByVal nSize As Long, ByVal Arguments As Long) As Long
Private Declare Function apiReadFile Lib "kernel32" Alias "ReadFile" (ByVal hFile As Long, ByRef lpBuffer As Byte, ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, ByRef lpOverlapped As OVERLAPPED) As Long
Private Declare Function apiResetEvent Lib "kernel32" Alias "ResetEvent" (ByVal hEvent As Long) As Long
Private Declare Function apiRtlMoveMemoryByteStruct Lib "kernel32" Alias "RtlMoveMemory" (ByRef Dest As Byte, ByRef src As SP_DEVICE_INTERFACE_DETAIL_DATA, ByVal Count As Long) As Long
Private Declare Function apiRtlMoveMemoryByteLong Lib "kernel32" Alias "RtlMoveMemory" (ByRef Dest As Byte, ByRef src As Long, ByVal Count As Long) As Long
Private Declare Function apiRtlMoveMemoryLongLong Lib "kernel32" Alias "RtlMoveMemory" (ByRef des As Long, ByRef src As Long, ByVal Count As Long) As Long
Private Declare Function apiCopyMemoryBYTELONG Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Byte, ByVal Source As Long, ByVal Length As Long) As Long
Private Declare Function apiCopyMemoryByteLongLong Lib "kernel32" Alias "RtlMoveMemory" (ByRef Dest As Byte, ByVal Source As Long, ByVal Bytes As Long) As Long
Private Declare Function apiRtlMoveMemoryByteValueCaps Lib "kernel32" Alias "RtlMoveMemory" (ByRef des As HIDP_VALUE_CAPS, ByVal src As Byte, ByVal Count As Long) As Long
Private Declare Function apiWaitForSingleObjectEx Lib "kernel32" Alias "WaitForSingleObjectEx" (ByVal hHandle As Long, ByVal dwMilliseconds As Long, ByVal balertable As Boolean) As Long
Private Declare Function apiWriteFile Lib "kernel32" Alias "WriteFile" (ByVal hFile As Long, ByRef lpBuffer As Byte, ByVal nNumberOfBytesToWrite As Long, ByRef lpNumberOfBytesWritten As Long, ByRef lpOverlapped As Long) As Long
Private Declare Function apiWideCharToMultiByte Lib "kernel32" Alias "WideCharToMultiByte" (ByVal CodePage As Long, ByVal dwFlags As Long, ByRef lpWideCharStr As Long, ByVal cchWideChar As Long, ByRef lpMultiByteStr As String, ByVal cchMultiByte As Long, ByVal lpDefaultChar As String, ByVal lpUsedDefaultChar As Long) As Long
Private Declare Function apilstrlenA Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
Private Declare Function apilstrlenW Lib "kernel32" Alias "lstrlenW" (ByVal lpString As Long) As Long
'
Private Declare Function apiHidD_FreePreparsedData Lib "hid.dll" Alias "HidD_FreePreparsedData" (ByRef PreparsedData As Long) As Long 'ByVal PreparsedData
Private Declare Function apiHidD_GetAttributes Lib "hid.dll" Alias "HidD_GetAttributes" (ByVal HidDeviceObject As Long, ByRef Attributes As HIDD_ATTRIBUTES) As Long
Private Declare Function apiHidP_GetCaps Lib "hid.dll" Alias "HidP_GetCaps" (ByVal PreparsedData As Long, ByRef capabilities As HIDP_CAPS) As Long
Private Declare Function apiHidD_GetHidGuid Lib "hid.dll" Alias "HidD_GetHidGuid" (ByRef HidGuid As GUID) As Long
Private Declare Function apiHidD_GetPreparsedData Lib "hid.dll" Alias "HidD_GetPreparsedData" (ByVal HidDeviceObject As Long, ByRef PreparsedData As Long) As Long
Private Declare Function apiHidP_GetValueCaps Lib "hid.dll" Alias "HidP_GetValueCaps" (ByVal ReportType As Integer, ByRef valuecaps As Byte, ByRef ValueCapsLength As Integer, ByVal PreparsedData As Long) As Long
Private Declare Function apiHidD_GetFeature Lib "hid.dll" Alias "HidD_GetFeature" (ByVal HidDeviceObject As Long, ByRef ReportBuffer As Byte, ByVal ReportBufferLength As Long) As Long
Private Declare Function apiHidD_SetFeature Lib "hid.dll" Alias "HidD_SetFeature" (ByVal HidDeviceObject As Long, ByRef ReportBuffer As Byte, ByVal ReportBufferLength As Long) As Byte
Private Declare Function apiHidD_FlushQueue Lib "hid.dll" Alias "HidD_FlushQueue" (ByVal HidDeviceObject As Long) As Long
''Private Const FACILITY_HID_ERROR_CODE = &H11
'? extras untested
''Private Declare Function apiHidD_GetNumInputBuffers Lib "hid.dll" Alias "HidD_GetNumInputBuffers" (ByVal HidDeviceObject As Long, ByRef NumberBuffers As Long) As Byte
''Private Declare Function apiHidD_SetNumInputBuffers Lib "hid.dll" Alias "HidD_SetNumInputBuffers" (ByVal HidDeviceObject As Long, ByVal NumberBuffers As Long) As Byte
''Private Declare Function apiHidD_GetInputReport Lib "hid.dll" Alias "HidD_GetInputReport" (ByVal HidDeviceObject As Long, ByRef ReportBuffer As Byte, ByVal ReportBufferLength As Long) As Byte
''Private Declare Function apiHidD_SetOutputReport Lib "hid.dll" Alias "HidD_SetOutputReport" (ByVal HidDeviceObject As Long, ByRef ReportBuffer As Byte, ByVal ReportBufferLength As Long) As Byte
Private Declare Function apiSetupDiDestroyDeviceInfoList Lib "setupapi.dll" Alias "SetupDiDestroyDeviceInfoList" (ByVal DeviceInfoSet As Long) As Long
Private Declare Function apiSetupDiGetClassDevs Lib "setupapi.dll" Alias "SetupDiGetClassDevsA" (ByRef ClassGuid As GUID, ByVal Enumerator As String, ByVal hwndParent As Long, ByVal Flags As Long) As Long
Private Declare Function apiSetupDiEnumDeviceInterfaces Lib "setupapi.dll" Alias "SetupDiEnumDeviceInterfaces" (ByVal DeviceInfoSet As Long, ByVal DeviceInfoData As Long, ByRef InterfaceClassGuid As GUID, ByVal MemberIndex As Long, ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Long
Private Declare Function apiSetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailA" (ByVal DeviceInfoSet As Long, ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, ByVal DeviceInterfaceDetailData As Long, ByVal DeviceInterfaceDetailDataSize As Long, ByRef RequiredSize As Long, ByVal DeviceInfoData As Long) As Long
Private ReadHandleL As Long
Private ReadHandleR As Long
Public bAlertableL As Long
Public bAlertableR As Long
Private CapabilitiesL As HIDP_CAPS
Private CapabilitiesR As HIDP_CAPS
Private EventObjectL As Long
Private EventObjectR As Long
Private hidHandleL As Long
Private hidHandleR As Long
Private HIDOverlappedL As OVERLAPPED
Private HIDOverlappedR As OVERLAPPED
Private mvarDeviceDetectedL As Boolean
Private mvarDeviceDetectedR As Boolean
Private DevicePathNameL As String
Private DevicePathNameR As String
'
Public Event DeviceConnection(ByVal Index As Integer, ByVal connected As Boolean)
Public Event ClickButton(ByVal joycon As Integer, ByVal down As Boolean, ByVal btns As String)
Public Event WriteReportResult(ByVal Report As String)
Public Event ReadReportResult(ByVal Report As String)
Private LTHUMB_RIGHT As Boolean
Private LTHUMB_DOWNRIGHT As Boolean
Private LTHUMB_DOWN As Boolean
Private LTHUMB_DOWNLEFT As Boolean
Private LTHUMB_LEFT As Boolean
Private LTHUMB_UP As Boolean
Private LTHUMB_UPLEFT As Boolean
Private LTHUMB_UPRIGHT As Boolean
Private LTHUMB_DEAD As Boolean
Private JOYCON1_MINUS As Boolean
Private JOYCON1_VIEW As Boolean
Private JOYCON1_LSHOULDER As Boolean
Private JOYCON1_LTRIGGER As Boolean
Private JOYCON1_LSTICK As Boolean
Private JOYCON1_DPAD_UP As Boolean
Private JOYCON1_DPAD_DOWN As Boolean
Private JOYCON1_DPAD_LEFT As Boolean
Private JOYCON1_DPAD_RIGHT As Boolean
Private JOYCON1_SL As Boolean
Private JOYCON1_SR As Boolean
'
Private RTHUMB_RIGHT As Boolean
Private RTHUMB_DOWNRIGHT As Boolean
Private RTHUMB_DOWN As Boolean
Private RTHUMB_DOWNLEFT As Boolean
Private RTHUMB_LEFT As Boolean
Private RTHUMB_UPLEFT As Boolean
Private RTHUMB_UP As Boolean
Private RTHUMB_UPRIGHT As Boolean
Private RTHUMB_DEAD As Boolean
Private JOYCON2_PLUS As Boolean
Private JOYCON2_MENU As Boolean
Private JOYCON2_RSHOULDER As Boolean
Private JOYCON2_RTRIGGER As Boolean
Private JOYCON2_RSTICK As Boolean
Private JOYCON2_A As Boolean
Private JOYCON2_B As Boolean
Private JOYCON2_X As Boolean
Private JOYCON2_Y As Boolean
Private JOYCON2_SL As Boolean
Private JOYCON2_SR As Boolean
Private WithEvents tmrPoll As Timer
Attribute tmrPoll.VB_VarHelpID = -1
Private WithEvents tmrFindDevices As Timer
Attribute tmrFindDevices.VB_VarHelpID = -1
Public Sub Class_Initialize()
Set tmrFindDevices = New Timer
Set tmrPoll = New Timer
tmrFindDevices.Interval = 3000
tmrPoll.Interval = 1
tmrFindDevices.Enabled = True
tmrPoll.Enabled = True
End Sub
Public Sub FormUnloading()
If hidHandleL <> 0 Then apiCloseHandle hidHandleL 'Actions that must execute when the program ends. 'Close the open handles to the device.
If hidHandleR <> 0 Then apiCloseHandle hidHandleR
End Sub
Private Sub tmrFindDevices_Timer()
FindJoyConHIDs
End Sub
Private Sub tmrPoll_Timer()
ReadDevices
End Sub
Public Sub FlushQueue()
If hidHandleL <> 0 Then apiHidD_FlushQueue hidHandleL
If hidHandleR <> 0 Then apiHidD_FlushQueue hidHandleR
End Sub
Public Sub ReadDevices()
'Read a report from device.
If mvarDeviceDetectedL = True And mvarDeviceDetectedR = True Then
ReadReport ReadHandleL, CapabilitiesL, EventObjectL, bAlertableL, HIDOverlappedL
ReadReport ReadHandleR, CapabilitiesR, EventObjectR, bAlertableR, HIDOverlappedR
ElseIf mvarDeviceDetectedL = True And mvarDeviceDetectedR = False Then
ReadReport ReadHandleL, CapabilitiesL, EventObjectL, bAlertableL, HIDOverlappedL
ElseIf mvarDeviceDetectedL = False And mvarDeviceDetectedR = True Then
ReadReport ReadHandleR, CapabilitiesR, EventObjectR, bAlertableR, HIDOverlappedR
End If
End Sub
Public Sub WriteReadDevices(ByVal lpData As String)
FindJoyConHIDs
If mvarDeviceDetectedL = True Then
If hidHandleL <> 0 Then
apiHidD_FlushQueue hidHandleL
WriteReport lpData, hidHandleL, CapabilitiesL
apiHidD_FlushQueue hidHandleL
ReadReport ReadHandleL, CapabilitiesL, EventObjectL, bAlertableL, HIDOverlappedL
apiHidD_FlushQueue hidHandleL
End If
End If
If mvarDeviceDetectedR = True Then
If hidHandleR <> 0 Then
apiHidD_FlushQueue hidHandleR
WriteReport lpData, hidHandleR, CapabilitiesR
apiHidD_FlushQueue hidHandleR
ReadReport ReadHandleR, CapabilitiesR, EventObjectR, bAlertableR, HIDOverlappedR
apiHidD_FlushQueue hidHandleR
End If
End If
End Sub
Public Sub RumbleJoyCon(ByVal Index As Long, ByVal lpData As String)
If Index = 1 And mvarDeviceDetectedL = True Then
If hidHandleL <> 0 Then
WriteReport lpData, hidHandleL, CapabilitiesL
End If
End If
If Index = 2 And mvarDeviceDetectedR = True Then
If hidHandleR <> 0 Then
WriteReport lpData, hidHandleR, CapabilitiesR
End If
End If
End Sub
Public Sub FindJoyConHIDs()
Dim ret As Long
Dim i As Integer
Dim GUIDString As String
Dim HidGuid As GUID
Dim MemberIndex As Long
Dim MyDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
Dim MyDeviceInfoData As SP_DEVINFO_DATA
Dim MyDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
Dim Needed As Long
Dim DataString As String
Dim DetailData As Long
Dim DetailDataBuffer() As Byte
Dim hidHandle As Long
Dim DeviceAttributes As HIDD_ATTRIBUTES
Dim DevicePathName As String
Dim DeviceInfoSet As Long
Dim LastDevice As Boolean
Dim SECURITYL As SECURITY_ATTRIBUTES
Dim SECURITYR As SECURITY_ATTRIBUTES
Dim SECURITY As SECURITY_ATTRIBUTES
Dim PreparsedData As Long
SECURITYL.lpSecurityDescriptor = 0
SECURITYL.bInheritHandle = True
SECURITYL.nLength = Len(SECURITYL)
SECURITYR.lpSecurityDescriptor = 0
SECURITYR.bInheritHandle = True
SECURITYR.nLength = Len(SECURITYR)
ret = apiHidD_GetHidGuid(HidGuid)
GUIDString = VBA.Hex$(HidGuid.data1) & "-" & VBA.Hex$(HidGuid.data2) & "-" & VBA.Hex$(HidGuid.Data3) & "-"
For i = 0 To 7
If HidGuid.Data4(i) >= &H10 Then 'Ensure that each of the 8 bytes in the GUID displays two characters
GUIDString = GUIDString & VBA.Hex$(HidGuid.Data4(i)) & " "
Else
GUIDString = GUIDString & "0" & VBA.Hex$(HidGuid.Data4(i)) & " "
End If
Next
DeviceInfoSet = apiSetupDiGetClassDevs(HidGuid, vbNullString, 0, (DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE))
DataString = GetDataString(DeviceInfoSet, 32)
MemberIndex = 0
If DeviceInfoSet <> 0 Then ' if device info set can be obtained
Do
MyDeviceInterfaceData.cbSize = LenB(MyDeviceInterfaceData) 'The cbSize element of the MyDeviceInterfaceData structure must be set to the structure's size in bytes. The size is 28 bytes.
ret = apiSetupDiEnumDeviceInterfaces(DeviceInfoSet, 0, HidGuid, MemberIndex, MyDeviceInterfaceData)
If ret = 0 Then
LastDevice = True ' no more devices to loop through
Else 'If a device exists during enumeration
MyDeviceInfoData.cbSize = Len(MyDeviceInfoData)
ret = apiSetupDiGetDeviceInterfaceDetail(DeviceInfoSet, MyDeviceInterfaceData, 0, 0, Needed, 0)
If ret = ERROR_SUCCESS Then 'if we obtained the device's interface details
DetailData = Needed
MyDeviceInterfaceDetailData.cbSize = Len(MyDeviceInterfaceDetailData)
ReDim DetailDataBuffer(Needed) 'Use a byte array to allocate memory for the MyDeviceInterfaceDetailData structure
apiRtlMoveMemoryByteStruct DetailDataBuffer(0), MyDeviceInterfaceDetailData, 4 'Store cbSize in the first four bytes of the array
ret = apiSetupDiGetDeviceInterfaceDetail(DeviceInfoSet, MyDeviceInterfaceData, VarPtr(DetailDataBuffer(0)), DetailData, Needed, 0)
DevicePathName = CStr(DetailDataBuffer()) 'Convert the byte array to a string.
DevicePathName = StrConv(DevicePathName, vbUnicode) 'Convert to Unicode.
DevicePathName = Right$(DevicePathName, Len(DevicePathName) - 4) 'Strip cbSize (4 bytes) from the beginning.
If VBA.Trim(DevicePathName) <> "" Then 'if we got a name from detail call
hidHandle = apiCreateFile(DevicePathName, GENERIC_READ Or GENERIC_WRITE, (FILE_SHARE_READ Or FILE_SHARE_WRITE), SECURITY, OPEN_EXISTING, 0&, 0)
If hidHandle <> 0 Then 'if we found a handle to the device
DeviceAttributes.Size = LenB(DeviceAttributes)
ret = apiHidD_GetAttributes(hidHandle, DeviceAttributes)
If ret <> 0 Then 'If we got the device's attributes
If DeviceAttributes.VendorID = VendorID Then
If DeviceAttributes.ProductID = productIdJoyConL Then 'If the device matches
mvarDeviceDetectedL = True 'Signal a flag for the desired device
hidHandleL = hidHandle
SECURITYL = SECURITY
DevicePathNameL = DevicePathName
RaiseEvent DeviceConnection(1, True) 'expose the class object event to application developers
ElseIf DeviceAttributes.ProductID = productIdJoyConR Then
mvarDeviceDetectedR = True
hidHandleR = hidHandle
SECURITYR = SECURITY
DevicePathNameR = DevicePathName
RaiseEvent DeviceConnection(2, True)
Else
apiCloseHandle hidHandle 'If not matching, close handle
End If
Else
apiCloseHandle hidHandle 'If not matching, close handle
End If
Else
apiCloseHandle hidHandle
End If
End If
End If
End If
End If
If LastDevice = True Then Exit Do
If mvarDeviceDetectedL = True And mvarDeviceDetectedR = True Then Exit Do
MemberIndex = MemberIndex + 1 'Loop through devices
Loop
If mvarDeviceDetectedL = False Then
RaiseEvent DeviceConnection(1, False)
End If
If mvarDeviceDetectedR = False Then
RaiseEvent DeviceConnection(2, False)
End If
apiSetupDiDestroyDeviceInfoList DeviceInfoSet 'Free the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs
End If
Dim ppData(29) As Byte
Dim ppDataString As Variant
Dim valuecaps() As Byte 'Dim valuecaps As HIDP_VALUE_CAPS
If mvarDeviceDetectedL = True Then
' Learn the capabilities of the device 'Get another handle for the overlapped ReadFiles.
If hidHandleL <> 0 Then
ret = apiHidD_GetPreparsedData(hidHandleL, PreparsedData) 'Preparsed Data is a pointer to a routine-allocated buffer.
If ret <> 0 Then
ret = apiRtlMoveMemoryByteLong(ppData(0), PreparsedData, 30) 'Copy the data at PreparsedData into a byte array.
If ret <> 0 Then
ppDataString = ppData()
ppDataString = StrConv(ppDataString, vbUnicode) 'Convert the data to Unicode.
ret = apiHidP_GetCaps(PreparsedData, CapabilitiesL)
If ret <> 0 Then
ReDim valuecaps(4096)
apiHidP_GetValueCaps HIDP_INPUT, valuecaps(0), CapabilitiesL.NumberInputValueCaps, PreparsedData 'To use this data, copy the byte array into an array of structures.
''apiRtlMoveMemoryByteValueCaps vc, valuecaps, Len(vc)
' Debug.Print Capabilities.FeatureReportByteLength '0
' Debug.Print Capabilities.InputReportByteLength '362
' Debug.Print Capabilities.NumberFeatureButtonCaps '0
' Debug.Print Capabilities.NumberFeatureDataIndices '0
' Debug.Print Capabilities.NumberFeatureValueCaps '0
' Debug.Print Capabilities.NumberInputButtonCaps '1
' Debug.Print Capabilities.NumberInputDataIndices '26
' Debug.Print Capabilities.NumberInputValueCaps '10
' Debug.Print Capabilities.NumberLinkCollectionNodes '1
' Debug.Print Capabilities.NumberOutputButtonCaps '0
' Debug.Print Capabilities.NumberOutputDataIndices '4
' Debug.Print Capabilities.NumberOutputValueCaps '4
' Debug.Print Capabilities.OutputReportByteLength '49
' '''Debug.Print Capabilities.Reserved'NO
' Debug.Print Capabilities.usage '5
' Debug.Print Capabilities.UsagePage '1
' Debug.Print "Value Caps= " & GetDataString((VarPtr(valuecaps(0))), 180)
apiHidD_FreePreparsedData PreparsedData 'Free the buffer reserved by HidD_GetPreparsedData
End If
End If
End If
End If
If VBA.Trim(DevicePathNameL) <> "" Then
ReadHandleL = apiCreateFile(DevicePathNameL, (GENERIC_READ Or GENERIC_WRITE), (FILE_SHARE_READ Or FILE_SHARE_WRITE), SECURITY, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
End If
If EventObjectL = 0 Then 'Creates an event object for the overlapped structure used with ReadFile. Requires a security attributes structure or null,
EventObjectL = apiCreateEvent(SECURITY, True, True, "")
End If 'Manual Reset = True (ResetEvent resets the manual reset object to nonsignaled), Initial state = True (signaled), and event object name (optional)
HIDOverlappedL.offset = 0
HIDOverlappedL.OffsetHigh = 0
HIDOverlappedL.hEvent = EventObjectL
End If
If mvarDeviceDetectedR = True Then
' Learn the capabilities of the device 'Get another handle for the overlapped ReadFiles.
If hidHandleR <> 0 Then
ret = apiHidD_GetPreparsedData(hidHandleR, PreparsedData) 'Preparsed Data is a pointer to a routine-allocated buffer.
If ret <> 0 Then
ret = apiRtlMoveMemoryByteLong(ppData(0), PreparsedData, 30) 'Copy the data at PreparsedData into a byte array.
If ret <> 0 Then
ppDataString = ppData()
ppDataString = StrConv(ppDataString, vbUnicode) 'Convert the data to Unicode.
ret = apiHidP_GetCaps(PreparsedData, CapabilitiesR)
If ret <> 0 Then
'Dim valuecaps() As Byte 'Dim valuecaps As HIDP_VALUE_CAPS
ReDim valuecaps(4096)
apiHidP_GetValueCaps HIDP_INPUT, valuecaps(0), CapabilitiesR.NumberInputValueCaps, PreparsedData 'To use this data, copy the byte array into an array of structures.
apiHidD_FreePreparsedData PreparsedData 'Free the buffer reserved by HidD_GetPreparsedData
End If
End If
End If
End If
If VBA.Trim(DevicePathNameR) <> "" Then
ReadHandleR = apiCreateFile(DevicePathNameR, (GENERIC_READ Or GENERIC_WRITE), (FILE_SHARE_READ Or FILE_SHARE_WRITE), SECURITY, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
End If
If EventObjectR = 0 Then 'Creates an event object for the overlapped structure used with ReadFile. Requires a security attributes structure or null,
EventObjectR = apiCreateEvent(SECURITY, True, True, "")
End If 'Manual Reset = True (ResetEvent resets the manual reset object to nonsignaled), Initial state = True (signaled), and event object name (optional)
HIDOverlappedR.offset = 0
HIDOverlappedR.OffsetHigh = 0
HIDOverlappedR.hEvent = EventObjectR
End If
End Sub
Private Function GetFeatureReport(ByVal hidHandle As Long, ByRef inFeatureReportBuffer() As Byte) As Boolean
Dim success As Byte
Dim nLen As Long
nLen = UBound(inFeatureReportBuffer) - LBound(inFeatureReportBuffer) + 1
success = apiHidD_GetFeature(hidHandle, inFeatureReportBuffer(1), nLen)
GetFeatureReport = CBool(success)
End Function
Private Function SendFeatureReport(ByVal hidHandle As Long, ByRef outFeatureReportBuffer() As Byte) As Boolean 'ByRef outFeatureReportBuffer As Byte ?
Dim success As Byte 'Writes a Feature report to the device.
Dim nLen As Long
nLen = UBound(outFeatureReportBuffer) - LBound(outFeatureReportBuffer) + 1
success = apiHidD_SetFeature(hidHandle, outFeatureReportBuffer(1), nLen)
SendFeatureReport = CBool(success)
End Function
Private Sub ReadReport(ByRef readHandle As Long, ByRef capabilities As HIDP_CAPS, ByRef eventobject As Long, ByVal balertable As Boolean, ByRef hidoverlapped As OVERLAPPED)
Dim i As Integer
Dim NumberOfBytesRead As Long
Dim ReadBuffer() As Byte
Dim ret As Long
If capabilities.InputReportByteLength > 0 Then 'The ReadBuffer array begins at 0, so subtract 1 from the number of bytes.
ReDim ReadBuffer(capabilities.InputReportByteLength - 1)
Else
ReDim ReadBuffer(0)
End If
ret = apiReadFile(readHandle, ReadBuffer(0), CLng(capabilities.InputReportByteLength), NumberOfBytesRead, hidoverlapped) 'Do an overlapped ReadFile. 'The function returns immediately, even if the data hasn't been received yet.
If ret = ERROR_SUCCESS Then
'balertable = True
ret = apiWaitForSingleObjectEx(eventobject, 0, balertable)
apiResetEvent eventobject
balertable = False
Select Case ret 'Find out if ReadFile completed or timeout.
Case WAIT_OBJECT_0
'ReadFile has completed success
Case WAIT_TIMEOUT
ret = apiCancelIo(readHandle) 'Returns non-zero on success.
Case WAIT_ABANDONED
If readHandle = ReadHandleL Then
mvarDeviceDetectedL = False
ElseIf readHandle = ReadHandleR Then
mvarDeviceDetectedR = False
End If
Case WAIT_FAILED
If readHandle = ReadHandleL Then
mvarDeviceDetectedL = False
ElseIf readHandle = ReadHandleR Then
mvarDeviceDetectedR = False
End If
Case Else
If readHandle = ReadHandleL Then
mvarDeviceDetectedL = False
ElseIf readHandle = ReadHandleR Then
mvarDeviceDetectedR = False
End If
End Select
End If
If UBound(ReadBuffer) > 0 And ReadBuffer(0) > 0 Then
If readHandle = ReadHandleL Then
RaiseEvents "2006", ReadBuffer
ElseIf readHandle = ReadHandleR Then
RaiseEvents "2007", ReadBuffer
End If
End If
End Sub
Private Sub WriteReport(ByVal lpData As String, ByRef hidHandle As Long, ByRef capabilities As HIDP_CAPS)
' If capabilities.OutputReportByteLength < 11 Then Exit Sub
Dim i As Integer
Dim NumberOfBytesWritten As Long
Dim SendBuffer() As Byte
ReDim SendBuffer(capabilities.OutputReportByteLength)
Dim byts() As String
lpData = VBA.Replace(lpData, " ", " ")
lpData = VBA.Replace(lpData, " ", " ")
byts = VBA.Split(lpData, " ")
For i = 0 To UBound(byts)
If VBA.Trim(byts(i)) <> "" Then
SendBuffer(i) = CByte(CLng("&H" & VBA.Trim(byts(i))))
End If
Next
NumberOfBytesWritten = 0
Dim nLen As Long
nLen = UBound(SendBuffer) - LBound(SendBuffer) + 1
apiWriteFile hidHandle, SendBuffer(1), nLen, NumberOfBytesWritten, 0 'Send data to the device.
Dim Report As String
Report = Report & "NumberOfBytesWritten = " & NumberOfBytesWritten
RaiseEvent WriteReportResult(Report)
End Sub
Private Sub RaiseEvents(ByVal mvarProductId As String, ByRef ReadBuffer() As Byte)
If UBound(ReadBuffer) = 0 Then Exit Sub ' no events to raise
Dim x As String
Dim y As String
Dim flag1 As Long
Dim flag2 As Long
Dim flag3 As Long
Dim flag4 As Long
Dim flag5 As Long
Dim flag6 As Long
Dim flag7 As Long
Dim flag8 As Long
Dim flag9 As Long
Dim flag10 As Long
Dim flag11 As Long
Dim flag12 As Long
Dim accel_x As Long ' IMU (6-Axis sensor)
Dim accel_y As Long
Dim accel_z As Long
Dim gyro_1 As Long
Dim gyro_2 As Long
Dim gyro_3 As Long
Dim imu As String
Dim bState As String
Dim ss As String
Dim bys() As String
Dim ByteValue As String
Dim bv As String
Dim bv2 As String
Dim i As Long
For i = 0 To UBound(ReadBuffer)
If Len(VBA.Hex$(ReadBuffer(i))) < 2 Then 'Add a leading 0 to values 0 - Fh.
ByteValue = "0" & VBA.Hex$(ReadBuffer(i))
Else
ByteValue = VBA.Hex$(ReadBuffer(i))
End If
bv = bv & ByteValue
If i < 50 Then
bv2 = bv2 & ByteValue & " "
End If
If i > 361 Then '361 seems to be the limit-ish for a pair of joycons. 49-361 (ID x31) NFC/IR data input report. Max 313 bytes.
Exit For
End If
Next
flag1 = CLng("&H" & VBA.Mid(bv, 1, 1)) 'GetLoByte(ReadBuffer(0)) '
flag2 = CLng("&H" & VBA.Mid(bv, 2, 1)) 'GetHiByte(ReadBuffer(0)) '
flag3 = CLng("&H" & VBA.Mid(bv, 3, 1)) 'GetLoByte(ReadBuffer(1)) '
flag4 = CLng("&H" & VBA.Mid(bv, 4, 1)) 'GetHiByte(ReadBuffer(1)) '
flag5 = CLng("&H" & VBA.Mid(bv, 5, 1)) ''GetLoByte(ReadBuffer(2)) '
flag6 = CLng("&H" & VBA.Mid(bv, 6, 1)) 'GetHiByte(ReadBuffer(2)) '
flag7 = CLng("&H" & VBA.Mid(bv, 7, 1)) 'GetLoByte(ReadBuffer(3)) '
flag8 = CLng("&H" & VBA.Mid(bv, 8, 1)) 'eight bit (thumb 0-8. Dead=8) 3F GetHiByte(ReadBuffer(3)) '
' frmMain.Caption = flag5 & " | " & flag6 & " | " & flag7 & " | " & flag8
'
flag9 = CLng("&H" & VBA.Mid(bv, 9, 1)) 'View button
flag10 = CLng("&H" & VBA.Mid(bv, 10, 1)) 'Minus-button=1 and Left-stick button=8
flag11 = CLng("&H" & VBA.Mid(bv, 11, 1)) 'SR=1,SL=2, Left-shoulder=4 and Left-trigger=8
flag12 = CLng("&H" & VBA.Mid(bv, 12, 1)) 'Dpad=2 Left JoyCon
'If 6-axis sensor is enabled, the IMU data in an 0x30, 0x31, 0x32 and 0x33 input report is packaged
'like this (assuming the packet ID is located at byte 0):
'25-48 The data is repeated 2 more times. Each with 5ms ?t sampling.
accel_x = CLng("&H" & VBA.Mid(bv, 27, 4))
accel_y = CLng("&H" & VBA.Mid(bv, 29, 4))
accel_z = CLng("&H" & VBA.Mid(bv, 31, 4))
gyro_1 = CLng("&H" & VBA.Mid(bv, 33, 4))
gyro_2 = CLng("&H" & VBA.Mid(bv, 35, 4))
gyro_3 = CLng("&H" & VBA.Mid(bv, 37, 4))
If mvarProductId = "2006" Then 'Left JoyCon
If VBA.Left(bv, 2) = "3F" Then 'Basic mode
bv = "(JoyCon L) (Basic Input Mode: " & VBA.Left(bv, 2) & ") (Buttons: " & VBA.Mid(bv, 3, 6) & ")"
bv = bv & " (Raw: " & bv2 & ")" & vbCrLf
Else 'fast polling mode 30, 31, 32 and 33
'Dim packet As Variant
'Dim data() As Integer
'Dim stick_horizontal As Long
'Dim stick_vertical As Long
'data = packet + (Iff(Left, 4, 8))
' stick_horizontal = data(0) Or LShift(data(1), 8)
' stick_vertical = data(2) Or LShift(data(3), 8)
'uint8_t *data = packet + (If(left, 4, 8))
'Dim stick_horizontal As uint16_t = data(0) Or (data(1) << 8)
'Dim stick_vertical As uint16_t = data(2) Or (data(3) << 8)
''' Something = RShift(SomeValue, HowManyBits) ' Same with LShift
'''
''' MyWord = HiWord(MyDWord) ' Get the HiWord (same way with LoWord)
''' HiWord(MyDWord) = MyWord ' Set the HiWord (same with LoWord)
'''
''' MyByte = HiByte(MyWord) ' Get the HiByte (same with LoByte)
''' HiByte(MyWord) = MyByte ' Set the HiByte (same with LoByte)
'Nintendo has the order scrambled encoded. Unscramble and convert to decimal. Messy. why did they do this?
x = VBA.Mid(bv, 16, 1) & VBA.Mid(bv, 13, 1) & VBA.Mid(bv, 14, 1) ' & VBA.Mid(bv, 14, 1)
y = VBA.Mid(bv, 17, 1) & VBA.Mid(bv, 18, 1) & VBA.Mid(bv, 15, 1) '& VBA.Mid(bv, 15, 1)
x = CStr(VBA.Round(1.5 * CLng("&H" & x & "0")) - 50000)
y = CStr(VBA.Round(1.5 * CLng("&H" & y & "0")) - 50000)
If VBA.Abs(CLng(x)) >= 32767 Then
If VBA.Abs(CLng(x)) = CLng(x) Then
x = CStr(32767)
Else
x = CStr(-32767)
End If
End If
If VBA.Abs(CLng(y)) >= 32767 Then
If VBA.Abs(CLng(y)) = CLng(y) Then
y = CStr(32767)
Else
y = CStr(-32767)
End If
End If
If accel_x <> 0 And accel_y <> 0 And accel_z <> 0 And gyro_1 <> 0 And gyro_2 <> 0 And gyro_3 <> 0 Then
If VBA.Left(bv, 2) = "21" Then
bys = Split(bv2, " ")
ss = "(Firmware Version: " & bys(15) & "." & bys(16) & ") " & "(JoyCon: " & bys(17) & ") "
ss = ss & "(MAC address: " & bys(19) & bys(20) & bys(21) & bys(22) & bys(23) & bys(24)
'
Else
imu = "IMU 6-axis Mode: " & "(Accel X: " & CStr(accel_x) & ") (Accel Y: " & CStr(accel_y) & ") (Accel Z: " & CStr(accel_z) & ") (Gyro 1: " & CStr(gyro_1) & ") (Gyro 2: " & CStr(gyro_2) & ") (Gyro 3: " & CStr(gyro_3) & ")"
End If
End If
bv = "(JoyCon L) (Input Mode: " & VBA.Left(bv, 2) & ") (Packet: " & VBA.Mid(bv, 3, 2) & ") (Battery: " & VBA.Mid(bv, 5, 1) & ") (Connection:" & VBA.Mid(bv, 6, 1) & ") (Buttons: " & VBA.Mid(bv, 9, 4) & ") (X,Y: " & x & "," & y & ") (L/R: " & VBA.Mid(bv, 25, 1) & "/" & VBA.Mid(bv, 26, 1) & ")"
If ss <> "" Then bv = ss & " " & bv
If imu <> "" Then bv = imu & " " & bv
bv = bv & " (Raw: " & bv2 & ")"
End If
ElseIf mvarProductId = "2007" Then 'Right JoyCon
If VBA.Left(bv, 2) = "3F" Then
bv = "(JoyCon R) (Basic Input Mode: " & VBA.Left(bv, 2) & ") (Buttons: " & VBA.Mid(bv, 3, 6) & ")"
bv = bv & " (Raw: " & bv2 & ")" & vbCrLf
Else
'Nintendo scrambled the order. Unscramble and convert Ugly
x = VBA.Mid(bv, 22, 1) & VBA.Mid(bv, 19, 1) & VBA.Mid(bv, 21, 1)
y = VBA.Mid(bv, 23, 1) & VBA.Mid(bv, 24, 1) & VBA.Mid(bv, 20, 1)
x = CStr(VBA.Round(1.5 * CLng("&H" & x & "0")) - 50000)
y = CStr(VBA.Round(1.5 * CLng("&H" & y & "0")) - 50000)
If VBA.Abs(CLng(x)) >= 32767 Then
If VBA.Abs(CLng(x)) = CLng(x) Then
x = CStr(32767)
Else
x = CStr(-32767)
End If
End If
If VBA.Abs(CLng(y)) >= 32767 Then
If VBA.Abs(CLng(y)) = CLng(y) Then
y = CStr(32767)
Else
y = CStr(-32767)
End If
End If
If accel_x <> 0 And accel_y <> 0 And accel_z <> 0 And gyro_1 <> 0 And gyro_2 <> 0 And gyro_3 <> 0 Then
If VBA.Left(bv, 2) = "21" Then
bys = Split(bv2, " ")
ss = "(Firmware Version: " & bys(15) & "." & bys(16) & ") " & "(JoyCon: " & bys(17) & ") "
ss = ss & "(MAC address: " & bys(19) & bys(20) & bys(21) & bys(22) & bys(23) & bys(24)
Else
imu = "IMU 6-axis Mode: " & "(Accel X: " & CStr(accel_x) & ") (Accel Y: " & CStr(accel_y) & ") (Accel Z: " & CStr(accel_z) & ") (Gyro 1: " & CStr(gyro_1) & ") (Gyro 2: " & CStr(gyro_2) & ") (Gyro 3: " & CStr(gyro_3) & ")"
End If
End If
bv = "(JoyCon R) (Input Mode: " & VBA.Left(bv, 2) & ") (Packet: " & VBA.Mid(bv, 3, 2) & ") (Battery: " & VBA.Mid(bv, 5, 1) & ") (Connection:" & VBA.Mid(bv, 6, 1) & ") (Buttons: " & VBA.Mid(bv, 7, 4) & ") (X,Y: " & x & "," & y & ") (L/R: " & VBA.Mid(bv, 25, 1) & "/" & VBA.Mid(bv, 26, 1) & ")"
If ss <> "" Then bv = ss & " " & bv
If imu <> "" Then bv = imu & " " & bv
bv = bv & " (Raw: " & bv2 & ")"
End If
End If
RaiseEvent ReadReportResult(bv)
End Sub
Public Function ProductIdJoyConLeft() As Long
ProductIdJoyConLeft = productIdJoyConL
End Function
Public Function ProductIdJoyConRight() As Long
ProductIdJoyConRight = productIdJoyConR
End Function
Public Sub EnablePoll()
tmrPoll.Enabled = True
End Sub
Public Sub DisablePoll()
tmrPoll.Enabled = False
End Sub
Public Sub EnableFindDevices()
tmrFindDevices.Enabled = True
End Sub
Public Sub DisableFindDevices()
tmrFindDevices.Enabled = False
End Sub
Private Function GetDataString(ByRef Address As Long, Bytes As Long) As String
Dim offset As Integer
Dim ret As String
Dim ThisByte As Byte
For offset = 0 To Bytes - 1
apiRtlMoveMemoryLongLong ByVal VarPtr(ThisByte), ByVal Address + offset, 1
If (ThisByte And &HF0) = 0 Then
ret = ret & "0"
End If
ret = ret & VBA.Hex$(ThisByte) & " "
Next
GetDataString = ret
End Function
Private Function GetStringFromLP(ByVal SPtr As Long) As String
Dim b As Byte
Dim txt As String
Do
apiCopyMemoryBYTELONG b, SPtr, 1 ' Get the byte/character that StrPtr is pointing to.
If b = 0 Then Exit Do ' If you've found a null character, then you're done.
txt = txt & VBA.Chr(b) ' Get the character for the byte's value'Add it to the string
SPtr = SPtr + 1 ' Increment the pointer to next byte/char
Loop
GetStringFromLP = txt
End Function
Public Function PtrToStringA(ByRef lpszA As Long) As String
If lpszA = 0 Then Exit Function
Dim nLen As Long
nLen = apilstrlenA(ByVal lpszA)
If nLen = 0 Then Exit Function
Dim buff() As Byte
ReDim buff(0 To (nLen - 1)) As Byte
apiCopyMemoryByteLongLong buff(0), lpszA, nLen
PtrToStringA = StrConv(buff, vbUnicode)
End Function
Public Function PtrToStringW(ByRef lpszW As Long) As String
Dim s As String
Const CP_ACP As Long = 0&
s = String$(apilstrlenW(ByVal lpszW) * 2&, vbNullChar)
apiWideCharToMultiByte CP_ACP, 0&, ByVal lpszW, -1, ByVal s, Len(s), 0&, 0&
PtrToStringW = Left$(s, apilstrlenW(StrPtr(s)))
End Function
Private Function ConvertByteToBit(ByRef byt As Byte) As String
'Bit == 32103210
'&HF0 == "11110000"
'&H0A == "00001010"
Dim e As Integer
Dim z As Integer
Dim valbyte As Integer
Dim bit As String
valbyte = VBA.Val(CStr(byt))
For e = 0 To 7
z = 2 ^ e
If valbyte And z Then
bit = "1" & bit
Else
bit = "0" & bit
End If
Next
ConvertByteToBit = bit
End Function
Function RShift(ByVal lNum As Long, ByVal lBits As Long) As Long
If lBits <= 0 Then RShift = lNum
If (lBits <= 0) Or (lBits > 31) Then Exit Function
RShift = (lNum And (2 ^ (31 - lBits) - 1)) * IIf(lBits = 31, &H80000000, 2 ^ lBits) Or IIf((lNum And 2 ^ (31 - lBits)) = 2 ^ (31 - lBits), &H80000000, 0)
End Function
Function LShift(ByVal lNum As Long, ByVal lBits As Long) As Long
If lBits <= 0 Then LShift = lNum
If (lBits <= 0) Or (lBits > 31) Then Exit Function
If lNum < 0 Then
LShift = (lNum And &H7FFFFFFF) \ (2 ^ lBits) Or 2 ^ (31 - lBits)
Else
LShift = lNum \ (2 ^ lBits)
End If
End Function
Property Get LoWord(dwNum As Long) As Integer
LoWord = dwNum And &HFFFF
End Property
Property Let LoWord(dwNum As Long, ByVal wNewWord As Integer)
dwNum = dwNum And &HFFFF0000 Or wNewWord
End Property
Property Get HiWord(dwNum As Long) As Integer
HiWord = ((dwNum And IIf(dwNum < 0, &H7FFF0000, &HFFFF0000)) \ &H10000) Or (-(dwNum < 0) * &H8000)
End Property
Property Let HiWord(dwNum As Long, ByVal wNewWord As Integer)
dwNum = dwNum And &HFFFF& Or IIf(wNewWord < 0, ((wNewWord And &H7FFF) * &H10000) Or &H80000000, wNewWord * &H10000)
End Property
Function GetLoByte(ByVal wNum As Integer) As Byte
GetLoByte = wNum And &HFF
End Function
'Function SetLoByte(wNum As Integer, ByVal btNewByte As Byte)
' wNum = wNum And &HFF00 Or btNewByte
'End Function
Function GetHiByte(ByVal wNum As Integer) As Byte
GetHiByte = (wNum And &HFF00&) \ &H100
End Function
Property Let HiByte(wNum As Integer, ByVal btNewByte As Byte)
wNum = wNum And &HFF Or (btNewByte * &H100&)
End Property
'' 3F mode
''Left Joycon bits
''1 SL1
''2 SR1
''01 Dpad Left
''02 Dpad Down
''04 Dpad Up
''08 Dpad Right
''002 View
''004 Left Shoulder Bumper
''008 Left Trigger
''0000 None (buttons)
''0001 Minus
''0004 Left Stick
''000000 Thumb Left
''000001 Thumb Up Left
''000002 Thumb Up
''000003 Thumb Up Right
''000004 Thumb Right
''000005 Thumb Down Right
''000006 Thumb Down
''000007 Thumb Down Left
''000008 Thumb Dead Zone
''_________________________________________
''Right Joycon
''1 SL2
''2 SR2
''01 B
''02 Y
''04 A
''08 X
''001 Menu
''004 Right Shoulder Bumper
''008 Right Trigger
''0000 None (buttons)
''0002 Plus
''0008 Right Stick
''000000 Thumb Right
''000001 Thumb Down Right
''000002 Thumb Down
''000003 Thumb Down Left
''000004 Thumb Left
''000005 Thumb Up Left
''000006 Thumb Up
''000007 Thumb Up Right
''000008 Thumb Dead Zone
'
''Private Const HIDP_LINK_COLLECTION_ROOT As Integer = (-1)
''Private Const HIDP_LINK_COLLECTION_UNSPECIFIED As Integer = (0)
''Private Const HIDP_STATUS_SUCCESS = &H110000
''Private Const HIDP_STATUS_NULL = &H80110001
''Private Const HIDP_STATUS_INVALID_PREPARSED_DATA = &HC0110001
''Private Const HIDP_STATUS_INVALID_REPORT_TYPE = &HC0110002
''Private Const HIDP_STATUS_INVALID_REPORT_LENGTH = &HC0110003
''Private Const HIDP_STATUS_USAGE_NOT_FOUND = &HC0110004
''Private Const HIDP_STATUS_VALUE_OUT_OF_RANGE = &HC0110005
''Private Const HIDP_STATUS_BAD_LOG_PHY_VALUES = &HC0110006
''Private Const HIDP_STATUS_BUFFER_TOO_SMALL = &HC0110007
''Private Const HIDP_STATUS_INTERNAL_ERROR = &HC0110008
''Private Const HIDP_STATUS_I8042_TRANS_UNKNOWN = &HC0110009
''Private Const HIDP_STATUS_INCOMPATIBLE_REPORT_ID = &HC011000A
''Private Const HIDP_STATUS_NOT_VALUE_ARRAY = &HC011000B
''Private Const HIDP_STATUS_IS_VALUE_ARRAY = &HC011000C
''Private Const HIDP_STATUS_DATA_INDEX_NOT_FOUND = &HC011000D
''Private Const HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE = &HC011000E
''Private Const HIDP_STATUS_BUTTON_NOT_PRESSED = &HC011000F
''Private Const HIDP_STATUS_REPORT_DOES_NOT_EXIST = &HC0110010
''Private Const HIDP_STATUS_NOT_IMPLEMENTED = &HC0110020
''Private Const HIDP_STATUS_NOT_BUTTON_ARRAY = &HC0110021
''Private Const DIGCF_ALLCLASSES As Long = &H4
''Private Const DIGCF_PROFILE As Long = &H8
''Private Type HIDP_BUTTON_CAPS
'' UsagePage As Integer
'' ReportID As Byte
'' IsAlias As Byte
'' BitField As Integer
'' LinkCollection As Integer
'' LinkUsage As Integer
'' LinkUsagePage As Integer
'' IsRange As Byte
'' IsStringRange As Byte
'' IsDesignatorRange As Byte
'' IsAbsolute As Byte
'' ReportCount As Integer
'' Reserved2 As Integer
'' reserved(0 To 8) As Long
'' UsageOrUsageMin As Integer
'' UsageMax As Integer
'' StringMinOrIndex As Integer
'' StringMax As Integer
'' DesignatorMinOrIndex As Integer
'' DesignatorMax As Integer
'' DataIndexMinOrIndex As Integer