├── HidSample.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── alexander.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── HidSample.xcscheme
└── project.pbxproj
├── HidSample
├── HidSample-Prefix.pch
├── HidSample.1
├── HidUtils.h
└── main.m
└── config.h
/HidSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HidSample/HidSample-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #ifdef __OBJC__
8 | #import
9 | #endif
10 |
--------------------------------------------------------------------------------
/config.h:
--------------------------------------------------------------------------------
1 | //
2 | // config.h
3 | // HidSample
4 | //
5 | // Created by Alexander Tarasikov on 23.11.13.
6 | // Copyright (c) 2013 Alexander Tarasikov. All rights reserved.
7 | //
8 |
9 | #ifndef HidSample_config_h
10 | #define HidSample_config_h
11 |
12 | #define TOUCH_REPORT 1
13 |
14 | #define NUM_TOUCHES 1
15 |
16 | #define TOUCH_VID 0x596
17 | #define TOUCH_PID 0x524
18 |
19 | #define SCREEN_RESX 1920
20 | #define SCREEN_RESY 1080
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/HidSample.xcodeproj/xcuserdata/alexander.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | HidSample.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 113F64D5183E93B20041DE1B
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/HidSample/HidSample.1:
--------------------------------------------------------------------------------
1 | .\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
2 | .\"See Also:
3 | .\"man mdoc.samples for a complete listing of options
4 | .\"man mdoc for the short list of editing options
5 | .\"/usr/share/misc/mdoc.template
6 | .Dd 21.11.13 \" DATE
7 | .Dt HidSample 1 \" Program name and manual section number
8 | .Os Darwin
9 | .Sh NAME \" Section Header - required - don't modify
10 | .Nm HidSample,
11 | .\" The following lines are read in generating the apropos(man -k) database. Use only key
12 | .\" words here as the database is built based on the words here and in the .ND line.
13 | .Nm Other_name_for_same_program(),
14 | .Nm Yet another name for the same program.
15 | .\" Use .Nm macro to designate other names for the documented program.
16 | .Nd This line parsed for whatis database.
17 | .Sh SYNOPSIS \" Section Header - required - don't modify
18 | .Nm
19 | .Op Fl abcd \" [-abcd]
20 | .Op Fl a Ar path \" [-a path]
21 | .Op Ar file \" [file]
22 | .Op Ar \" [file ...]
23 | .Ar arg0 \" Underlined argument - use .Ar anywhere to underline
24 | arg2 ... \" Arguments
25 | .Sh DESCRIPTION \" Section Header - required - don't modify
26 | Use the .Nm macro to refer to your program throughout the man page like such:
27 | .Nm
28 | Underlining is accomplished with the .Ar macro like this:
29 | .Ar underlined text .
30 | .Pp \" Inserts a space
31 | A list of items with descriptions:
32 | .Bl -tag -width -indent \" Begins a tagged list
33 | .It item a \" Each item preceded by .It macro
34 | Description of item a
35 | .It item b
36 | Description of item b
37 | .El \" Ends the list
38 | .Pp
39 | A list of flags and their descriptions:
40 | .Bl -tag -width -indent \" Differs from above in tag removed
41 | .It Fl a \"-a flag as a list item
42 | Description of -a flag
43 | .It Fl b
44 | Description of -b flag
45 | .El \" Ends the list
46 | .Pp
47 | .\" .Sh ENVIRONMENT \" May not be needed
48 | .\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
49 | .\" .It Ev ENV_VAR_1
50 | .\" Description of ENV_VAR_1
51 | .\" .It Ev ENV_VAR_2
52 | .\" Description of ENV_VAR_2
53 | .\" .El
54 | .Sh FILES \" File used or created by the topic of the man page
55 | .Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
56 | .It Pa /usr/share/file_name
57 | FILE_1 description
58 | .It Pa /Users/joeuser/Library/really_long_file_name
59 | FILE_2 description
60 | .El \" Ends the list
61 | .\" .Sh DIAGNOSTICS \" May not be needed
62 | .\" .Bl -diag
63 | .\" .It Diagnostic Tag
64 | .\" Diagnostic informtion here.
65 | .\" .It Diagnostic Tag
66 | .\" Diagnostic informtion here.
67 | .\" .El
68 | .Sh SEE ALSO
69 | .\" List links in ascending order by section, alphabetically within a section.
70 | .\" Please do not reference files that do not exist without filing a bug report
71 | .Xr a 1 ,
72 | .Xr b 1 ,
73 | .Xr c 1 ,
74 | .Xr a 2 ,
75 | .Xr b 2 ,
76 | .Xr a 3 ,
77 | .Xr b 3
78 | .\" .Sh BUGS \" Document known, unremedied bugs
79 | .\" .Sh HISTORY \" Document history if command behaves in a unique manner
--------------------------------------------------------------------------------
/HidSample.xcodeproj/xcuserdata/alexander.xcuserdatad/xcschemes/HidSample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/HidSample/HidUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // HidUtils.h
3 | // HidSample
4 | //
5 | // Created by Alexander Tarasikov on 23.11.13.
6 | // Copyright (c) 2013 Alexander Tarasikov. All rights reserved.
7 | //
8 |
9 | #ifndef HidSample_HidUtils_h
10 | #define HidSample_HidUtils_h
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include "config.h"
20 |
21 | typedef enum CalibrationState {
22 | kCalibrationStateInactive = 0,
23 | kCalibrationStateTopLeft,
24 | kCalibrationStateTopRight,
25 | kCalibrationStateBottomRight,
26 | kCalibrationStateBottomLeft
27 | } CalibrationState;
28 |
29 | typedef struct HIDData
30 | {
31 | io_object_t notification;
32 | IOHIDDeviceInterface122 ** hidDeviceInterface;
33 | IOHIDQueueInterface ** hidQueueInterface;
34 | CFDictionaryRef hidElementDictionary;
35 | CFRunLoopSourceRef eventSource;
36 | CalibrationState state;
37 | SInt32 minx;
38 | SInt32 maxx;
39 | SInt32 miny;
40 | SInt32 maxy;
41 | UInt8 buffer[256];
42 | } HIDData;
43 |
44 | typedef HIDData * HIDDataRef;
45 |
46 | typedef struct HIDElement {
47 | SInt32 currentValue;
48 | SInt32 usagePage;
49 | SInt32 usage;
50 | IOHIDElementType type;
51 | IOHIDElementCookie cookie;
52 | HIDDataRef owner;
53 | }HIDElement;
54 | typedef HIDElement * HIDElementRef;
55 |
56 | static const char *translateHIDType(IOHIDElementType type) {
57 | switch (type) {
58 | case 1:
59 | return "MISC";
60 | case 2:
61 | return "Button";
62 | case 3:
63 | return "Axis";
64 | case 4:
65 | return "ScanCodes";
66 | case 129:
67 | return "Output";
68 | case 257:
69 | return "Feature";
70 | case 513:
71 | return "Collection";
72 |
73 | default:
74 | return "unknown";
75 | break;
76 | }
77 | };
78 |
79 | static void printHidElement(const char *fname, HIDElement *element) {
80 | if (!element) {
81 | return;
82 | }
83 |
84 | const char *hidType = translateHIDType(element->type);
85 | const char *hidUsage = "unknown";
86 |
87 | #define USAGE(__page, __usage, name) do {\
88 | if (element->usagePage == __page && element->usage == __usage) {\
89 | hidUsage = name;\
90 | break;\
91 | } \
92 | } while (0)
93 |
94 | do {
95 | USAGE(0x1, 0x30, "X");
96 | USAGE(0x1, 0x31, "Y");
97 | USAGE(0xd, kHIDUsage_Dig_TouchScreen, "Touchscreen");
98 | USAGE(0xd, 0x1, "Digitizer");
99 | USAGE(0xd, 2, "Pen");
100 | USAGE(0xd, 0x3, "Config");
101 | USAGE(0xd, 0x20, "stylus");
102 | USAGE(0xd, 0x22, "finger");
103 | USAGE(0xd, 0x23, "DevSettings");
104 | USAGE(0xd, 0x30, "pressure");
105 | USAGE(0xd, 0x32, "InRange");
106 | USAGE(0xd, kHIDUsage_Dig_Touch, "Touch");
107 | USAGE(0xd, 0x3c, "Invert");
108 | USAGE(0xd, 0x3f, "Azimuth");
109 | USAGE(0xd, 0x42, "TipSwitch");
110 | USAGE(0xd, 0x47, "Confidence");
111 | USAGE(0xd, 0x48, "MT Widght");
112 | USAGE(0xd, 0x49, "MT Height");
113 | USAGE(0xd, 0x51, "ContactID");
114 | USAGE(0xd, 0x53, "DevIndex");
115 | USAGE(0xd, 0x54, "TouchCount");
116 | USAGE(0xd, 0x55, "Contact Count Maximum");
117 | USAGE(0xd, 0x56, "ScanTime");
118 | } while (0);
119 |
120 | #undef USAGE
121 |
122 | #if TOUCH_REPORT
123 | printf("[%s]: <%x:%x> [%s] %s=0x%x (%d)\n",
124 | fname ? fname : "unknown",
125 | element->usagePage, element->usage,
126 | hidType,
127 | hidUsage,
128 | element->currentValue,
129 | element->currentValue);
130 | fflush(stdout);
131 | #endif
132 | }
133 |
134 | #endif
135 |
--------------------------------------------------------------------------------
/HidSample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 113D4CE0183FFFC30051122B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D4CDF183FFFC30051122B /* CoreFoundation.framework */; };
11 | 113D4CE2183FFFC60051122B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D4CE1183FFFC60051122B /* IOKit.framework */; };
12 | 113D4CE4184000800051122B /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113D4CE3184000800051122B /* ApplicationServices.framework */; };
13 | 113F64DA183E93B20041DE1B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 113F64D9183E93B20041DE1B /* Foundation.framework */; };
14 | 113F64DD183E93B20041DE1B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 113F64DC183E93B20041DE1B /* main.m */; };
15 | 113F64E1183E93B20041DE1B /* HidSample.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 113F64E0183E93B20041DE1B /* HidSample.1 */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 113F64D4183E93B20041DE1B /* CopyFiles */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = /usr/share/man/man1/;
23 | dstSubfolderSpec = 0;
24 | files = (
25 | 113F64E1183E93B20041DE1B /* HidSample.1 in CopyFiles */,
26 | );
27 | runOnlyForDeploymentPostprocessing = 1;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 113D4CDF183FFFC30051122B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
33 | 113D4CE1183FFFC60051122B /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
34 | 113D4CE3184000800051122B /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; };
35 | 113D4CE51840DF7A0051122B /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../config.h; sourceTree = ""; };
36 | 113D4CE61840E8600051122B /* HidUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HidUtils.h; sourceTree = ""; };
37 | 113D4CE71842AE330051122B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
38 | 113F64D6183E93B20041DE1B /* HidSample */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = HidSample; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 113F64D9183E93B20041DE1B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
40 | 113F64DC183E93B20041DE1B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
41 | 113F64DF183E93B20041DE1B /* HidSample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HidSample-Prefix.pch"; sourceTree = ""; };
42 | 113F64E0183E93B20041DE1B /* HidSample.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = HidSample.1; sourceTree = ""; };
43 | /* End PBXFileReference section */
44 |
45 | /* Begin PBXFrameworksBuildPhase section */
46 | 113F64D3183E93B20041DE1B /* Frameworks */ = {
47 | isa = PBXFrameworksBuildPhase;
48 | buildActionMask = 2147483647;
49 | files = (
50 | 113D4CE4184000800051122B /* ApplicationServices.framework in Frameworks */,
51 | 113D4CE2183FFFC60051122B /* IOKit.framework in Frameworks */,
52 | 113D4CE0183FFFC30051122B /* CoreFoundation.framework in Frameworks */,
53 | 113F64DA183E93B20041DE1B /* Foundation.framework in Frameworks */,
54 | );
55 | runOnlyForDeploymentPostprocessing = 0;
56 | };
57 | /* End PBXFrameworksBuildPhase section */
58 |
59 | /* Begin PBXGroup section */
60 | 113F64CD183E93B20041DE1B = {
61 | isa = PBXGroup;
62 | children = (
63 | 113F64DB183E93B20041DE1B /* HidSample */,
64 | 113F64D8183E93B20041DE1B /* Frameworks */,
65 | 113F64D7183E93B20041DE1B /* Products */,
66 | );
67 | sourceTree = "";
68 | };
69 | 113F64D7183E93B20041DE1B /* Products */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 113F64D6183E93B20041DE1B /* HidSample */,
73 | );
74 | name = Products;
75 | sourceTree = "";
76 | };
77 | 113F64D8183E93B20041DE1B /* Frameworks */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 113D4CE71842AE330051122B /* Cocoa.framework */,
81 | 113D4CE3184000800051122B /* ApplicationServices.framework */,
82 | 113D4CE1183FFFC60051122B /* IOKit.framework */,
83 | 113D4CDF183FFFC30051122B /* CoreFoundation.framework */,
84 | 113F64D9183E93B20041DE1B /* Foundation.framework */,
85 | );
86 | name = Frameworks;
87 | sourceTree = "";
88 | };
89 | 113F64DB183E93B20041DE1B /* HidSample */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 113D4CE51840DF7A0051122B /* config.h */,
93 | 113D4CE61840E8600051122B /* HidUtils.h */,
94 | 113F64DC183E93B20041DE1B /* main.m */,
95 | 113F64E0183E93B20041DE1B /* HidSample.1 */,
96 | 113F64DE183E93B20041DE1B /* Supporting Files */,
97 | );
98 | path = HidSample;
99 | sourceTree = "";
100 | };
101 | 113F64DE183E93B20041DE1B /* Supporting Files */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 113F64DF183E93B20041DE1B /* HidSample-Prefix.pch */,
105 | );
106 | name = "Supporting Files";
107 | sourceTree = "";
108 | };
109 | /* End PBXGroup section */
110 |
111 | /* Begin PBXNativeTarget section */
112 | 113F64D5183E93B20041DE1B /* HidSample */ = {
113 | isa = PBXNativeTarget;
114 | buildConfigurationList = 113F64E4183E93B20041DE1B /* Build configuration list for PBXNativeTarget "HidSample" */;
115 | buildPhases = (
116 | 113F64D2183E93B20041DE1B /* Sources */,
117 | 113F64D3183E93B20041DE1B /* Frameworks */,
118 | 113F64D4183E93B20041DE1B /* CopyFiles */,
119 | );
120 | buildRules = (
121 | );
122 | dependencies = (
123 | );
124 | name = HidSample;
125 | productName = HidSample;
126 | productReference = 113F64D6183E93B20041DE1B /* HidSample */;
127 | productType = "com.apple.product-type.tool";
128 | };
129 | /* End PBXNativeTarget section */
130 |
131 | /* Begin PBXProject section */
132 | 113F64CE183E93B20041DE1B /* Project object */ = {
133 | isa = PBXProject;
134 | attributes = {
135 | LastUpgradeCheck = 0500;
136 | ORGANIZATIONNAME = "Alexander Tarasikov";
137 | };
138 | buildConfigurationList = 113F64D1183E93B20041DE1B /* Build configuration list for PBXProject "HidSample" */;
139 | compatibilityVersion = "Xcode 3.2";
140 | developmentRegion = English;
141 | hasScannedForEncodings = 0;
142 | knownRegions = (
143 | en,
144 | );
145 | mainGroup = 113F64CD183E93B20041DE1B;
146 | productRefGroup = 113F64D7183E93B20041DE1B /* Products */;
147 | projectDirPath = "";
148 | projectRoot = "";
149 | targets = (
150 | 113F64D5183E93B20041DE1B /* HidSample */,
151 | );
152 | };
153 | /* End PBXProject section */
154 |
155 | /* Begin PBXSourcesBuildPhase section */
156 | 113F64D2183E93B20041DE1B /* Sources */ = {
157 | isa = PBXSourcesBuildPhase;
158 | buildActionMask = 2147483647;
159 | files = (
160 | 113F64DD183E93B20041DE1B /* main.m in Sources */,
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXSourcesBuildPhase section */
165 |
166 | /* Begin XCBuildConfiguration section */
167 | 113F64E2183E93B20041DE1B /* Debug */ = {
168 | isa = XCBuildConfiguration;
169 | buildSettings = {
170 | ALWAYS_SEARCH_USER_PATHS = NO;
171 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
172 | CLANG_CXX_LIBRARY = "libc++";
173 | CLANG_ENABLE_OBJC_ARC = YES;
174 | CLANG_WARN_BOOL_CONVERSION = YES;
175 | CLANG_WARN_CONSTANT_CONVERSION = YES;
176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
177 | CLANG_WARN_EMPTY_BODY = YES;
178 | CLANG_WARN_ENUM_CONVERSION = YES;
179 | CLANG_WARN_INT_CONVERSION = YES;
180 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
181 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
182 | COPY_PHASE_STRIP = NO;
183 | GCC_C_LANGUAGE_STANDARD = gnu99;
184 | GCC_DYNAMIC_NO_PIC = NO;
185 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
186 | GCC_OPTIMIZATION_LEVEL = 0;
187 | GCC_PREPROCESSOR_DEFINITIONS = (
188 | "DEBUG=1",
189 | "$(inherited)",
190 | );
191 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
192 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
193 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
194 | GCC_WARN_UNDECLARED_SELECTOR = YES;
195 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
196 | GCC_WARN_UNUSED_FUNCTION = YES;
197 | GCC_WARN_UNUSED_VARIABLE = YES;
198 | MACOSX_DEPLOYMENT_TARGET = 10.9;
199 | ONLY_ACTIVE_ARCH = YES;
200 | SDKROOT = macosx;
201 | };
202 | name = Debug;
203 | };
204 | 113F64E3183E93B20041DE1B /* Release */ = {
205 | isa = XCBuildConfiguration;
206 | buildSettings = {
207 | ALWAYS_SEARCH_USER_PATHS = NO;
208 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
209 | CLANG_CXX_LIBRARY = "libc++";
210 | CLANG_ENABLE_OBJC_ARC = YES;
211 | CLANG_WARN_BOOL_CONVERSION = YES;
212 | CLANG_WARN_CONSTANT_CONVERSION = YES;
213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
214 | CLANG_WARN_EMPTY_BODY = YES;
215 | CLANG_WARN_ENUM_CONVERSION = YES;
216 | CLANG_WARN_INT_CONVERSION = YES;
217 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
218 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
219 | COPY_PHASE_STRIP = YES;
220 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
221 | ENABLE_NS_ASSERTIONS = NO;
222 | GCC_C_LANGUAGE_STANDARD = gnu99;
223 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
224 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
225 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
226 | GCC_WARN_UNDECLARED_SELECTOR = YES;
227 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
228 | GCC_WARN_UNUSED_FUNCTION = YES;
229 | GCC_WARN_UNUSED_VARIABLE = YES;
230 | MACOSX_DEPLOYMENT_TARGET = 10.9;
231 | SDKROOT = macosx;
232 | };
233 | name = Release;
234 | };
235 | 113F64E5183E93B20041DE1B /* Debug */ = {
236 | isa = XCBuildConfiguration;
237 | buildSettings = {
238 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
239 | GCC_PREFIX_HEADER = "HidSample/HidSample-Prefix.pch";
240 | PRODUCT_NAME = "$(TARGET_NAME)";
241 | SDKROOT = macosx10.8;
242 | };
243 | name = Debug;
244 | };
245 | 113F64E6183E93B20041DE1B /* Release */ = {
246 | isa = XCBuildConfiguration;
247 | buildSettings = {
248 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
249 | GCC_PREFIX_HEADER = "HidSample/HidSample-Prefix.pch";
250 | "INFOPLIST_FILE[sdk=macosx10.8]" = "";
251 | PRODUCT_NAME = "$(TARGET_NAME)";
252 | SDKROOT = macosx10.8;
253 | };
254 | name = Release;
255 | };
256 | /* End XCBuildConfiguration section */
257 |
258 | /* Begin XCConfigurationList section */
259 | 113F64D1183E93B20041DE1B /* Build configuration list for PBXProject "HidSample" */ = {
260 | isa = XCConfigurationList;
261 | buildConfigurations = (
262 | 113F64E2183E93B20041DE1B /* Debug */,
263 | 113F64E3183E93B20041DE1B /* Release */,
264 | );
265 | defaultConfigurationIsVisible = 0;
266 | defaultConfigurationName = Release;
267 | };
268 | 113F64E4183E93B20041DE1B /* Build configuration list for PBXNativeTarget "HidSample" */ = {
269 | isa = XCConfigurationList;
270 | buildConfigurations = (
271 | 113F64E5183E93B20041DE1B /* Debug */,
272 | 113F64E6183E93B20041DE1B /* Release */,
273 | );
274 | defaultConfigurationIsVisible = 0;
275 | defaultConfigurationName = Release;
276 | };
277 | /* End XCConfigurationList section */
278 | };
279 | rootObject = 113F64CE183E93B20041DE1B /* Project object */;
280 | }
281 |
--------------------------------------------------------------------------------
/HidSample/main.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 |
9 | #include "config.h"
10 | #include "HidUtils.h"
11 |
12 | //---------------------------------------------------------------------------
13 | // Globals
14 | //---------------------------------------------------------------------------
15 | static IONotificationPortRef gNotifyPort = NULL;
16 | static io_iterator_t gAddedIter = 0;
17 | static NSLock *gLock = 0;
18 |
19 | //---------------------------------------------------------------------------
20 | // TypeDefs
21 | //---------------------------------------------------------------------------
22 |
23 | typedef enum {
24 | UP,
25 | DOWN,
26 | NO_CHANGE,
27 | } ButtonState;
28 |
29 | static void simulateClick(int x, int y, ButtonState button) {
30 | printf("CLICK %d %d %d\n", x, y, button);
31 | static int eventNumber = 0;
32 | if (button == DOWN) {
33 | CGEventRef move = CGEventCreateMouseEvent(NULL,
34 | kCGEventLeftMouseDown,
35 | CGPointMake(x, y),
36 | kCGMouseButtonLeft);
37 | CGEventSetIntegerValueField(move, kCGMouseEventNumber, eventNumber);
38 | CGEventPost(kCGHIDEventTap, move);
39 | CFRelease(move);
40 | eventNumber++;
41 | }
42 | else if (button == UP) {
43 | CGEventRef move_up = CGEventCreateMouseEvent(NULL,
44 | kCGEventLeftMouseUp,
45 | CGPointMake(x, y),
46 | kCGMouseButtonLeft);
47 | CGEventSetIntegerValueField(move_up, kCGMouseEventNumber, eventNumber);
48 | CGEventPost(kCGHIDEventTap, move_up);
49 | CFRelease(move_up);
50 | //eventNumber++;
51 | }
52 | if (button == NO_CHANGE) {
53 | CGEventRef move = CGEventCreateMouseEvent(NULL,
54 | kCGEventLeftMouseDragged,
55 | CGPointMake(x, y),
56 | kCGMouseButtonLeft);
57 | CGEventSetIntegerValueField(move, kCGMouseEventNumber, eventNumber);
58 | CGEventPost(kCGHIDEventTap, move);
59 | CFRelease(move);
60 | //eventNumber++;
61 | }
62 | }
63 |
64 | static void submitTouch(int fingerId, int x, int y, ButtonState button) {
65 | printf("%s: <%d, %d> state=%d\n", __func__, x, y, button);
66 | static int last_x[NUM_TOUCHES] = {
67 | 0,
68 | };
69 | static int last_y[NUM_TOUCHES] = {
70 | 0,
71 | };
72 |
73 | if (button == DOWN || button == UP) {
74 | if (last_x[fingerId] >0 && last_y[fingerId] > 0) {
75 | printf("last <%d %d>\n", last_x[fingerId], last_y[fingerId]);
76 | simulateClick(last_x[fingerId], last_y[fingerId], button);
77 | last_x[fingerId] = last_y[fingerId] = -1;
78 | }
79 | }
80 | else {
81 | if (x > 0) {
82 | last_x[fingerId] = x;
83 | }
84 | if (y > 0) {
85 | last_y[fingerId] = y;
86 | }
87 | if (last_x[fingerId] > 0 && last_y[fingerId] > 0) {
88 | simulateClick(last_x[fingerId], last_y[fingerId], NO_CHANGE);
89 | }
90 | }
91 | }
92 |
93 | static bool acceptHidElement(HIDElement *element) {
94 | printHidElement("acceptHidElement", element);
95 |
96 | switch (element->usagePage) {
97 | case kHIDPage_GenericDesktop:
98 | switch (element->usage) {
99 | case kHIDUsage_GD_X:
100 | case kHIDUsage_GD_Y:
101 | return true;
102 | }
103 | break;
104 | case kHIDPage_Button:
105 | switch (element->usage) {
106 | case kHIDUsage_Button_1:
107 | return true;
108 | break;
109 | }
110 | break;
111 | case kHIDPage_Digitizer:
112 | return true;
113 | break;
114 | }
115 |
116 | return false;
117 | }
118 |
119 | static void reportHidElement(HIDElement *element) {
120 | if (!element) {
121 | return;
122 | }
123 |
124 | [gLock lock];
125 |
126 | printf("\n+++++++++++\n");
127 | printHidElement("report element", element);
128 | printf("------------\n");
129 |
130 | static int fingerId = 0;
131 | static ButtonState button = NO_CHANGE;
132 |
133 | //button
134 | if (element->type == 2) {
135 | button = element->currentValue ? DOWN : UP;
136 | submitTouch(fingerId, 0, 0, button);
137 | }
138 | else {
139 | button = NO_CHANGE;
140 | }
141 |
142 | if (element->usagePage == 0xd && element->usage == 0x22) {
143 | //fingerId = element->currentValue;
144 | }
145 |
146 | if (element->usagePage == 1 && element->currentValue < 0x10000) {
147 | float scale_x = SCREEN_RESX / 32768.0f;
148 | float scale_y = SCREEN_RESY / 32768.0f;
149 |
150 | short value = element->currentValue & 0xffff;
151 |
152 | if (element->usage == kHIDUsage_GD_X) {
153 | int x = (int)(value * scale_x);
154 | submitTouch(fingerId, x, 0, NO_CHANGE);
155 | }
156 | else if (element->usage == kHIDUsage_GD_Y) {
157 | int y = (int)(value * scale_y);
158 | submitTouch(fingerId, 0, y, NO_CHANGE);
159 | }
160 | }
161 |
162 | [gLock unlock];
163 | }
164 |
165 | #ifndef max
166 | #define max(a, b) \
167 | ((a > b) ? a:b)
168 | #endif
169 |
170 | #ifndef min
171 | #define min(a, b) \
172 | ((a < b) ? a:b)
173 | #endif
174 |
175 | //---------------------------------------------------------------------------
176 | // Methods
177 | //---------------------------------------------------------------------------
178 | static void InitHIDNotifications();
179 | static void HIDDeviceAdded(void *refCon, io_iterator_t iterator);
180 | static void DeviceNotification(void *refCon, io_service_t service, natural_t messageType, void *messageArgument);
181 | static bool FindHIDElements(HIDDataRef hidDataRef);
182 | static bool SetupQueue(HIDDataRef hidDataRef);
183 | static void QueueCallbackFunction(
184 | void * target,
185 | IOReturn result,
186 | void * refcon,
187 | void * sender);
188 |
189 | int main (int argc, const char * argv[]) {
190 | gLock = [[NSLock alloc] init];
191 | InitHIDNotifications(TOUCH_VID, TOUCH_PID);
192 | CFRunLoopRun();
193 |
194 | return 0;
195 | }
196 |
197 |
198 | //---------------------------------------------------------------------------
199 | // InitHIDNotifications
200 | //
201 | // This routine just creates our master port for IOKit and turns around
202 | // and calls the routine that will alert us when a HID Device is plugged in.
203 | //---------------------------------------------------------------------------
204 |
205 | static void InitHIDNotifications(SInt32 vendorID, SInt32 productID)
206 | {
207 | CFMutableDictionaryRef matchingDict;
208 | CFNumberRef refProdID;
209 | CFNumberRef refVendorID;
210 | mach_port_t masterPort;
211 | kern_return_t kr;
212 |
213 | // first create a master_port for my task
214 | //
215 | kr = IOMasterPort(bootstrap_port, &masterPort);
216 | if (kr || !masterPort)
217 | return;
218 |
219 | // Create a notification port and add its run loop event source to our run loop
220 | // This is how async notifications get set up.
221 | //
222 | gNotifyPort = IONotificationPortCreate(masterPort);
223 | CFRunLoopAddSource( CFRunLoopGetCurrent(),
224 | IONotificationPortGetRunLoopSource(gNotifyPort),
225 | kCFRunLoopDefaultMode);
226 |
227 | // Create the IOKit notifications that we need
228 | //
229 | /* Create a matching dictionary that (initially) matches all HID devices. */
230 | matchingDict = IOServiceMatching(kIOHIDDeviceKey);
231 |
232 | if (!matchingDict)
233 | return;
234 |
235 | /* Create objects for product and vendor IDs. */
236 | refProdID = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &productID);
237 | refVendorID = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &vendorID);
238 |
239 | /* Add objects to matching dictionary and clean up. */
240 | CFDictionarySetValue (matchingDict, CFSTR (kIOHIDVendorIDKey), refVendorID);
241 | CFDictionarySetValue (matchingDict, CFSTR (kIOHIDProductIDKey), refProdID);
242 |
243 | CFRelease(refProdID);
244 | CFRelease(refVendorID);
245 |
246 | // Now set up a notification to be called when a device is first matched by I/O Kit.
247 | // Note that this will not catch any devices that were already plugged in so we take
248 | // care of those later.
249 | kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
250 | kIOFirstMatchNotification, // notificationType
251 | matchingDict, // matching
252 | HIDDeviceAdded, // callback
253 | NULL, // refCon
254 | &gAddedIter // notification
255 | );
256 |
257 | if (kr != kIOReturnSuccess)
258 | return;
259 |
260 | HIDDeviceAdded(NULL, gAddedIter);
261 | }
262 |
263 | //---------------------------------------------------------------------------
264 | // HIDDeviceAdded
265 | //
266 | // This routine is the callback for our IOServiceAddMatchingNotification.
267 | // When we get called we will look at all the devices that were added and
268 | // we will:
269 | //
270 | // Create some private data to relate to each device
271 | //
272 | // Submit an IOServiceAddInterestNotification of type kIOGeneralInterest for
273 | // this device using the refCon field to store a pointer to our private data.
274 | // When we get called with this interest notification, we can grab the refCon
275 | // and access our private data.
276 | //---------------------------------------------------------------------------
277 |
278 | static void HIDDeviceAdded(void *refCon, io_iterator_t iterator)
279 | {
280 | io_object_t hidDevice = 0;
281 | IOCFPlugInInterface ** plugInInterface = NULL;
282 | IOHIDDeviceInterface122 ** hidDeviceInterface = NULL;
283 | HRESULT result = S_FALSE;
284 | HIDDataRef hidDataRef = NULL;
285 | IOReturn kr;
286 | SInt32 score;
287 | bool pass;
288 |
289 | /* Interate through all the devices that matched */
290 | while (0 != (hidDevice = IOIteratorNext(iterator)))
291 | {
292 | // Create the CF plugin for this device
293 | kr = IOCreatePlugInInterfaceForService(hidDevice, kIOHIDDeviceUserClientTypeID,
294 | kIOCFPlugInInterfaceID, &plugInInterface, &score);
295 |
296 | if (kr != kIOReturnSuccess)
297 | goto HIDDEVICEADDED_NONPLUGIN_CLEANUP;
298 |
299 | /* Obtain a device interface structure (hidDeviceInterface). */
300 | result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122),
301 | (LPVOID *)&hidDeviceInterface);
302 |
303 | // Got the interface
304 | if ((result == S_OK) && hidDeviceInterface)
305 | {
306 | /* Create a custom object to keep data around for later. */
307 | hidDataRef = malloc(sizeof(HIDData));
308 | bzero(hidDataRef, sizeof(HIDData));
309 |
310 | hidDataRef->hidDeviceInterface = hidDeviceInterface;
311 |
312 | /* Open the device interface. */
313 | result = (*(hidDataRef->hidDeviceInterface))->open (hidDataRef->hidDeviceInterface, kIOHIDOptionsTypeSeizeDevice);
314 |
315 | if (result != S_OK)
316 | goto HIDDEVICEADDED_FAIL;
317 |
318 | /* Find the HID elements for this device and set up a receive queue. */
319 | pass = FindHIDElements(hidDataRef);
320 | pass = SetupQueue(hidDataRef);
321 |
322 | printf("Please touch screen to continue.\n\n");
323 |
324 |
325 | /* Register an interest in finding out anything that happens with this device (disconnection, for example) */
326 | IOServiceAddInterestNotification(
327 | gNotifyPort, // notifyPort
328 | hidDevice, // service
329 | kIOGeneralInterest, // interestType
330 | DeviceNotification, // callback
331 | hidDataRef, // refCon
332 | &(hidDataRef->notification) // notification
333 | );
334 |
335 | goto HIDDEVICEADDED_CLEANUP;
336 | }
337 |
338 | HIDDEVICEADDED_FAIL:
339 | // Failed to allocated a UPS interface. Do some cleanup
340 | if (hidDeviceInterface)
341 | {
342 | (*hidDeviceInterface)->Release(hidDeviceInterface);
343 | hidDeviceInterface = NULL;
344 | }
345 |
346 | if (hidDataRef)
347 | free (hidDataRef);
348 |
349 | HIDDEVICEADDED_CLEANUP:
350 | // Clean up
351 | (*plugInInterface)->Release(plugInInterface);
352 |
353 | HIDDEVICEADDED_NONPLUGIN_CLEANUP:
354 | IOObjectRelease(hidDevice);
355 | }
356 | }
357 |
358 | //---------------------------------------------------------------------------
359 | // DeviceNotification
360 | //
361 | // This routine will get called whenever any kIOGeneralInterest notification
362 | // happens.
363 | //---------------------------------------------------------------------------
364 |
365 | static void DeviceNotification(void * refCon,
366 | io_service_t service,
367 | natural_t messageType,
368 | void * messageArgument)
369 | {
370 | kern_return_t kr;
371 | HIDDataRef hidDataRef = (HIDDataRef) refCon;
372 |
373 | /* Check to see if a device went away and clean up. */
374 | if ((hidDataRef != NULL) &&
375 | (messageType == kIOMessageServiceIsTerminated))
376 | {
377 | if (hidDataRef->hidQueueInterface != NULL)
378 | {
379 | kr = (*(hidDataRef->hidQueueInterface))->stop((hidDataRef->hidQueueInterface));
380 | kr = (*(hidDataRef->hidQueueInterface))->dispose((hidDataRef->hidQueueInterface));
381 | kr = (*(hidDataRef->hidQueueInterface))->Release (hidDataRef->hidQueueInterface);
382 | hidDataRef->hidQueueInterface = NULL;
383 | }
384 |
385 | if (hidDataRef->hidDeviceInterface != NULL)
386 | {
387 | kr = (*(hidDataRef->hidDeviceInterface))->close (hidDataRef->hidDeviceInterface);
388 | kr = (*(hidDataRef->hidDeviceInterface))->Release (hidDataRef->hidDeviceInterface);
389 | hidDataRef->hidDeviceInterface = NULL;
390 | }
391 |
392 | if (hidDataRef->notification)
393 | {
394 | kr = IOObjectRelease(hidDataRef->notification);
395 | hidDataRef->notification = 0;
396 | }
397 |
398 | }
399 | }
400 |
401 | //---------------------------------------------------------------------------
402 | // FindHIDElements
403 | //---------------------------------------------------------------------------
404 | static bool FindHIDElements(HIDDataRef hidDataRef)
405 | {
406 | CFArrayRef elementArray = NULL;
407 | CFMutableDictionaryRef hidElements = NULL;
408 | CFMutableDataRef newData = NULL;
409 | CFNumberRef number = NULL;
410 | CFDictionaryRef element = NULL;
411 | HIDElement newElement;
412 | IOReturn ret = kIOReturnError;
413 | unsigned i;
414 |
415 | if (!hidDataRef)
416 | return false;
417 |
418 | /* Create a mutable dictionary to hold HID elements. */
419 | hidElements = CFDictionaryCreateMutable(
420 | kCFAllocatorDefault,
421 | 0,
422 | &kCFTypeDictionaryKeyCallBacks,
423 | &kCFTypeDictionaryValueCallBacks);
424 | if (!hidElements)
425 | return false;
426 |
427 | // Let's find the elements
428 | ret = (*hidDataRef->hidDeviceInterface)->copyMatchingElements(
429 | hidDataRef->hidDeviceInterface,
430 | NULL,
431 | &elementArray);
432 |
433 |
434 | if ((ret != kIOReturnSuccess) || !elementArray)
435 | goto FIND_ELEMENT_CLEANUP;
436 |
437 | //CFShow(elementArray);
438 |
439 | /* Iterate through the elements and read their values. */
440 | for (i=0; ihidElementDictionary = hidElements;
503 | }
504 |
505 | return hidDataRef->hidElementDictionary;
506 | }
507 |
508 | //---------------------------------------------------------------------------
509 | // SetupQueue
510 | //---------------------------------------------------------------------------
511 | static bool SetupQueue(HIDDataRef hidDataRef)
512 | {
513 | CFIndex count = 0;
514 | CFIndex i = 0;
515 | CFMutableDataRef * elements = NULL;
516 | CFStringRef * keys = NULL;
517 | IOReturn ret;
518 | HIDElementRef tempHIDElement = NULL;
519 | bool cookieAdded = false;
520 | bool boolRet = true;
521 |
522 | if (!hidDataRef->hidElementDictionary || (((count = CFDictionaryGetCount(hidDataRef->hidElementDictionary)) <= 0)))
523 | return false;
524 |
525 | keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count);
526 | elements = (CFMutableDataRef *)malloc(sizeof(CFMutableDataRef) * count);
527 |
528 | CFDictionaryGetKeysAndValues(hidDataRef->hidElementDictionary, (const void **)keys, (const void **)elements);
529 |
530 | hidDataRef->hidQueueInterface = (*hidDataRef->hidDeviceInterface)->allocQueue(hidDataRef->hidDeviceInterface);
531 | if (!hidDataRef->hidQueueInterface)
532 | {
533 | boolRet = false;
534 | goto SETUP_QUEUE_CLEANUP;
535 | }
536 |
537 | ret = (*hidDataRef->hidQueueInterface)->create(hidDataRef->hidQueueInterface, 0, 8);
538 | if (ret != kIOReturnSuccess)
539 | {
540 | boolRet = false;
541 | goto SETUP_QUEUE_CLEANUP;
542 | }
543 |
544 | for (i=0; itype < kIOHIDElementTypeInput_Misc) || (tempHIDElement->type > kIOHIDElementTypeInput_ScanCodes))
553 | continue;
554 |
555 | ret = (*hidDataRef->hidQueueInterface)->addElement(hidDataRef->hidQueueInterface, tempHIDElement->cookie, 0);
556 |
557 | if (ret == kIOReturnSuccess)
558 | cookieAdded = true;
559 | }
560 |
561 | if (cookieAdded)
562 | {
563 | ret = (*hidDataRef->hidQueueInterface)->createAsyncEventSource(hidDataRef->hidQueueInterface, &hidDataRef->eventSource);
564 | if (ret != kIOReturnSuccess)
565 | {
566 | boolRet = false;
567 | goto SETUP_QUEUE_CLEANUP;
568 | }
569 |
570 | ret = (*hidDataRef->hidQueueInterface)->setEventCallout(hidDataRef->hidQueueInterface, QueueCallbackFunction, NULL, hidDataRef);
571 | if (ret != kIOReturnSuccess)
572 | {
573 | boolRet = false;
574 | goto SETUP_QUEUE_CLEANUP;
575 | }
576 |
577 | CFRunLoopAddSource(CFRunLoopGetCurrent(), hidDataRef->eventSource, kCFRunLoopDefaultMode);
578 |
579 | ret = (*hidDataRef->hidQueueInterface)->start(hidDataRef->hidQueueInterface);
580 | if (ret != kIOReturnSuccess)
581 | {
582 | boolRet = false;
583 | goto SETUP_QUEUE_CLEANUP;
584 | }
585 | }
586 | else
587 | {
588 | (*hidDataRef->hidQueueInterface)->stop(hidDataRef->hidQueueInterface);
589 | (*hidDataRef->hidQueueInterface)->dispose(hidDataRef->hidQueueInterface);
590 | (*hidDataRef->hidQueueInterface)->Release(hidDataRef->hidQueueInterface);
591 | hidDataRef->hidQueueInterface = NULL;
592 | }
593 |
594 | SETUP_QUEUE_CLEANUP:
595 |
596 | free(keys);
597 | free(elements);
598 |
599 | return boolRet;
600 | }
601 |
602 |
603 | //---------------------------------------------------------------------------
604 | // QueueCallbackFunction
605 | //---------------------------------------------------------------------------
606 | static void QueueCallbackFunction(
607 | void * target,
608 | IOReturn result,
609 | void * refcon,
610 | void * sender)
611 | {
612 | HIDDataRef hidDataRef = (HIDDataRef)refcon;
613 | AbsoluteTime zeroTime = {0,0};
614 | CFNumberRef number = NULL;
615 | CFMutableDataRef element = NULL;
616 | HIDElementRef tempHIDElement = NULL;//(HIDElementRef)refcon;
617 | IOHIDEventStruct event;
618 | bool change;
619 |
620 | if (!hidDataRef || (sender != hidDataRef->hidQueueInterface))
621 | return;
622 |
623 | while (result == kIOReturnSuccess)
624 | {
625 | result = (*hidDataRef->hidQueueInterface)->getNextEvent(
626 | hidDataRef->hidQueueInterface,
627 | &event,
628 | zeroTime,
629 | 0);
630 |
631 | if (result != kIOReturnSuccess)
632 | continue;
633 |
634 | // Only intersted in 32 values right now
635 | if ((event.longValueSize != 0) && (event.longValue != NULL))
636 | {
637 | free(event.longValue);
638 | continue;
639 | }
640 |
641 | number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &event.elementCookie);
642 | if (!number) continue;
643 | element = (CFMutableDataRef)CFDictionaryGetValue(hidDataRef->hidElementDictionary, number);
644 | CFRelease(number);
645 |
646 | if (!element ||
647 | !(tempHIDElement = (HIDElement *)CFDataGetMutableBytePtr(element)))
648 | continue;
649 |
650 | change = (tempHIDElement->currentValue != event.value);
651 | tempHIDElement->currentValue = event.value;
652 |
653 | reportHidElement(tempHIDElement);
654 | }
655 |
656 | }
657 |
--------------------------------------------------------------------------------