From 7b10a530b3017c9719e9b3dd64a7abfc0145ad5d Mon Sep 17 00:00:00 2001 From: Macy Abbey Date: Sat, 8 Dec 2018 21:35:09 -0500 Subject: [PATCH 1/2] Adding support for shift modified keycodes. Adding comments referencing relevant USB HID specifications. Maintain legacy support for old hidMap format, and new hidMap format of : { unmodified: "", shift: ""}. This allows for uppercase and lowercase alphanumeric strings, as well as many special characters that didn't work before. The most glaring problems occurred when attempting to scan a QRcode which contained a URL. --- src/usb-barcode-scanner-utils.ts | 259 ++++++++++++++++++++++++++----- src/usb-barcode-scanner.ts | 54 ++++++- 2 files changed, 267 insertions(+), 46 deletions(-) diff --git a/src/usb-barcode-scanner-utils.ts b/src/usb-barcode-scanner-utils.ts index 16ba96a..64e0491 100644 --- a/src/usb-barcode-scanner-utils.ts +++ b/src/usb-barcode-scanner-utils.ts @@ -13,50 +13,223 @@ export function getDeviceByPath(path: string): Device|undefined { return _.find(getDevices(), { 'path': path }); } + +/** + * Keyboard keycodes defined in USB HID Usage Tables specification + * https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf + * Page 53 + * + * Map is + * + * Usage Id (Decimal) : { + * unmodified: "", + * shift: "" + * } + */ export function defaultHidMap(): Object { return { - 4: "A", - 5: "B", - 6: "C", - 7: "D", - 8: "E", - 9: "F", - 10: "G", - 11: "H", - 12: "I", - 13: "J", - 14: "K", - 15: "L", - 16: "M", - 17: "N", - 18: "O", - 19: "P", - 20: "Q", - 21: "R", - 22: "S", - 23: "T", - 24: "U", - 25: "V", - 26: "W", - 27: "X", - 28: "Y", - 29: "Z", - 30: "1", - 31: "2", - 32: "3", - 33: "4", - 34: "5", - 35: "6", - 36: "7", - 37: "8", - 38: "9", - 39: "0", - 40: "enter", - 44: " ", - 45: "-", - 55: ".", - 56: "/", - 85: "*", - 87: "+" + 4: { + unmodified: "a", + shift: "A" + }, + 5: { + unmodified: "b", + shift: "B" + }, + 6: { + unmodified: "c", + shift: "C" + }, + 7: { + unmodified: "d", + shift: "D" + }, + 8: { + unmodified: "e", + shift: "E" + }, + 9: { + unmodified: "f", + shift: "F" + }, + 10: { + unmodified: "g", + shift: "G" + }, + 11: { + unmodified: "h", + shift: "H" + }, + 12: { + unmodified: "i", + shift: "I" + }, + 13: { + unmodified: "j", + shift: "J" + }, + 14: { + unmodified: "k", + shift: "K" + }, + 15: { + unmodified: "l", + shift: "L" + }, + 16: { + unmodified: "m", + shift: "M" + }, + 17: { + unmodified: "n", + shift: "N" + }, + 18: { + unmodified: "o", + shift: "O" + }, + 19: { + unmodified: "p", + shift: "P" + }, + 20: { + unmodified: "q", + shift: "Q" + }, + 21: { + unmodified: "r", + shift: "R" + }, + 22: { + unmodified: "s", + shift: "S" + }, + 23: { + unmodified: "t", + shift: "T" + }, + 24: { + unmodified: "u", + shift: "U" + }, + 25: { + unmodified: "v", + shift: "V" + }, + 26: { + unmodified: "w", + shift: "W" + }, + 27: { + unmodified: "x", + shift: "X" + }, + 28: { + unmodified: "y", + shift: "Y" + }, + 29: { + unmodified: "z", + shift: "Z" + }, + 30: { + unmodified: "1", + shift: "!" + }, + 31: { + unmodified: "2", + shift: "@" + }, + 32: { + unmodified: "3", + shift: "#" + }, + 33: { + unmodified: "4", + shift: "$" + }, + 34: { + unmodified: "5", + shift: "%" + }, + 35: { + unmodified: "6", + shift: "^" + }, + 36: { + unmodified: "7", + shift: "&" + }, + 37: { + unmodified: "8", + shift: "*" + }, + 38: { + unmodified: "9", + shift: "(" + }, + 39: { + unmodified: "0", + shift: ")" + }, + 40: { + unmodified: "enter" + }, + 43: { + unmodified: "\t", + }, + 44: { + unmodified: " " + }, + 45: { + unmodified: "-", + shift: "_" + }, + 46: { + unmodified: "=", + shift: "+" + }, + 47: { + unmodified: "[", + shift: "{" + }, + 48: { + unmodified: "]", + shift: "}" + }, + 49: { + unmodified: "\\", + shift: "|" + }, + 51: { + unmodified: ";", + shift: ":" + }, + 52: { + unmodified: "'", + shift: "\"" + }, + 53: { + unmodified: "`", + shift: "~" + }, + 54: { + unmodified: ",", + shift: "<" + }, + 55: { + unmodified: ".", + shift: ">" + }, + 56: { + unmodified: "/", + shift: "?" + }, + 85: { + unmodified: "*", + }, + 87: { + unmodified: "+" + } } } \ No newline at end of file diff --git a/src/usb-barcode-scanner.ts b/src/usb-barcode-scanner.ts index 828c915..e3976b3 100644 --- a/src/usb-barcode-scanner.ts +++ b/src/usb-barcode-scanner.ts @@ -41,14 +41,62 @@ export class UsbScanner extends EventEmitter implements onDataScanned { } startScanning(): void { + /** + * USB HID Report Specification: https://www.usb.org/sites/default/files/documents/hid1_11.pdf + * Starting Page 55 + * + * Note USB barcode scanners always send a "input" type report which is a "long item" of 8 bytes. + */ + + /** + * Page 60 in the specification + */ + const HID_REPORT_BYTE_SIGNIFICANCE = { + MODIFIER: 0, + RESERVED: 1, + KEY_CODE_1: 2, + KEY_CODE_2: 3, + KEY_CODE_3: 4, + KEY_CODE_4: 5, + KEY_CODE_5: 6, + KEY_CODE_6: 7 + }; + + const MODIFIER_BITS = { + LEFT_CTRL: 0x0, + LEFT_SHIFT: 0x1, + LEFT_ALT: 0x2, + LEFT_GUI: 0x3, + RIGHT_CTRL: 0x4, + RIGHT_SHIFT: 0x5, + RIGHT_ALT: 0x6, + RIGHT_GUI: 0x7 + }; + + const REPORT_ENDING_KEY_CODE = 40; + let bcodeBuffer: string[] = []; let barcode: string = ''; if (this.hid) { this.hid.on('data', (chunk) => { - if (this.hidMap[chunk[2]]) { - if (chunk[2] !== 40) { - bcodeBuffer.push(this.hidMap[chunk[2]]); + let keyCode1 = chunk[HID_REPORT_BYTE_SIGNIFICANCE.KEY_CODE_1]; + let modifierByte = chunk[HID_REPORT_BYTE_SIGNIFICANCE.MODIFIER]; + let isShiftModified = modifierByte & MODIFIER_BITS.LEFT_SHIFT || modifierByte & MODIFIER_BITS.RIGHT_SHIFT; + if (keyCode1) { + if (keyCode1 !== REPORT_ENDING_KEY_CODE) { + let hidMapEntry = this.hidMap[keyCode1]; + if (hidMapEntry) { + if (typeof hidMapEntry === 'object') { + if (isShiftModified && hidMapEntry.shift) { + bcodeBuffer.push(hidMapEntry.shift); + } else { + bcodeBuffer.push(hidMapEntry.unmodified); + } + } else { + bcodeBuffer.push(hidMapEntry); + } + } } else { barcode = bcodeBuffer.join(""); bcodeBuffer = []; From 556e4ae549c52cd0a6e1b9740094218372d74214 Mon Sep 17 00:00:00 2001 From: Macy Abbey Date: Fri, 14 Dec 2018 10:03:51 -0500 Subject: [PATCH 2/2] Giving the right bit address for the different types of modifiers. --- src/usb-barcode-scanner.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/usb-barcode-scanner.ts b/src/usb-barcode-scanner.ts index e3976b3..60f6800 100644 --- a/src/usb-barcode-scanner.ts +++ b/src/usb-barcode-scanner.ts @@ -63,14 +63,14 @@ export class UsbScanner extends EventEmitter implements onDataScanned { }; const MODIFIER_BITS = { - LEFT_CTRL: 0x0, - LEFT_SHIFT: 0x1, - LEFT_ALT: 0x2, - LEFT_GUI: 0x3, - RIGHT_CTRL: 0x4, - RIGHT_SHIFT: 0x5, - RIGHT_ALT: 0x6, - RIGHT_GUI: 0x7 + LEFT_CTRL: 0x1, + LEFT_SHIFT: 0x2, + LEFT_ALT: 0x3, + LEFT_GUI: 0x4, + RIGHT_CTRL: 0x5, + RIGHT_SHIFT: 0x6, + RIGHT_ALT: 0x7, + RIGHT_GUI: 0x8 }; const REPORT_ENDING_KEY_CODE = 40;