hid: Rewrite HidP_MaxUsageListLength using enum_value_caps.
[wine.git] / dlls / hid / hidp.c
blob76b9ff5ee2cbc329ac90ca2c51df2d5e8c198844
1 /*
2 * Human Input Devices
4 * Copyright (C) 2015 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "winioctl.h"
30 #include "ddk/wdm.h"
32 #include "hidusage.h"
33 #include "ddk/hidpi.h"
34 #include "wine/hid.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(hidp);
39 static NTSTATUS get_value_caps_range( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPORT_TYPE report_type, ULONG report_len,
40 const struct hid_value_caps **caps, const struct hid_value_caps **caps_end )
42 if (preparsed->magic != HID_MAGIC) return HIDP_STATUS_INVALID_PREPARSED_DATA;
44 switch (report_type)
46 case HidP_Input:
47 if (report_len && report_len != preparsed->caps.InputReportByteLength)
48 return HIDP_STATUS_INVALID_REPORT_LENGTH;
49 *caps = HID_INPUT_VALUE_CAPS( preparsed );
50 break;
51 case HidP_Output:
52 if (report_len && report_len != preparsed->caps.OutputReportByteLength)
53 return HIDP_STATUS_INVALID_REPORT_LENGTH;
54 *caps = HID_OUTPUT_VALUE_CAPS( preparsed );
55 break;
56 case HidP_Feature:
57 if (report_len && report_len != preparsed->caps.FeatureReportByteLength)
58 return HIDP_STATUS_INVALID_REPORT_LENGTH;
59 *caps = HID_FEATURE_VALUE_CAPS( preparsed );
60 break;
61 default:
62 return HIDP_STATUS_INVALID_REPORT_TYPE;
65 *caps_end = *caps + preparsed->value_caps_count[report_type];
66 return HIDP_STATUS_SUCCESS;
69 struct caps_filter
71 BOOLEAN buttons;
72 BOOLEAN values;
73 USAGE usage_page;
74 USHORT collection;
75 USAGE usage;
78 static BOOL match_value_caps( const struct hid_value_caps *caps, const struct caps_filter *filter )
80 if (!caps->usage_min && !caps->usage_max) return FALSE;
81 if (filter->buttons && !HID_VALUE_CAPS_IS_BUTTON( caps )) return FALSE;
82 if (filter->values && HID_VALUE_CAPS_IS_BUTTON( caps )) return FALSE;
83 if (filter->usage_page && filter->usage_page != caps->usage_page) return FALSE;
84 if (filter->collection && filter->collection != caps->link_collection) return FALSE;
85 if (!filter->usage) return TRUE;
86 return caps->usage_min <= filter->usage && caps->usage_max >= filter->usage;
89 typedef NTSTATUS (*enum_value_caps_callback)( const struct hid_value_caps *caps, void *user );
91 static NTSTATUS enum_value_caps( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPORT_TYPE report_type,
92 const struct caps_filter *filter, enum_value_caps_callback callback,
93 void *user, USHORT *count )
95 const struct hid_value_caps *caps, *caps_end;
96 NTSTATUS status;
97 LONG remaining = *count;
99 for (status = get_value_caps_range( preparsed, report_type, 0, &caps, &caps_end );
100 status == HIDP_STATUS_SUCCESS && caps != caps_end; caps++)
102 if (!match_value_caps( caps, filter )) continue;
103 if (remaining-- > 0) status = callback( caps, user );
106 if (status != HIDP_STATUS_SUCCESS) return status;
108 *count -= remaining;
109 if (*count == 0) return HIDP_STATUS_USAGE_NOT_FOUND;
110 if (remaining < 0) return HIDP_STATUS_BUFFER_TOO_SMALL;
111 return HIDP_STATUS_SUCCESS;
114 static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value)
117 if ((startBit + valueSize) / 8 > reportLength)
118 return HIDP_STATUS_INVALID_REPORT_LENGTH;
120 if (valueSize == 1)
122 ULONG byte_index = startBit / 8;
123 ULONG bit_index = startBit - (byte_index * 8);
124 INT mask = (1 << bit_index);
125 *value = !!(report[byte_index] & mask);
127 else
129 ULONG remaining_bits = valueSize;
130 ULONG byte_index = startBit / 8;
131 ULONG bit_index = startBit % 8;
132 ULONG data = 0;
133 ULONG shift = 0;
134 while (remaining_bits)
136 ULONG copy_bits = 8 - bit_index;
137 if (remaining_bits < copy_bits)
138 copy_bits = remaining_bits;
140 data |= ((report[byte_index] >> bit_index) & ((1 << copy_bits) - 1)) << shift;
142 shift += copy_bits;
143 bit_index = 0;
144 byte_index++;
145 remaining_bits -= copy_bits;
147 *value = data;
149 return HIDP_STATUS_SUCCESS;
152 static NTSTATUS set_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, ULONG value)
154 if ((startBit + valueSize) / 8 > reportLength)
155 return HIDP_STATUS_INVALID_REPORT_LENGTH;
157 if (valueSize == 1)
159 ULONG byte_index = startBit / 8;
160 ULONG bit_index = startBit - (byte_index * 8);
161 if (value)
162 report[byte_index] |= (1 << bit_index);
163 else
164 report[byte_index] &= ~(1 << bit_index);
166 else
168 ULONG byte_index = (startBit + valueSize - 1) / 8;
169 ULONG data = value;
170 ULONG remainingBits = valueSize;
171 while (remainingBits)
173 BYTE subvalue = data & 0xff;
175 data >>= 8;
177 if (remainingBits >= 8)
179 report[byte_index] = subvalue;
180 byte_index --;
181 remainingBits -= 8;
183 else if (remainingBits > 0)
185 BYTE mask = (0xff << (8-remainingBits)) & subvalue;
186 report[byte_index] |= mask;
187 remainingBits = 0;
191 return HIDP_STATUS_SUCCESS;
194 static NTSTATUS get_report_data_array(BYTE *report, UINT reportLength, UINT startBit, UINT elemSize,
195 UINT numElements, PCHAR values, UINT valuesSize)
197 BYTE byte, *end, *p = report + startBit / 8;
198 ULONG size = elemSize * numElements;
199 ULONG m, bit_index = startBit % 8;
200 BYTE *data = (BYTE*)values;
202 if ((startBit + size) / 8 > reportLength)
203 return HIDP_STATUS_INVALID_REPORT_LENGTH;
205 if (valuesSize < (size + 7) / 8)
206 return HIDP_STATUS_BUFFER_TOO_SMALL;
208 end = report + (startBit + size + 7) / 8;
210 data--;
211 byte = *p++;
212 while (p != end)
214 *(++data) = byte >> bit_index;
215 byte = *p++;
216 *data |= byte << (8 - bit_index);
219 /* Handle the end and mask out bits beyond */
220 m = (startBit + size) % 8;
221 m = m ? m : 8;
223 if (m > bit_index)
224 *(++data) = (byte >> bit_index) & ((1 << (m - bit_index)) - 1);
225 else
226 *data &= (1 << (m + 8 - bit_index)) - 1;
228 if (++data < (BYTE*)values + valuesSize)
229 memset(data, 0, (BYTE*)values + valuesSize - data);
231 return HIDP_STATUS_SUCCESS;
234 NTSTATUS WINAPI HidP_GetButtonCaps( HIDP_REPORT_TYPE report_type, HIDP_BUTTON_CAPS *caps, USHORT *caps_count,
235 PHIDP_PREPARSED_DATA preparsed_data )
237 return HidP_GetSpecificButtonCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data );
240 NTSTATUS WINAPI HidP_GetCaps( PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps )
242 WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
244 TRACE( "preparsed_data %p, caps %p.\n", preparsed_data, caps );
246 if (preparsed->magic != HID_MAGIC) return HIDP_STATUS_INVALID_PREPARSED_DATA;
248 *caps = preparsed->caps;
249 caps->NumberInputButtonCaps = preparsed->new_caps.NumberInputButtonCaps;
250 caps->NumberOutputButtonCaps = preparsed->new_caps.NumberOutputButtonCaps;
251 caps->NumberFeatureButtonCaps = preparsed->new_caps.NumberFeatureButtonCaps;
252 caps->NumberInputValueCaps = preparsed->new_caps.NumberInputValueCaps;
253 caps->NumberOutputValueCaps = preparsed->new_caps.NumberOutputValueCaps;
254 caps->NumberFeatureValueCaps = preparsed->new_caps.NumberFeatureValueCaps;
256 return HIDP_STATUS_SUCCESS;
259 static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
260 USAGE Usage, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
261 USHORT bit_size, WINE_HID_ELEMENT *element)
263 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
264 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
265 WINE_HID_REPORT *report = NULL;
266 USHORT v_count = 0, r_count = 0;
267 int i;
269 TRACE("(%i, %x, %i, %i, %p, %p)\n", ReportType, UsagePage, LinkCollection, Usage,
270 PreparsedData, Report);
272 if (data->magic != HID_MAGIC)
273 return HIDP_STATUS_INVALID_PREPARSED_DATA;
274 switch(ReportType)
276 case HidP_Input:
277 v_count = data->caps.NumberInputValueCaps;
278 break;
279 case HidP_Output:
280 v_count = data->caps.NumberOutputValueCaps;
281 break;
282 case HidP_Feature:
283 v_count = data->caps.NumberFeatureValueCaps;
284 break;
285 default:
286 return HIDP_STATUS_INVALID_REPORT_TYPE;
288 r_count = data->reportCount[ReportType];
289 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
291 if (!r_count || !v_count)
292 return HIDP_STATUS_USAGE_NOT_FOUND;
294 if (report->reportID && report->reportID != Report[0])
295 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
297 for (i = 0; i < report->elementCount; i++)
299 HIDP_VALUE_CAPS *value = &elems[report->elementIdx + i].caps;
301 if ((elems[report->elementIdx + i].caps.BitSize == 1) != (bit_size == 1) ||
302 value->UsagePage != UsagePage)
303 continue;
305 if (value->IsRange && value->Range.UsageMin <= Usage && Usage <= value->Range.UsageMax)
307 *element = elems[report->elementIdx + i];
308 element->valueStartBit += value->BitSize * (Usage - value->Range.UsageMin);
309 element->bitCount = elems[report->elementIdx + i].caps.BitSize;
310 return HIDP_STATUS_SUCCESS;
312 else if (value->NotRange.Usage == Usage)
314 *element = elems[report->elementIdx + i];
315 element->bitCount = elems[report->elementIdx + i].caps.BitSize;
316 return HIDP_STATUS_SUCCESS;
320 return HIDP_STATUS_USAGE_NOT_FOUND;
323 static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
325 UINT bit_count = element->bitCount;
327 if ((value & (1 << (bit_count - 1)))
328 && element->caps.BitSize != 1
329 && element->caps.LogicalMin < 0)
331 value -= (1 << bit_count);
333 return value;
336 static LONG logical_to_physical(LONG value, const WINE_HID_ELEMENT *element)
338 if (element->caps.PhysicalMin || element->caps.PhysicalMax)
340 value = (((ULONGLONG)(value - element->caps.LogicalMin)
341 * (element->caps.PhysicalMax - element->caps.PhysicalMin))
342 / (element->caps.LogicalMax - element->caps.LogicalMin))
343 + element->caps.PhysicalMin;
345 return value;
348 NTSTATUS WINAPI HidP_GetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage,
349 USHORT LinkCollection, USAGE Usage, PLONG UsageValue,
350 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
352 NTSTATUS rc;
353 WINE_HID_ELEMENT element;
354 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
355 PreparsedData, Report, ReportLength);
357 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, 0, &element);
359 if (rc == HIDP_STATUS_SUCCESS)
361 ULONG rawValue;
362 rc = get_report_data((BYTE*)Report, ReportLength,
363 element.valueStartBit, element.bitCount, &rawValue);
364 if (rc != HIDP_STATUS_SUCCESS)
365 return rc;
366 *UsageValue = logical_to_physical(sign_extend(rawValue, &element), &element);
369 return rc;
373 NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
374 USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
375 PCHAR Report, ULONG ReportLength)
377 WINE_HID_ELEMENT element;
378 NTSTATUS rc;
380 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
381 PreparsedData, Report, ReportLength);
383 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, 0, &element);
385 if (rc == HIDP_STATUS_SUCCESS)
387 return get_report_data((BYTE*)Report, ReportLength,
388 element.valueStartBit, element.bitCount, UsageValue);
391 return rc;
395 NTSTATUS WINAPI HidP_GetUsageValueArray(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
396 USAGE Usage, PCHAR UsageValue, USHORT UsageValueByteLength,
397 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
399 WINE_HID_ELEMENT element;
400 NTSTATUS rc;
402 TRACE("(%i, %x, %i, %i, %p, %u, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
403 UsageValueByteLength, PreparsedData, Report, ReportLength);
405 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, 0, &element);
407 if (rc == HIDP_STATUS_SUCCESS)
409 if (element.caps.IsRange || element.caps.ReportCount <= 1 || !element.bitCount)
410 return HIDP_STATUS_NOT_VALUE_ARRAY;
412 return get_report_data_array((BYTE*)Report, ReportLength, element.valueStartBit, element.bitCount,
413 element.caps.ReportCount, UsageValue, UsageValueByteLength);
416 return rc;
420 NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
421 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
422 PCHAR Report, ULONG ReportLength)
424 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
425 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
426 WINE_HID_REPORT *report = NULL;
427 BOOL found = FALSE;
428 USHORT b_count = 0, r_count = 0;
429 int i,uCount;
431 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
432 UsageLength, PreparsedData, Report, ReportLength);
434 if (data->magic != HID_MAGIC)
436 *UsageLength = 0;
437 return HIDP_STATUS_INVALID_PREPARSED_DATA;
440 switch(ReportType)
442 case HidP_Input:
443 b_count = data->caps.NumberInputButtonCaps;
444 break;
445 case HidP_Output:
446 b_count = data->caps.NumberOutputButtonCaps;
447 break;
448 case HidP_Feature:
449 b_count = data->caps.NumberFeatureButtonCaps;
450 break;
451 default:
452 return HIDP_STATUS_INVALID_REPORT_TYPE;
454 r_count = data->reportCount[ReportType];
455 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
457 if (!r_count || !b_count)
458 return HIDP_STATUS_USAGE_NOT_FOUND;
460 if (report->reportID && report->reportID != Report[0])
461 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
463 uCount = 0;
464 for (i = 0; i < report->elementCount && uCount < *UsageLength; i++)
466 if (elems[report->elementIdx + i].caps.BitSize == 1 &&
467 elems[report->elementIdx + i].caps.UsagePage == UsagePage)
469 int k;
470 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
471 for (k=0; k < element->bitCount; k++)
473 UINT v = 0;
474 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
475 element->valueStartBit + k, 1, &v);
476 if (rc != HIDP_STATUS_SUCCESS)
477 return rc;
478 found = TRUE;
479 if (v)
481 if (uCount == *UsageLength)
482 return HIDP_STATUS_BUFFER_TOO_SMALL;
483 UsageList[uCount] = element->caps.Range.UsageMin + k;
484 uCount++;
490 *UsageLength = uCount;
492 if (!found)
493 return HIDP_STATUS_USAGE_NOT_FOUND;
495 return HIDP_STATUS_SUCCESS;
498 NTSTATUS WINAPI HidP_GetValueCaps( HIDP_REPORT_TYPE report_type, HIDP_VALUE_CAPS *caps, USHORT *caps_count,
499 PHIDP_PREPARSED_DATA preparsed_data )
501 return HidP_GetSpecificValueCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data );
504 NTSTATUS WINAPI HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type, UCHAR report_id,
505 PHIDP_PREPARSED_DATA preparsed_data, char *report_buf, ULONG report_len )
507 WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
508 const struct hid_value_caps *caps, *end;
509 NTSTATUS status;
511 TRACE( "report_type %d, report_id %x, preparsed_data %p, report_buf %p, report_len %u.\n", report_type,
512 report_id, preparsed_data, report_buf, report_len );
514 if (!report_len) return HIDP_STATUS_INVALID_REPORT_LENGTH;
516 status = get_value_caps_range( preparsed, report_type, report_len, &caps, &end );
517 if (status != HIDP_STATUS_SUCCESS) return status;
519 while (caps != end && (caps->report_id != report_id || (!caps->usage_min && !caps->usage_max))) caps++;
520 if (caps == end) return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
522 memset( report_buf, 0, report_len );
523 report_buf[0] = report_id;
524 return HIDP_STATUS_SUCCESS;
527 static NTSTATUS get_usage_list_length( const struct hid_value_caps *caps, void *data )
529 *(ULONG *)data += caps->report_count;
530 return HIDP_STATUS_SUCCESS;
533 ULONG WINAPI HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type, USAGE usage_page, PHIDP_PREPARSED_DATA preparsed_data )
535 WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
536 struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page};
537 USHORT limit = -1;
538 ULONG count = 0;
540 TRACE( "report_type %d, usage_page %x, preparsed_data %p.\n", report_type, usage_page, preparsed_data );
542 enum_value_caps( preparsed, report_type, &filter, get_usage_list_length, &count, &limit );
543 return count;
546 NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
547 USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
548 CHAR *Report, ULONG ReportLength)
550 WINE_HID_ELEMENT element;
551 NTSTATUS rc;
553 TRACE("(%i, %x, %i, %i, %i, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
554 PreparsedData, Report, ReportLength);
556 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, 0, &element);
558 if (rc == HIDP_STATUS_SUCCESS)
560 return set_report_data((BYTE*)Report, ReportLength,
561 element.valueStartBit, element.bitCount, UsageValue);
564 return rc;
567 NTSTATUS WINAPI HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type, USAGE usage_page, USHORT collection,
568 USAGE usage, char *value_buf, USHORT value_len,
569 PHIDP_PREPARSED_DATA preparsed_data, char *report_buf, ULONG report_len )
571 FIXME( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
572 "preparsed_data %p, report_buf %p, report_len %u stub!\n",
573 report_type, usage_page, collection, usage, value_buf, value_len, preparsed_data, report_buf, report_len );
575 return HIDP_STATUS_NOT_IMPLEMENTED;
578 NTSTATUS WINAPI HidP_SetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
579 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
580 PCHAR Report, ULONG ReportLength)
582 WINE_HID_ELEMENT element;
583 NTSTATUS rc;
584 ULONG i;
586 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
587 UsageLength, PreparsedData, Report, ReportLength);
589 for (i = 0; i < *UsageLength; i++)
591 rc = find_usage(ReportType, UsagePage, LinkCollection,
592 UsageList[i], PreparsedData, Report, 1, &element);
593 if (rc == HIDP_STATUS_SUCCESS)
595 rc = set_report_data((BYTE*)Report, ReportLength,
596 element.valueStartBit, element.bitCount, -1);
599 if (rc != HIDP_STATUS_SUCCESS)
601 *UsageLength = i;
602 return rc;
606 return HIDP_STATUS_SUCCESS;
610 NTSTATUS WINAPI HidP_TranslateUsagesToI8042ScanCodes(USAGE *ChangedUsageList,
611 ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction,
612 HIDP_KEYBOARD_MODIFIER_STATE *ModifierState,
613 PHIDP_INSERT_SCANCODES InsertCodesProcedure, VOID *InsertCodesContext)
615 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList, UsageListLength,
616 KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
618 return STATUS_NOT_IMPLEMENTED;
621 static NTSTATUS get_button_caps( const struct hid_value_caps *caps, void *user )
623 HIDP_BUTTON_CAPS **iter = user, *dst = *iter;
624 dst->UsagePage = caps->usage_page;
625 dst->ReportID = caps->report_id;
626 dst->LinkCollection = caps->link_collection;
627 dst->LinkUsagePage = caps->link_usage_page;
628 dst->LinkUsage = caps->link_usage;
629 dst->BitField = caps->bit_field;
630 dst->IsAlias = FALSE;
631 dst->IsAbsolute = HID_VALUE_CAPS_IS_ABSOLUTE( caps );
632 if (!(dst->IsRange = caps->is_range))
634 dst->NotRange.Usage = caps->usage_min;
635 dst->NotRange.DataIndex = caps->data_index_min;
637 else
639 dst->Range.UsageMin = caps->usage_min;
640 dst->Range.UsageMax = caps->usage_max;
641 dst->Range.DataIndexMin = caps->data_index_min;
642 dst->Range.DataIndexMax = caps->data_index_max;
644 if (!(dst->IsStringRange = caps->is_string_range))
645 dst->NotRange.StringIndex = caps->string_min;
646 else
648 dst->Range.StringMin = caps->string_min;
649 dst->Range.StringMax = caps->string_max;
651 if ((dst->IsDesignatorRange = caps->is_designator_range))
652 dst->NotRange.DesignatorIndex = caps->designator_min;
653 else
655 dst->Range.DesignatorMin = caps->designator_min;
656 dst->Range.DesignatorMax = caps->designator_max;
658 *iter += 1;
659 return HIDP_STATUS_SUCCESS;
662 NTSTATUS WINAPI HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type, USAGE usage_page, USHORT collection,
663 USAGE usage, HIDP_BUTTON_CAPS *caps, USHORT *caps_count,
664 PHIDP_PREPARSED_DATA preparsed_data )
666 WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
667 const struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage};
669 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
670 report_type, usage_page, collection, usage, caps, caps_count, preparsed_data );
672 return enum_value_caps( preparsed, report_type, &filter, get_button_caps, &caps, caps_count );
675 static NTSTATUS get_value_caps( const struct hid_value_caps *caps, void *user )
677 HIDP_VALUE_CAPS **iter = user, *dst = *iter;
678 dst->UsagePage = caps->usage_page;
679 dst->ReportID = caps->report_id;
680 dst->LinkCollection = caps->link_collection;
681 dst->LinkUsagePage = caps->link_usage_page;
682 dst->LinkUsage = caps->link_usage;
683 dst->BitField = caps->bit_field;
684 dst->IsAlias = FALSE;
685 dst->IsAbsolute = HID_VALUE_CAPS_IS_ABSOLUTE( caps );
686 dst->HasNull = HID_VALUE_CAPS_HAS_NULL( caps );
687 dst->BitSize = caps->bit_size;
688 dst->ReportCount = caps->is_range ? 1 : caps->report_count;
689 dst->UnitsExp = caps->units_exp;
690 dst->Units = caps->units;
691 dst->LogicalMin = caps->logical_min;
692 dst->LogicalMax = caps->logical_max;
693 dst->PhysicalMin = caps->physical_min;
694 dst->PhysicalMax = caps->physical_max;
695 if (!(dst->IsRange = caps->is_range))
697 dst->NotRange.Usage = caps->usage_min;
698 dst->NotRange.DataIndex = caps->data_index_min;
700 else
702 dst->Range.UsageMin = caps->usage_min;
703 dst->Range.UsageMax = caps->usage_max;
704 dst->Range.DataIndexMin = caps->data_index_min;
705 dst->Range.DataIndexMax = caps->data_index_max;
707 if (!(dst->IsStringRange = caps->is_string_range))
708 dst->NotRange.StringIndex = caps->string_min;
709 else
711 dst->Range.StringMin = caps->string_min;
712 dst->Range.StringMax = caps->string_max;
714 if ((dst->IsDesignatorRange = caps->is_designator_range))
715 dst->NotRange.DesignatorIndex = caps->designator_min;
716 else
718 dst->Range.DesignatorMin = caps->designator_min;
719 dst->Range.DesignatorMax = caps->designator_max;
721 *iter += 1;
722 return HIDP_STATUS_SUCCESS;
725 NTSTATUS WINAPI HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type, USAGE usage_page, USHORT collection,
726 USAGE usage, HIDP_VALUE_CAPS *caps, USHORT *caps_count,
727 PHIDP_PREPARSED_DATA preparsed_data )
729 WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
730 const struct caps_filter filter = {.values = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage};
732 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
733 report_type, usage_page, collection, usage, caps, caps_count, preparsed_data );
735 return enum_value_caps( preparsed, report_type, &filter, get_value_caps, &caps, caps_count );
738 NTSTATUS WINAPI HidP_GetUsagesEx(HIDP_REPORT_TYPE ReportType, USHORT LinkCollection, USAGE_AND_PAGE *ButtonList,
739 ULONG *UsageLength, PHIDP_PREPARSED_DATA PreparsedData, CHAR *Report, ULONG ReportLength)
741 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
742 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
743 WINE_HID_REPORT *report = NULL;
744 USHORT b_count = 0, r_count = 0;
745 int i,uCount = 0;
746 NTSTATUS rc;
748 TRACE("(%i, %i, %p, %p(%i), %p, %p, %i)\n", ReportType, LinkCollection, ButtonList,
749 UsageLength, *UsageLength, PreparsedData, Report, ReportLength);
751 if (data->magic != HID_MAGIC)
752 return HIDP_STATUS_INVALID_PREPARSED_DATA;
754 switch(ReportType)
756 case HidP_Input:
757 b_count = data->caps.NumberInputButtonCaps;
758 break;
759 case HidP_Output:
760 b_count = data->caps.NumberOutputButtonCaps;
761 break;
762 case HidP_Feature:
763 b_count = data->caps.NumberFeatureButtonCaps;
764 break;
765 default:
766 return HIDP_STATUS_INVALID_REPORT_TYPE;
768 r_count = data->reportCount[ReportType];
769 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
771 if (!r_count || !b_count)
772 return HIDP_STATUS_USAGE_NOT_FOUND;
774 if (report->reportID && report->reportID != Report[0])
775 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
777 for (i = 0; i < report->elementCount; i++)
779 if (elems[report->elementIdx + i].caps.BitSize == 1)
781 int k;
782 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
783 for (k=0; k < element->bitCount; k++)
785 UINT v = 0;
786 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
787 element->valueStartBit + k, 1, &v);
788 if (rc != HIDP_STATUS_SUCCESS)
789 return rc;
790 if (v)
792 if (uCount < *UsageLength)
794 ButtonList[uCount].Usage = element->caps.Range.UsageMin + k;
795 ButtonList[uCount].UsagePage = element->caps.UsagePage;
797 uCount++;
803 TRACE("Returning %i usages\n", uCount);
805 if (*UsageLength < uCount)
806 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
807 else
808 rc = HIDP_STATUS_SUCCESS;
810 *UsageLength = uCount;
812 return rc;
815 ULONG WINAPI HidP_MaxDataListLength(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData)
817 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA *)PreparsedData;
818 TRACE("(%i, %p)\n", ReportType, PreparsedData);
819 if (data->magic != HID_MAGIC)
820 return 0;
822 switch(ReportType)
824 case HidP_Input:
825 return data->caps.NumberInputDataIndices;
826 case HidP_Output:
827 return data->caps.NumberOutputDataIndices;
828 case HidP_Feature:
829 return data->caps.NumberFeatureDataIndices;
830 default:
831 return 0;
835 NTSTATUS WINAPI HidP_GetData(HIDP_REPORT_TYPE ReportType, HIDP_DATA *DataList, ULONG *DataLength,
836 PHIDP_PREPARSED_DATA PreparsedData,CHAR *Report, ULONG ReportLength)
838 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
839 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
840 WINE_HID_REPORT *report = NULL;
841 USHORT r_count = 0;
842 int i,uCount = 0;
843 NTSTATUS rc;
845 TRACE("(%i, %p, %p(%i), %p, %p, %i)\n", ReportType, DataList, DataLength,
846 DataLength?*DataLength:0, PreparsedData, Report, ReportLength);
848 if (data->magic != HID_MAGIC)
849 return 0;
851 if (ReportType != HidP_Input && ReportType != HidP_Output && ReportType != HidP_Feature)
852 return HIDP_STATUS_INVALID_REPORT_TYPE;
854 r_count = data->reportCount[ReportType];
855 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
857 if (!r_count || (report->reportID && report->reportID != Report[0]))
858 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
860 for (i = 0; i < report->elementCount; i++)
862 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
863 if (element->caps.BitSize == 1)
865 int k;
866 for (k=0; k < element->bitCount; k++)
868 UINT v = 0;
869 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
870 element->valueStartBit + k, 1, &v);
871 if (rc != HIDP_STATUS_SUCCESS)
872 return rc;
873 if (v)
875 if (uCount < *DataLength)
877 DataList[uCount].DataIndex = element->caps.Range.DataIndexMin + k;
878 DataList[uCount].On = v;
880 uCount++;
884 else
886 if (uCount < *DataLength)
888 UINT v;
889 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
890 element->valueStartBit, element->bitCount, &v);
891 if (rc != HIDP_STATUS_SUCCESS)
892 return rc;
893 DataList[uCount].DataIndex = element->caps.NotRange.DataIndex;
894 DataList[uCount].RawValue = v;
896 uCount++;
900 if (*DataLength < uCount)
901 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
902 else
903 rc = HIDP_STATUS_SUCCESS;
905 *DataLength = uCount;
907 return rc;
910 NTSTATUS WINAPI HidP_GetLinkCollectionNodes(HIDP_LINK_COLLECTION_NODE *LinkCollectionNode,
911 ULONG *LinkCollectionNodeLength, PHIDP_PREPARSED_DATA PreparsedData)
913 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
914 WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data);
915 ULONG i;
917 TRACE("(%p, %p, %p)\n", LinkCollectionNode, LinkCollectionNodeLength, PreparsedData);
919 if (data->magic != HID_MAGIC)
920 return HIDP_STATUS_INVALID_PREPARSED_DATA;
922 if (*LinkCollectionNodeLength < data->caps.NumberLinkCollectionNodes)
923 return HIDP_STATUS_BUFFER_TOO_SMALL;
925 for (i = 0; i < data->caps.NumberLinkCollectionNodes; ++i)
927 LinkCollectionNode[i].LinkUsage = nodes[i].LinkUsage;
928 LinkCollectionNode[i].LinkUsagePage = nodes[i].LinkUsagePage;
929 LinkCollectionNode[i].Parent = nodes[i].Parent;
930 LinkCollectionNode[i].NumberOfChildren = nodes[i].NumberOfChildren;
931 LinkCollectionNode[i].NextSibling = nodes[i].NextSibling;
932 LinkCollectionNode[i].FirstChild = nodes[i].FirstChild;
933 LinkCollectionNode[i].CollectionType = nodes[i].CollectionType;
934 LinkCollectionNode[i].IsAlias = nodes[i].IsAlias;
936 *LinkCollectionNodeLength = data->caps.NumberLinkCollectionNodes;
938 return HIDP_STATUS_SUCCESS;