1
+ import 'dart:convert' ;
2
+ import 'dart:ffi' ;
3
+ import 'dart:typed_data' ;
4
+
5
+ import 'package:ffi/ffi.dart' ;
6
+ import 'package:win32/win32.dart' ;
7
+
8
+ import 'logic_conf_interface.dart' ;
9
+ import 'windows/hidsdi.dart' as hid;
10
+ import 'windows/setupapi.dart' as sp;
11
+
12
+ class LogicConfWindows extends LogicConfPlatform {
13
+ var _devHandle = INVALID_HANDLE_VALUE ;
14
+
15
+ final _setupapi = sp.SetupAPI (DynamicLibrary .open ('setupapi.dll' ));
16
+
17
+ final _hidSdi = hid.HidSdi (DynamicLibrary .open ('hid.dll' ));
18
+
19
+ @override
20
+ List <dynamic > listDevices () {
21
+ var hidInterfaceClassGuid = calloc <GUID >()
22
+ ..ref.setGUID ('{4D1E55B2-F16F-11CF-88CB-001111000030}' );
23
+
24
+ var deviceInfoSetPtr = _setupapi.SetupDiGetClassDevsW (
25
+ hidInterfaceClassGuid.cast (),
26
+ nullptr,
27
+ nullptr,
28
+ sp.DIGCF_PRESENT | sp.DIGCF_DEVICEINTERFACE ,
29
+ );
30
+
31
+ var deviceList = _iterateDevice (deviceInfoSetPtr, hidInterfaceClassGuid).toList ();
32
+
33
+ _setupapi.SetupDiDestroyDeviceInfoList (deviceInfoSetPtr);
34
+ calloc.free (hidInterfaceClassGuid);
35
+ return deviceList;
36
+ }
37
+
38
+ Iterable <Map <String , dynamic >> _iterateDevice (Pointer <Void > deviceInfoSetPtr, Pointer <GUID > hidInterfaceClassGuid) sync * {
39
+ var requiredSizePtr = calloc <Uint32 >();
40
+ var devicInterfaceDataPtr = calloc< sp.SP_DEVICE_INTERFACE_DATA > ();
41
+ devicInterfaceDataPtr.ref.cbSize = sizeOf< sp.SP_DEVICE_INTERFACE_DATA > ();
42
+
43
+ for (var index = 0 ; _setupapi.SetupDiEnumDeviceInterfaces (deviceInfoSetPtr, nullptr, hidInterfaceClassGuid.cast (), index, devicInterfaceDataPtr) == TRUE ; index++ ) {
44
+ // Get requiredSize
45
+ _setupapi.SetupDiGetDeviceInterfaceDetailW (deviceInfoSetPtr, devicInterfaceDataPtr, nullptr, 0 , requiredSizePtr, nullptr);
46
+
47
+ var detailDataMemoryPtr = calloc <Uint16 >(requiredSizePtr.value);
48
+ var devHandle = INVALID_HANDLE_VALUE ;
49
+
50
+ try {
51
+ var deviceInterfaceDetailDataPtr = Pointer <sp.SP_DEVICE_INTERFACE_DETAIL_DATA_W >.fromAddress (detailDataMemoryPtr.address);
52
+ deviceInterfaceDetailDataPtr.ref.cbSize = sizeOf< sp.SP_DEVICE_INTERFACE_DETAIL_DATA_W > ();
53
+
54
+ var getDeviceInterfaceDetail = _setupapi.SetupDiGetDeviceInterfaceDetailW (deviceInfoSetPtr, devicInterfaceDataPtr, deviceInterfaceDetailDataPtr, requiredSizePtr.value, nullptr, nullptr);
55
+ if (getDeviceInterfaceDetail != TRUE ) {
56
+ print ('SetupDiGetDeviceInterfaceDetailW error ${GetLastError ()}' );
57
+ continue ;
58
+ }
59
+ // FIXME Utf16.decode
60
+ var devicePath = utf8.decode (deviceInterfaceDetailDataPtr.getDevicePathData (requiredSizePtr.value));
61
+
62
+ devHandle = CreateFile (devicePath.toNativeUtf16 (), 0 , FILE_SHARE_READ | FILE_SHARE_WRITE , nullptr, OPEN_EXISTING , 0 , NULL );
63
+ if (devHandle == INVALID_HANDLE_VALUE ) {
64
+ print ('CreateFile error ${GetLastError ()}' );
65
+ continue ;
66
+ }
67
+ var devHandlePtr = Pointer <Void >.fromAddress (devHandle);
68
+
69
+ yield {
70
+ 'path' : devicePath,
71
+ ..._getAttributes (devHandlePtr),
72
+ ..._getPreparsedData (devHandlePtr),
73
+ };
74
+ } finally {
75
+ calloc.free (detailDataMemoryPtr);
76
+ if (devHandle != INVALID_HANDLE_VALUE ) {
77
+ CloseHandle (devHandle);
78
+ }
79
+ }
80
+ }
81
+
82
+ calloc.free (requiredSizePtr);
83
+ calloc.free (devicInterfaceDataPtr);
84
+ }
85
+
86
+ Map <String , dynamic > _getAttributes (Pointer <Void > devHandlePtr) {
87
+ var res = < String , dynamic > {};
88
+
89
+ var attributesPtr = calloc< hid.HIDD_ATTRIBUTES > ();
90
+ if (_hidSdi.HidD_GetAttributes (devHandlePtr, attributesPtr) == TRUE ) {
91
+ res = {
92
+ 'vendorId' : attributesPtr.ref.VendorID ,
93
+ 'productId' : attributesPtr.ref.ProductID ,
94
+ };
95
+ } else {
96
+ print ('HidD_GetAttributes error ${GetLastError ()}' );
97
+ }
98
+ calloc.free (attributesPtr);
99
+
100
+ return res;
101
+ }
102
+
103
+ Map <String , dynamic > _getPreparsedData (Pointer <Void > devHandlePtr) {
104
+ var res = < String , dynamic > {};
105
+
106
+ var preparsedDataRefPtr = calloc< Pointer <hid.HIDP_PREPARSED_DATA >> ();
107
+ if (_hidSdi.HidD_GetPreparsedData (devHandlePtr, preparsedDataRefPtr) == TRUE ) {
108
+ var capsPtr = calloc< hid.HIDP_CAPS > ();
109
+ var getCaps = _hidSdi.HidP_GetCaps (preparsedDataRefPtr.value, capsPtr);
110
+ if (getCaps == hid.HIDP_STATUS_SUCCESS ) {
111
+ res = {
112
+ 'usagePage' : capsPtr.ref.UsagePage ,
113
+ 'usage' : capsPtr.ref.Usage ,
114
+ };
115
+ } else {
116
+ print ('HidP_GetCaps error $getCaps ' );
117
+ }
118
+ calloc.free (capsPtr);
119
+ _hidSdi.HidD_FreePreparsedData (preparsedDataRefPtr.value);
120
+ }
121
+ calloc.free (preparsedDataRefPtr);
122
+
123
+ return res;
124
+ }
125
+
126
+ @override
127
+ bool openDevice (String path) {
128
+ _devHandle = CreateFile (
129
+ path.toNativeUtf16 (),
130
+ GENERIC_READ | GENERIC_WRITE ,
131
+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
132
+ nullptr,
133
+ OPEN_EXISTING ,
134
+ 0 ,
135
+ NULL ,
136
+ );
137
+ return _devHandle != INVALID_HANDLE_VALUE ;
138
+ }
139
+
140
+ @override
141
+ void closeDevice () {
142
+ if (_devHandle != INVALID_HANDLE_VALUE ) {
143
+ CloseHandle (_devHandle);
144
+ }
145
+ }
146
+
147
+ @override
148
+ int sendData (Uint8List data) {
149
+ var dataPtr = calloc <Uint8 >(data.length);
150
+ dataPtr.asTypedList (data.length).setAll (0 , data);
151
+ var writtenLengthPtr = calloc <Uint32 >();
152
+ try {
153
+ var writeFile = WriteFile (_devHandle, dataPtr, data.length, writtenLengthPtr, nullptr);
154
+ if (writeFile != TRUE ) {
155
+ return - 1 ;
156
+ }
157
+ return writtenLengthPtr.value;
158
+ } finally {
159
+ calloc.free (dataPtr);
160
+ calloc.free (writtenLengthPtr);
161
+ }
162
+ }
163
+ }
164
+
165
+ extension Pointer_SP_DEVICE_INTERFACE_DETAIL_DATA_W on Pointer <sp.SP_DEVICE_INTERFACE_DETAIL_DATA_W > {
166
+ Uint16List getDevicePathData (int requiredSize) => Pointer <Uint16 >.fromAddress (address).asTypedList (requiredSize).sublist (2 );
167
+ }
0 commit comments