@ac-kit/format-hid 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/LICENSE +28 -0
- package/README.md +96 -2
- package/dist/descriptor/hid-field-usage.d.ts +35 -0
- package/dist/descriptor/hid-field-usage.d.ts.map +1 -0
- package/dist/descriptor/hid-field-usage.js +63 -0
- package/dist/descriptor/hid-field-usage.js.map +1 -0
- package/dist/descriptor/hid-report-descriptor.d.ts +148 -0
- package/dist/descriptor/hid-report-descriptor.d.ts.map +1 -0
- package/dist/descriptor/hid-report-descriptor.js +15 -0
- package/dist/descriptor/hid-report-descriptor.js.map +1 -0
- package/dist/descriptor/parse-hid-report-descriptor.d.ts +30 -0
- package/dist/descriptor/parse-hid-report-descriptor.d.ts.map +1 -0
- package/dist/descriptor/parse-hid-report-descriptor.js +440 -0
- package/dist/descriptor/parse-hid-report-descriptor.js.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -0
- package/dist/field/_field-value-bit-position.d.ts +7 -0
- package/dist/field/_field-value-bit-position.d.ts.map +1 -0
- package/dist/field/_field-value-bit-position.js +24 -0
- package/dist/field/_field-value-bit-position.js.map +1 -0
- package/dist/field/create-hid-report.d.ts +9 -0
- package/dist/field/create-hid-report.d.ts.map +1 -0
- package/dist/field/create-hid-report.js +14 -0
- package/dist/field/create-hid-report.js.map +1 -0
- package/dist/field/hid-field-layout.d.ts +7 -0
- package/dist/field/hid-field-layout.d.ts.map +1 -0
- package/dist/field/hid-field-layout.js +2 -0
- package/dist/field/hid-field-layout.js.map +1 -0
- package/dist/field/hid-logical-to-physical.d.ts +14 -0
- package/dist/field/hid-logical-to-physical.d.ts.map +1 -0
- package/dist/field/hid-logical-to-physical.js +27 -0
- package/dist/field/hid-logical-to-physical.js.map +1 -0
- package/dist/field/read-hid-field-value.d.ts +18 -0
- package/dist/field/read-hid-field-value.d.ts.map +1 -0
- package/dist/field/read-hid-field-value.js +35 -0
- package/dist/field/read-hid-field-value.js.map +1 -0
- package/dist/field/write-hid-field-value-in-place.d.ts +18 -0
- package/dist/field/write-hid-field-value-in-place.d.ts.map +1 -0
- package/dist/field/write-hid-field-value-in-place.js +41 -0
- package/dist/field/write-hid-field-value-in-place.js.map +1 -0
- package/dist/field/write-hid-field-value.d.ts +18 -0
- package/dist/field/write-hid-field-value.d.ts.map +1 -0
- package/dist/field/write-hid-field-value.js +41 -0
- package/dist/field/write-hid-field-value.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/item/_read-hid-item.d.ts +18 -0
- package/dist/item/_read-hid-item.d.ts.map +1 -0
- package/dist/item/_read-hid-item.js +48 -0
- package/dist/item/_read-hid-item.js.map +1 -0
- package/dist/item/decode-hid-items.d.ts +16 -0
- package/dist/item/decode-hid-items.d.ts.map +1 -0
- package/dist/item/decode-hid-items.js +24 -0
- package/dist/item/decode-hid-items.js.map +1 -0
- package/dist/item/encode-hid-items.d.ts +17 -0
- package/dist/item/encode-hid-items.d.ts.map +1 -0
- package/dist/item/encode-hid-items.js +74 -0
- package/dist/item/encode-hid-items.js.map +1 -0
- package/dist/item/hid-item-tag.d.ts +37 -0
- package/dist/item/hid-item-tag.d.ts.map +1 -0
- package/dist/item/hid-item-tag.js +40 -0
- package/dist/item/hid-item-tag.js.map +1 -0
- package/dist/item/hid-item-value.d.ts +20 -0
- package/dist/item/hid-item-value.d.ts.map +1 -0
- package/dist/item/hid-item-value.js +36 -0
- package/dist/item/hid-item-value.js.map +1 -0
- package/dist/item/hid-item.d.ts +32 -0
- package/dist/item/hid-item.d.ts.map +1 -0
- package/dist/item/hid-item.js +2 -0
- package/dist/item/hid-item.js.map +1 -0
- package/dist/unit/decode-hid-unit.d.ts +9 -0
- package/dist/unit/decode-hid-unit.d.ts.map +1 -0
- package/dist/unit/decode-hid-unit.js +26 -0
- package/dist/unit/decode-hid-unit.js.map +1 -0
- package/dist/unit/encode-hid-unit.d.ts +10 -0
- package/dist/unit/encode-hid-unit.d.ts.map +1 -0
- package/dist/unit/encode-hid-unit.js +32 -0
- package/dist/unit/encode-hid-unit.js.map +1 -0
- package/dist/unit/hid-unit.d.ts +29 -0
- package/dist/unit/hid-unit.d.ts.map +1 -0
- package/dist/unit/hid-unit.js +11 -0
- package/dist/unit/hid-unit.js.map +1 -0
- package/package.json +60 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @ac-kit/format-hid
|
|
2
|
+
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [aca1cb1]
|
|
8
|
+
- @ac-kit/core@0.4.0
|
|
9
|
+
|
|
10
|
+
## 0.1.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 992cbbb: New package: USB HID 1.11 report descriptors, from the raw items to the bits of
|
|
15
|
+
a single field.
|
|
16
|
+
|
|
17
|
+
- `decodeHidItems`/`encodeHidItems` split a descriptor into its short and long
|
|
18
|
+
items and spell them back byte for byte, with `HidMainTag`, `HidGlobalTag` and
|
|
19
|
+
`HidLocalTag` naming every tag and `hidItemUnsigned`/`hidItemSigned` reading
|
|
20
|
+
an item's value.
|
|
21
|
+
- `parseHidReportDescriptor` runs the HID 1.11 §6.2.2 state machine — Push/Pop,
|
|
22
|
+
local state cleared at every main item, extended usages, delimited sets,
|
|
23
|
+
Report IDs — into the collections, the reports with their length as
|
|
24
|
+
transferred, and the fields tiling each report, padding included. It reads
|
|
25
|
+
descriptors the way the Linux HID core does where devices and the
|
|
26
|
+
specification disagree: a Maximum is unsigned unless its Minimum is negative,
|
|
27
|
+
a one-byte Unit Exponent is a 4-bit nibble, and physical bounds both 0 mean
|
|
28
|
+
the logical range. Usage ranges stay ranges, so a whole-page range costs one
|
|
29
|
+
slot; `hidFieldUsage` resolves the usage of one element. A malformed
|
|
30
|
+
descriptor throws `HidDescriptorError` with the byte offset of the offending
|
|
31
|
+
item.
|
|
32
|
+
- `readHidFieldValue`, `writeHidFieldValueInPlace` and `createHidReport` read
|
|
33
|
+
and build report buffers at the field offsets the parser returns, Report ID
|
|
34
|
+
byte included, and `hidLogicalToPhysical` converts a value to its physical
|
|
35
|
+
quantity. `decodeHidUnit`/`encodeHidUnit` split the unit word into its system
|
|
36
|
+
and the exponent of each base quantity.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Anthony Champagne and contributors
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,97 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ac-kit/format-hid
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
USB HID 1.11 report descriptors: what a device's reports look like, read from
|
|
4
|
+
the descriptor it publishes, and the bit-level access to read and build those
|
|
5
|
+
reports.
|
|
6
|
+
|
|
7
|
+
A HID device describes its own reports in a compact item language. Before a
|
|
8
|
+
single input report can be decoded, or an output report built, that language has
|
|
9
|
+
to be run through the state machine of HID 1.11 §6.2.2 — global state with
|
|
10
|
+
Push/Pop, local state cleared after every main item, Report IDs, usage ranges,
|
|
11
|
+
delimited sets. This package does that once and hands back a plain layout:
|
|
12
|
+
which reports exist, how long each is on the wire, and where every field sits.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {
|
|
16
|
+
createHidReport,
|
|
17
|
+
parseHidReportDescriptor,
|
|
18
|
+
readHidFieldValue,
|
|
19
|
+
writeHidFieldValueInPlace,
|
|
20
|
+
} from "@ac-kit/format-hid";
|
|
21
|
+
|
|
22
|
+
const { reports } = parseHidReportDescriptor(descriptorBytes);
|
|
23
|
+
|
|
24
|
+
const input = reports.find((report) => report.kind === "input" && report.reportId === 0x01)!;
|
|
25
|
+
readHidFieldValue(received, input.fields[2]!, 0); // logical value of element 0
|
|
26
|
+
|
|
27
|
+
const lights = reports.find((report) => report.kind === "output" && report.reportId === 0x82)!;
|
|
28
|
+
const bytes = createHidReport(lights); // zeroed, bytes[0] === 0x82
|
|
29
|
+
writeHidFieldValueInPlace(bytes, lights.fields[0]!, 182, 127);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
It reads no device: get the descriptor from wherever the platform exposes it —
|
|
33
|
+
`/sys/class/hidraw/*/device/report_descriptor` on Linux, a USB `GET_DESCRIPTOR`
|
|
34
|
+
request — and move reports with whatever transport you already have.
|
|
35
|
+
|
|
36
|
+
## Three levels
|
|
37
|
+
|
|
38
|
+
- **Items** — `decodeHidItems` splits a descriptor into raw `HidItem`s and
|
|
39
|
+
`encodeHidItems` spells them back, byte for byte. Use it to inspect, patch or
|
|
40
|
+
generate a descriptor. `HidMainTag`, `HidGlobalTag` and `HidLocalTag` name
|
|
41
|
+
every tag; `hidItemUnsigned`/`hidItemSigned` read an item's value.
|
|
42
|
+
- **Descriptor** — `parseHidReportDescriptor` returns the `collections`, the
|
|
43
|
+
`reports` and whether the device `usesReportIds`. Each `HidReportField` carries
|
|
44
|
+
its position, size, count, data flags, logical and physical ranges, unit, and
|
|
45
|
+
its usages, designators and strings as slots. `hidFieldUsage` gives the usage
|
|
46
|
+
an element refers to.
|
|
47
|
+
- **Field values** — `readHidFieldValue`, `writeHidFieldValueInPlace`,
|
|
48
|
+
`createHidReport` and `hidLogicalToPhysical` work on a report buffer.
|
|
49
|
+
`decodeHidUnit`/`encodeHidUnit` split the unit word into its system and
|
|
50
|
+
exponents.
|
|
51
|
+
|
|
52
|
+
## Reports as transferred
|
|
53
|
+
|
|
54
|
+
Every position is counted from the first bit of the report **as it travels on
|
|
55
|
+
the wire**: when the descriptor uses Report IDs, the ID is byte 0, the first
|
|
56
|
+
field starts at bit 8, and `byteLength` includes it. That is what `read()` on a
|
|
57
|
+
Linux `hidraw` node returns, and what `write()` on one takes for a device using
|
|
58
|
+
Report IDs (for one that does not, `hidraw` wants an extra leading 0 byte).
|
|
59
|
+
WebHID strips the ID byte from `inputreport` events and takes it as a separate
|
|
60
|
+
argument to `sendReport`; put it back in front, or build the buffer with
|
|
61
|
+
`createHidReport`, before using the field offsets.
|
|
62
|
+
|
|
63
|
+
Padding and constant fields are kept, so a report's fields tile it completely.
|
|
64
|
+
|
|
65
|
+
## Where real devices and the specification disagree
|
|
66
|
+
|
|
67
|
+
The parser reads descriptors the way the Linux HID core does, because that is
|
|
68
|
+
what devices are tested against:
|
|
69
|
+
|
|
70
|
+
- A Logical or Physical Maximum is **unsigned unless its Minimum is negative**:
|
|
71
|
+
`Logical Minimum (0)`, `Logical Maximum (0xFF)` is 0–255, not 0 to -1.
|
|
72
|
+
- A one-byte Unit Exponent of 0–15 is a 4-bit two's-complement nibble, so
|
|
73
|
+
`0x0E` is -2.
|
|
74
|
+
- A Usage declared before a later Usage Page takes the page in effect at the
|
|
75
|
+
main item.
|
|
76
|
+
- Physical Minimum and Maximum both 0 means the physical range is the logical
|
|
77
|
+
one.
|
|
78
|
+
|
|
79
|
+
## Usages
|
|
80
|
+
|
|
81
|
+
A usage is an unsigned 32-bit number, `page << 16 | id`; a 4-byte Usage item is
|
|
82
|
+
taken whole as such an extended usage. `Usage Minimum`/`Usage Maximum` pairs stay
|
|
83
|
+
ranges — a field covering a whole 65 536-usage page costs one slot — and a
|
|
84
|
+
delimited set becomes one slot whose first usage is preferred and whose others
|
|
85
|
+
are its `aliases`. For a variable field with fewer usages than values, the last
|
|
86
|
+
usage applies to every remaining element.
|
|
87
|
+
|
|
88
|
+
## Errors
|
|
89
|
+
|
|
90
|
+
A malformed descriptor throws `HidDescriptorError`, a `SyntaxError` carrying the
|
|
91
|
+
byte `offset` of the item the parser gave up at. An argument the caller built
|
|
92
|
+
that cannot be honoured — an item `encodeHidItems` cannot spell, a value that
|
|
93
|
+
does not fit its field, an index past `count` — is a `RangeError`.
|
|
94
|
+
|
|
95
|
+
See the
|
|
96
|
+
[generated API docs](https://anthochamp.github.io/node-essentials/api/format-hid/)
|
|
97
|
+
for the full reference.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HidFieldFlags, HidReportField, HidSlot } from "./hid-report-descriptor.js";
|
|
2
|
+
/**
|
|
3
|
+
* The value at position `index` of a slot list once its ranges are expanded, or
|
|
4
|
+
* `undefined` past the end. Ranges are never materialized.
|
|
5
|
+
*
|
|
6
|
+
* Use {@link hidFieldUsage} for a field's usages, which applies the HID rule for
|
|
7
|
+
* a variable field with fewer usages than values.
|
|
8
|
+
*
|
|
9
|
+
* O(n) time in `slots.length`, O(1) memory.
|
|
10
|
+
*
|
|
11
|
+
* @throws {RangeError} When `index` is not a non-negative integer.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hidSlotValue(slots: readonly HidSlot[], index: number): number | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The usage a field's value refers to.
|
|
16
|
+
*
|
|
17
|
+
* - **Variable field** — `index` is the element, `0 ≤ index < count`. When the
|
|
18
|
+
* field declares fewer usages than values, the last usage applies to every
|
|
19
|
+
* remaining element (HID 1.11 §6.2.2.8).
|
|
20
|
+
* - **Array field** — `index` is a position in the usage list, i.e. a received
|
|
21
|
+
* value minus `logicalMinimum`. A position past the list is `undefined`, as
|
|
22
|
+
* is any position in a field declaring no usage (padding).
|
|
23
|
+
*
|
|
24
|
+
* Aliases of a delimited set are on {@link HidReportField.usages}; this answers
|
|
25
|
+
* the preferred usage only.
|
|
26
|
+
*
|
|
27
|
+
* O(n) time in `field.usages.length`, O(1) memory.
|
|
28
|
+
*
|
|
29
|
+
* @throws {RangeError} When `index` is negative or not an integer, or is
|
|
30
|
+
* `count` or more for a variable field.
|
|
31
|
+
*/
|
|
32
|
+
export declare function hidFieldUsage(field: Pick<HidReportField, "count" | "usages"> & {
|
|
33
|
+
flags: Pick<HidFieldFlags, "variable">;
|
|
34
|
+
}, index: number): number | undefined;
|
|
35
|
+
//# sourceMappingURL=hid-field-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hid-field-usage.d.ts","sourceRoot":"","sources":["../../src/descriptor/hid-field-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,cAAc,EACd,OAAO,EACP,MAAM,4BAA4B,CAAC;AAMpC;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAiBpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG;IACjD,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;CACvC,EACD,KAAK,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAoBpB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
function slotLength_(slot) {
|
|
2
|
+
return slot.kind === "single" ? 1 : slot.maximum - slot.minimum + 1;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* The value at position `index` of a slot list once its ranges are expanded, or
|
|
6
|
+
* `undefined` past the end. Ranges are never materialized.
|
|
7
|
+
*
|
|
8
|
+
* Use {@link hidFieldUsage} for a field's usages, which applies the HID rule for
|
|
9
|
+
* a variable field with fewer usages than values.
|
|
10
|
+
*
|
|
11
|
+
* O(n) time in `slots.length`, O(1) memory.
|
|
12
|
+
*
|
|
13
|
+
* @throws {RangeError} When `index` is not a non-negative integer.
|
|
14
|
+
*/
|
|
15
|
+
export function hidSlotValue(slots, index) {
|
|
16
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
17
|
+
throw new RangeError(`hidSlotValue: index ${index} is not a non-negative integer`);
|
|
18
|
+
}
|
|
19
|
+
let remaining = index;
|
|
20
|
+
for (const slot of slots) {
|
|
21
|
+
const length = slotLength_(slot);
|
|
22
|
+
if (remaining < length) {
|
|
23
|
+
return slot.kind === "single" ? slot.value : slot.minimum + remaining;
|
|
24
|
+
}
|
|
25
|
+
remaining -= length;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The usage a field's value refers to.
|
|
31
|
+
*
|
|
32
|
+
* - **Variable field** — `index` is the element, `0 ≤ index < count`. When the
|
|
33
|
+
* field declares fewer usages than values, the last usage applies to every
|
|
34
|
+
* remaining element (HID 1.11 §6.2.2.8).
|
|
35
|
+
* - **Array field** — `index` is a position in the usage list, i.e. a received
|
|
36
|
+
* value minus `logicalMinimum`. A position past the list is `undefined`, as
|
|
37
|
+
* is any position in a field declaring no usage (padding).
|
|
38
|
+
*
|
|
39
|
+
* Aliases of a delimited set are on {@link HidReportField.usages}; this answers
|
|
40
|
+
* the preferred usage only.
|
|
41
|
+
*
|
|
42
|
+
* O(n) time in `field.usages.length`, O(1) memory.
|
|
43
|
+
*
|
|
44
|
+
* @throws {RangeError} When `index` is negative or not an integer, or is
|
|
45
|
+
* `count` or more for a variable field.
|
|
46
|
+
*/
|
|
47
|
+
export function hidFieldUsage(field, index) {
|
|
48
|
+
if (!field.flags.variable) {
|
|
49
|
+
return hidSlotValue(field.usages, index);
|
|
50
|
+
}
|
|
51
|
+
if (!Number.isInteger(index) || index < 0 || index >= field.count) {
|
|
52
|
+
throw new RangeError(`hidFieldUsage: index ${index} is outside 0–${field.count - 1}`);
|
|
53
|
+
}
|
|
54
|
+
let total = 0;
|
|
55
|
+
for (const slot of field.usages) {
|
|
56
|
+
total += slotLength_(slot);
|
|
57
|
+
}
|
|
58
|
+
if (total === 0) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return hidSlotValue(field.usages, Math.min(index, total - 1));
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=hid-field-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hid-field-usage.js","sourceRoot":"","sources":["../../src/descriptor/hid-field-usage.ts"],"names":[],"mappings":"AAMA,SAAS,WAAW,CAAC,IAAa;IACjC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC3B,KAAyB,EACzB,KAAa;IAEb,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,UAAU,CACnB,uBAAuB,KAAK,gCAAgC,CAC5D,CAAC;IACH,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACvE,CAAC;QACD,SAAS,IAAI,MAAM,CAAC;IACrB,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,aAAa,CAC5B,KAEC,EACD,KAAa;IAEb,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QACnE,MAAM,IAAI,UAAU,CACnB,wBAAwB,KAAK,iBAAiB,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAC/D,CAAC;IACH,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,KAAK,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection types of the Collection main item (HID 1.11 §6.2.2.6). 0x07–0x7F
|
|
3
|
+
* are reserved, 0x80–0xFF vendor-defined.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum HidCollectionType {
|
|
6
|
+
PHYSICAL = 0,
|
|
7
|
+
APPLICATION = 1,
|
|
8
|
+
LOGICAL = 2,
|
|
9
|
+
REPORT = 3,
|
|
10
|
+
NAMED_ARRAY = 4,
|
|
11
|
+
USAGE_SWITCH = 5,
|
|
12
|
+
USAGE_MODIFIER = 6
|
|
13
|
+
}
|
|
14
|
+
/** Which of the three report kinds a field belongs to. */
|
|
15
|
+
export type HidReportKind = "input" | "output" | "feature";
|
|
16
|
+
/**
|
|
17
|
+
* One position, or a run of positions, in a field's list of usages, designators
|
|
18
|
+
* or strings.
|
|
19
|
+
*
|
|
20
|
+
* Usages are 32-bit extended usages, `page << 16 | id`, read as unsigned.
|
|
21
|
+
* Designators and strings are plain indexes and never carry aliases.
|
|
22
|
+
*/
|
|
23
|
+
export type HidSlot = {
|
|
24
|
+
kind: "single";
|
|
25
|
+
value: number;
|
|
26
|
+
/**
|
|
27
|
+
* The other usages of a delimited set (HID 1.11 §6.2.2.8), in declaration
|
|
28
|
+
* order.
|
|
29
|
+
*/
|
|
30
|
+
aliases: number[];
|
|
31
|
+
} | {
|
|
32
|
+
kind: "range";
|
|
33
|
+
/** First value of the range, inclusive. */
|
|
34
|
+
minimum: number;
|
|
35
|
+
/** Last value of the range, inclusive. Never below `minimum`. */
|
|
36
|
+
maximum: number;
|
|
37
|
+
};
|
|
38
|
+
/** One collection, in a flat table in descriptor (pre-)order. */
|
|
39
|
+
export type HidCollection = {
|
|
40
|
+
/**
|
|
41
|
+
* A {@link HidCollectionType}, or the raw number of a reserved or
|
|
42
|
+
* vendor-defined type.
|
|
43
|
+
*/
|
|
44
|
+
type: number;
|
|
45
|
+
/**
|
|
46
|
+
* The first usage declared before the Collection item, or `undefined` when
|
|
47
|
+
* there was none.
|
|
48
|
+
*/
|
|
49
|
+
usage: number | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Index of the enclosing collection in the same table, or -1 at the top
|
|
52
|
+
* level.
|
|
53
|
+
*/
|
|
54
|
+
parentIndex: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The data bits of an Input, Output or Feature main item (HID 1.11 §6.2.2.5),
|
|
58
|
+
* one boolean per bit.
|
|
59
|
+
*/
|
|
60
|
+
export type HidFieldFlags = {
|
|
61
|
+
/** Bit 0: the values are fixed padding rather than data. */
|
|
62
|
+
constant: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Bit 1: one value per usage (variable) rather than a list of active usages
|
|
65
|
+
* (array).
|
|
66
|
+
*/
|
|
67
|
+
variable: boolean;
|
|
68
|
+
/** Bit 2: values are deltas from the previous report rather than absolute. */
|
|
69
|
+
relative: boolean;
|
|
70
|
+
/** Bit 3: values wrap from one extreme to the other. */
|
|
71
|
+
wrap: boolean;
|
|
72
|
+
/** Bit 4: the data is not linear in what it measures. */
|
|
73
|
+
nonLinear: boolean;
|
|
74
|
+
/** Bit 5: the control has no rest position. */
|
|
75
|
+
noPreferredState: boolean;
|
|
76
|
+
/** Bit 6: a value outside the logical range means "no data". */
|
|
77
|
+
nullState: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Bit 7: the device may change the value on its own. Always `false` for an
|
|
80
|
+
* input field, whose bit 7 is reserved.
|
|
81
|
+
*/
|
|
82
|
+
volatile: boolean;
|
|
83
|
+
/** Bit 8: the field is a byte stream rather than a number. */
|
|
84
|
+
bufferedBytes: boolean;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* One Input, Output or Feature main item: `count` values of `bitSize` bits
|
|
88
|
+
* each, packed little-endian and least significant bit first.
|
|
89
|
+
*/
|
|
90
|
+
export type HidReportField = {
|
|
91
|
+
kind: HidReportKind;
|
|
92
|
+
/**
|
|
93
|
+
* The report this field belongs to, or 0 when the descriptor declares no
|
|
94
|
+
* Report ID.
|
|
95
|
+
*/
|
|
96
|
+
reportId: number;
|
|
97
|
+
/**
|
|
98
|
+
* Position of the field's first bit from the first bit of the report as
|
|
99
|
+
* transferred — the Report ID byte included when there is one.
|
|
100
|
+
*/
|
|
101
|
+
bitOffset: number;
|
|
102
|
+
/** Report Size: bits per value. */
|
|
103
|
+
bitSize: number;
|
|
104
|
+
/** Report Count: number of values. */
|
|
105
|
+
count: number;
|
|
106
|
+
flags: HidFieldFlags;
|
|
107
|
+
logicalMinimum: number;
|
|
108
|
+
logicalMaximum: number;
|
|
109
|
+
/** Equal to `logicalMinimum` when the descriptor leaves both physical bounds 0. */
|
|
110
|
+
physicalMinimum: number;
|
|
111
|
+
/** Equal to `logicalMaximum` when the descriptor leaves both physical bounds 0. */
|
|
112
|
+
physicalMaximum: number;
|
|
113
|
+
/** The raw unit word; see {@link decodeHidUnit}. */
|
|
114
|
+
unit: number;
|
|
115
|
+
/** Base-10 exponent applied to physical values. */
|
|
116
|
+
unitExponent: number;
|
|
117
|
+
/**
|
|
118
|
+
* Usage slots in declaration order; see {@link hidFieldUsage}. Empty for
|
|
119
|
+
* padding.
|
|
120
|
+
*/
|
|
121
|
+
usages: HidSlot[];
|
|
122
|
+
designators: HidSlot[];
|
|
123
|
+
strings: HidSlot[];
|
|
124
|
+
/**
|
|
125
|
+
* Index in {@link HidReportDescriptor.collections} of the innermost enclosing
|
|
126
|
+
* collection, or -1.
|
|
127
|
+
*/
|
|
128
|
+
collectionIndex: number;
|
|
129
|
+
};
|
|
130
|
+
/** Every field one report carries, and its size on the wire. */
|
|
131
|
+
export type HidReport = {
|
|
132
|
+
kind: HidReportKind;
|
|
133
|
+
/** 0 when the descriptor declares no Report ID. */
|
|
134
|
+
reportId: number;
|
|
135
|
+
/** Bytes as transferred, the Report ID byte included. */
|
|
136
|
+
byteLength: number;
|
|
137
|
+
/** In descriptor order, padding included, so the fields tile the report. */
|
|
138
|
+
fields: HidReportField[];
|
|
139
|
+
};
|
|
140
|
+
/** The reports and collections a report descriptor declares. */
|
|
141
|
+
export type HidReportDescriptor = {
|
|
142
|
+
collections: HidCollection[];
|
|
143
|
+
/** In order of first appearance. */
|
|
144
|
+
reports: HidReport[];
|
|
145
|
+
/** Whether every report starts with a Report ID byte. */
|
|
146
|
+
usesReportIds: boolean;
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=hid-report-descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hid-report-descriptor.d.ts","sourceRoot":"","sources":["../../src/descriptor/hid-report-descriptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection types of the Collection main item (HID 1.11 §6.2.2.6). 0x07–0x7F
|
|
3
|
+
* are reserved, 0x80–0xFF vendor-defined.
|
|
4
|
+
*/
|
|
5
|
+
export var HidCollectionType;
|
|
6
|
+
(function (HidCollectionType) {
|
|
7
|
+
HidCollectionType[HidCollectionType["PHYSICAL"] = 0] = "PHYSICAL";
|
|
8
|
+
HidCollectionType[HidCollectionType["APPLICATION"] = 1] = "APPLICATION";
|
|
9
|
+
HidCollectionType[HidCollectionType["LOGICAL"] = 2] = "LOGICAL";
|
|
10
|
+
HidCollectionType[HidCollectionType["REPORT"] = 3] = "REPORT";
|
|
11
|
+
HidCollectionType[HidCollectionType["NAMED_ARRAY"] = 4] = "NAMED_ARRAY";
|
|
12
|
+
HidCollectionType[HidCollectionType["USAGE_SWITCH"] = 5] = "USAGE_SWITCH";
|
|
13
|
+
HidCollectionType[HidCollectionType["USAGE_MODIFIER"] = 6] = "USAGE_MODIFIER";
|
|
14
|
+
})(HidCollectionType || (HidCollectionType = {}));
|
|
15
|
+
//# sourceMappingURL=hid-report-descriptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hid-report-descriptor.js","sourceRoot":"","sources":["../../src/descriptor/hid-report-descriptor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,iBAQX;AARD,WAAY,iBAAiB;IAC5B,iEAAe,CAAA;IACf,uEAAkB,CAAA;IAClB,+DAAc,CAAA;IACd,6DAAa,CAAA;IACb,uEAAkB,CAAA;IAClB,yEAAmB,CAAA;IACnB,6EAAqB,CAAA;AACtB,CAAC,EARW,iBAAiB,KAAjB,iBAAiB,QAQ5B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HidReportDescriptor } from "./hid-report-descriptor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reads a report descriptor into the reports a device sends and accepts, the
|
|
4
|
+
* fields that tile each one, and the collections around them — the HID 1.11
|
|
5
|
+
* §6.2.2 item state machine, with Push/Pop, delimited sets and extended
|
|
6
|
+
* usages.
|
|
7
|
+
*
|
|
8
|
+
* Use {@link decodeHidItems} instead to see or rewrite the items themselves.
|
|
9
|
+
*
|
|
10
|
+
* Follows the Linux reading wherever real devices and the letter of the spec
|
|
11
|
+
* disagree: a Logical or Physical Maximum is unsigned unless its Minimum is
|
|
12
|
+
* negative, so `0xFF` means 255; a one-byte Unit Exponent of 0–15 is a 4-bit
|
|
13
|
+
* two's-complement nibble; a Usage declared before a later Usage Page takes the
|
|
14
|
+
* page in effect at the main item. Long items, reserved main and local tags and
|
|
15
|
+
* reserved item types are skipped.
|
|
16
|
+
*
|
|
17
|
+
* Usage ranges are kept as ranges, so a field declaring `Usage Minimum (0)`,
|
|
18
|
+
* `Usage Maximum (0xFFFF)` costs one slot, not 65 536.
|
|
19
|
+
*
|
|
20
|
+
* O(n) time and memory in `bytes.length`.
|
|
21
|
+
*
|
|
22
|
+
* @throws {HidDescriptorError} When an item is truncated, a collection is left
|
|
23
|
+
* open or closed twice, `Pop` meets an empty stack, a data item has no Report
|
|
24
|
+
* Size or Report Count, a report grows past 65 535 bytes, a Report ID is 0, a
|
|
25
|
+
* data item carries no Report ID in a descriptor that declares one, a usage,
|
|
26
|
+
* designator or string range is unpaired or reversed, a delimited set is
|
|
27
|
+
* nested or unbalanced, or a reserved global tag appears.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseHidReportDescriptor(bytes: Uint8Array): HidReportDescriptor;
|
|
30
|
+
//# sourceMappingURL=parse-hid-report-descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-hid-report-descriptor.d.ts","sourceRoot":"","sources":["../../src/descriptor/parse-hid-report-descriptor.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAGX,mBAAmB,EAInB,MAAM,4BAA4B,CAAC;AAokBpC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,UAAU,GACf,mBAAmB,CAErB"}
|