diff --git a/config-tool-web/usages.js b/config-tool-web/usages.js
index 44b1672..246a44a 100644
--- a/config-tool-web/usages.js
+++ b/config-tool-web/usages.js
@@ -1,159 +1,415 @@
const usages = {
- "0x00090001": { 'name': 'Left button', 'class': 'mouse' },
- "0x00090002": { 'name': 'Right button', 'class': 'mouse' },
- "0x00090003": { 'name': 'Middle button', 'class': 'mouse' },
- "0x00090004": { 'name': 'Back', 'class': 'mouse' },
- "0x00090005": { 'name': 'Forward', 'class': 'mouse' },
- "0x00090006": { 'name': 'Button 6', 'class': 'mouse' },
- "0x00090007": { 'name': 'Button 7', 'class': 'mouse' },
- "0x00090008": { 'name': 'Button 8', 'class': 'mouse' },
- "0x00010030": { 'name': 'Cursor X', 'class': 'mouse' },
- "0x00010031": { 'name': 'Cursor Y', 'class': 'mouse' },
- "0x00010038": { 'name': 'V scroll', 'class': 'mouse' },
- "0x000c0238": { 'name': 'H scroll', 'class': 'mouse' },
+ 'source': {
+ "0x00090001": { 'name': 'Left button', 'class': 'mouse' },
+ "0x00090002": { 'name': 'Right button', 'class': 'mouse' },
+ "0x00090003": { 'name': 'Middle button', 'class': 'mouse' },
+ "0x00090004": { 'name': 'Back', 'class': 'mouse' },
+ "0x00090005": { 'name': 'Forward', 'class': 'mouse' },
+ "0x00090006": { 'name': 'Button 6', 'class': 'mouse' },
+ "0x00090007": { 'name': 'Button 7', 'class': 'mouse' },
+ "0x00090008": { 'name': 'Button 8', 'class': 'mouse' },
+ "0x00010030": { 'name': 'Cursor X', 'class': 'mouse' },
+ "0x00010031": { 'name': 'Cursor Y', 'class': 'mouse' },
+ "0x00010038": { 'name': 'V scroll', 'class': 'mouse' },
+ "0x000c0238": { 'name': 'H scroll', 'class': 'mouse' },
- "0x000700e0": { 'name': 'Left Control', 'class': 'keyboard' },
- "0x000700e1": { 'name': 'Left Shift', 'class': 'keyboard' },
- "0x000700e2": { 'name': 'Left Alt', 'class': 'keyboard' },
- "0x000700e3": { 'name': 'Left GUI', 'class': 'keyboard' },
- "0x000700e4": { 'name': 'Right Control', 'class': 'keyboard' },
- "0x000700e5": { 'name': 'Right Shift', 'class': 'keyboard' },
- "0x000700e6": { 'name': 'Right Alt', 'class': 'keyboard' },
- "0x000700e7": { 'name': 'Right GUI', 'class': 'keyboard' },
- "0x00070004": { 'name': 'A', 'class': 'keyboard' },
- "0x00070005": { 'name': 'B', 'class': 'keyboard' },
- "0x00070006": { 'name': 'C', 'class': 'keyboard' },
- "0x00070007": { 'name': 'D', 'class': 'keyboard' },
- "0x00070008": { 'name': 'E', 'class': 'keyboard' },
- "0x00070009": { 'name': 'F', 'class': 'keyboard' },
- "0x0007000a": { 'name': 'G', 'class': 'keyboard' },
- "0x0007000b": { 'name': 'H', 'class': 'keyboard' },
- "0x0007000c": { 'name': 'I', 'class': 'keyboard' },
- "0x0007000d": { 'name': 'J', 'class': 'keyboard' },
- "0x0007000e": { 'name': 'K', 'class': 'keyboard' },
- "0x0007000f": { 'name': 'L', 'class': 'keyboard' },
- "0x00070010": { 'name': 'M', 'class': 'keyboard' },
- "0x00070011": { 'name': 'N', 'class': 'keyboard' },
- "0x00070012": { 'name': 'O', 'class': 'keyboard' },
- "0x00070013": { 'name': 'P', 'class': 'keyboard' },
- "0x00070014": { 'name': 'Q', 'class': 'keyboard' },
- "0x00070015": { 'name': 'R', 'class': 'keyboard' },
- "0x00070016": { 'name': 'S', 'class': 'keyboard' },
- "0x00070017": { 'name': 'T', 'class': 'keyboard' },
- "0x00070018": { 'name': 'U', 'class': 'keyboard' },
- "0x00070019": { 'name': 'V', 'class': 'keyboard' },
- "0x0007001a": { 'name': 'W', 'class': 'keyboard' },
- "0x0007001b": { 'name': 'X', 'class': 'keyboard' },
- "0x0007001c": { 'name': 'Y', 'class': 'keyboard' },
- "0x0007001d": { 'name': 'Z', 'class': 'keyboard' },
- "0x0007001e": { 'name': '1', 'class': 'keyboard' },
- "0x0007001f": { 'name': '2', 'class': 'keyboard' },
- "0x00070020": { 'name': '3', 'class': 'keyboard' },
- "0x00070021": { 'name': '4', 'class': 'keyboard' },
- "0x00070022": { 'name': '5', 'class': 'keyboard' },
- "0x00070023": { 'name': '6', 'class': 'keyboard' },
- "0x00070024": { 'name': '7', 'class': 'keyboard' },
- "0x00070025": { 'name': '8', 'class': 'keyboard' },
- "0x00070026": { 'name': '9', 'class': 'keyboard' },
- "0x00070027": { 'name': '0', 'class': 'keyboard' },
- "0x00070028": { 'name': 'Enter', 'class': 'keyboard' },
- "0x00070029": { 'name': 'Escape', 'class': 'keyboard' },
- "0x0007002a": { 'name': 'Backspace', 'class': 'keyboard' },
- "0x0007002b": { 'name': 'Tab', 'class': 'keyboard' },
- "0x0007002c": { 'name': 'Space', 'class': 'keyboard' },
- "0x00070039": { 'name': 'Caps Lock', 'class': 'keyboard' },
- "0x00070046": { 'name': 'PrintScreen', 'class': 'keyboard' },
- "0x00070047": { 'name': 'Scroll Lock', 'class': 'keyboard' },
- "0x00070048": { 'name': 'Pause', 'class': 'keyboard' },
- "0x00070049": { 'name': 'Insert', 'class': 'keyboard' },
- "0x0007004a": { 'name': 'Home', 'class': 'keyboard' },
- "0x0007004b": { 'name': 'PageUp', 'class': 'keyboard' },
- "0x0007004c": { 'name': 'Delete', 'class': 'keyboard' },
- "0x0007004d": { 'name': 'End', 'class': 'keyboard' },
- "0x0007004e": { 'name': 'PageDown', 'class': 'keyboard' },
- "0x0007004f": { 'name': 'Right arrow', 'class': 'keyboard' },
- "0x00070050": { 'name': 'Left arrow', 'class': 'keyboard' },
- "0x00070051": { 'name': 'Down arrow', 'class': 'keyboard' },
- "0x00070052": { 'name': 'Up arrow', 'class': 'keyboard' },
- "0x00070053": { 'name': 'Num Lock', 'class': 'keyboard' },
- "0x0007002d": { 'name': '- _', 'class': 'keyboard' },
- "0x0007002e": { 'name': '= +', 'class': 'keyboard' },
- "0x0007002f": { 'name': '[ {', 'class': 'keyboard' },
- "0x00070030": { 'name': '] }', 'class': 'keyboard' },
- "0x00070031": { 'name': '\\ |', 'class': 'keyboard' },
- "0x00070033": { 'name': '; :', 'class': 'keyboard' },
- "0x00070034": { 'name': '‘ “', 'class': 'keyboard' },
- "0x00070035": { 'name': '` ~', 'class': 'keyboard' },
- "0x00070036": { 'name': ', <', 'class': 'keyboard' },
- "0x00070037": { 'name': '. >', 'class': 'keyboard' },
- "0x00070038": { 'name': '/ ?', 'class': 'keyboard' },
- "0x0007003a": { 'name': 'F1', 'class': 'keyboard' },
- "0x0007003b": { 'name': 'F2', 'class': 'keyboard' },
- "0x0007003c": { 'name': 'F3', 'class': 'keyboard' },
- "0x0007003d": { 'name': 'F4', 'class': 'keyboard' },
- "0x0007003e": { 'name': 'F5', 'class': 'keyboard' },
- "0x0007003f": { 'name': 'F6', 'class': 'keyboard' },
- "0x00070040": { 'name': 'F7', 'class': 'keyboard' },
- "0x00070041": { 'name': 'F8', 'class': 'keyboard' },
- "0x00070042": { 'name': 'F9', 'class': 'keyboard' },
- "0x00070043": { 'name': 'F10', 'class': 'keyboard' },
- "0x00070044": { 'name': 'F11', 'class': 'keyboard' },
- "0x00070045": { 'name': 'F12', 'class': 'keyboard' },
- "0x00070068": { 'name': 'F13', 'class': 'keyboard' },
- "0x00070069": { 'name': 'F14', 'class': 'keyboard' },
- "0x0007006a": { 'name': 'F15', 'class': 'keyboard' },
- "0x0007006b": { 'name': 'F16', 'class': 'keyboard' },
- "0x0007006c": { 'name': 'F17', 'class': 'keyboard' },
- "0x0007006d": { 'name': 'F18', 'class': 'keyboard' },
- "0x0007006e": { 'name': 'F19', 'class': 'keyboard' },
- "0x0007006f": { 'name': 'F20', 'class': 'keyboard' },
- "0x00070070": { 'name': 'F21', 'class': 'keyboard' },
- "0x00070071": { 'name': 'F22', 'class': 'keyboard' },
- "0x00070072": { 'name': 'F23', 'class': 'keyboard' },
- "0x00070073": { 'name': 'F24', 'class': 'keyboard' },
- "0x00070054": { 'name': 'Keypad /', 'class': 'keyboard' },
- "0x00070055": { 'name': 'Keypad *', 'class': 'keyboard' },
- "0x00070056": { 'name': 'Keypad -', 'class': 'keyboard' },
- "0x00070057": { 'name': 'Keypad +', 'class': 'keyboard' },
- "0x00070058": { 'name': 'Keypad Enter', 'class': 'keyboard' },
- "0x00070059": { 'name': 'Keypad 1', 'class': 'keyboard' },
- "0x0007005a": { 'name': 'Keypad 2', 'class': 'keyboard' },
- "0x0007005b": { 'name': 'Keypad 3', 'class': 'keyboard' },
- "0x0007005c": { 'name': 'Keypad 4', 'class': 'keyboard' },
- "0x0007005d": { 'name': 'Keypad 5', 'class': 'keyboard' },
- "0x0007005e": { 'name': 'Keypad 6', 'class': 'keyboard' },
- "0x0007005f": { 'name': 'Keypad 7', 'class': 'keyboard' },
- "0x00070060": { 'name': 'Keypad 8', 'class': 'keyboard' },
- "0x00070061": { 'name': 'Keypad 9', 'class': 'keyboard' },
- "0x00070062": { 'name': 'Keypad 0', 'class': 'keyboard' },
- "0x00070063": { 'name': 'Keypad .', 'class': 'keyboard' },
- "0x00070067": { 'name': 'Keypad =', 'class': 'keyboard' },
- "0x00070064": { 'name': 'Non-US \\ |', 'class': 'keyboard' },
- "0x00070032": { 'name': 'Non-US # ~', 'class': 'keyboard' },
- "0x00070065": { 'name': 'Application', 'class': 'keyboard' },
- "0x00070066": { 'name': 'Power', 'class': 'keyboard' },
- "0x00070087": { 'name': '\\ _', 'class': 'keyboard' },
- "0x00070089": { 'name': '¥ |', 'class': 'keyboard' },
- "0x0007008a": { 'name': 'Henkan', 'class': 'keyboard' },
- "0x0007008b": { 'name': 'Muhenkan', 'class': 'keyboard' },
- "0x00070088": { 'name': 'Kana', 'class': 'keyboard' },
- "0x00070090": { 'name': 'Kana (Mac)', 'class': 'keyboard' },
- "0x00070091": { 'name': 'Eisū (Mac)', 'class': 'keyboard' },
- "0x00080001": { 'name': 'Num Lock LED', 'class': 'keyboard' },
- "0x00080002": { 'name': 'Caps Lock LED', 'class': 'keyboard' },
- "0x00080003": { 'name': 'Scroll Lock LED', 'class': 'keyboard' },
- "0x00080004": { 'name': 'Compose LED', 'class': 'keyboard' },
- "0x00080005": { 'name': 'Kana LED', 'class': 'keyboard' },
+ "0x000700e0": { 'name': 'Left Control', 'class': 'keyboard' },
+ "0x000700e1": { 'name': 'Left Shift', 'class': 'keyboard' },
+ "0x000700e2": { 'name': 'Left Alt', 'class': 'keyboard' },
+ "0x000700e3": { 'name': 'Left GUI', 'class': 'keyboard' },
+ "0x000700e4": { 'name': 'Right Control', 'class': 'keyboard' },
+ "0x000700e5": { 'name': 'Right Shift', 'class': 'keyboard' },
+ "0x000700e6": { 'name': 'Right Alt', 'class': 'keyboard' },
+ "0x000700e7": { 'name': 'Right GUI', 'class': 'keyboard' },
+ "0x00070004": { 'name': 'A', 'class': 'keyboard' },
+ "0x00070005": { 'name': 'B', 'class': 'keyboard' },
+ "0x00070006": { 'name': 'C', 'class': 'keyboard' },
+ "0x00070007": { 'name': 'D', 'class': 'keyboard' },
+ "0x00070008": { 'name': 'E', 'class': 'keyboard' },
+ "0x00070009": { 'name': 'F', 'class': 'keyboard' },
+ "0x0007000a": { 'name': 'G', 'class': 'keyboard' },
+ "0x0007000b": { 'name': 'H', 'class': 'keyboard' },
+ "0x0007000c": { 'name': 'I', 'class': 'keyboard' },
+ "0x0007000d": { 'name': 'J', 'class': 'keyboard' },
+ "0x0007000e": { 'name': 'K', 'class': 'keyboard' },
+ "0x0007000f": { 'name': 'L', 'class': 'keyboard' },
+ "0x00070010": { 'name': 'M', 'class': 'keyboard' },
+ "0x00070011": { 'name': 'N', 'class': 'keyboard' },
+ "0x00070012": { 'name': 'O', 'class': 'keyboard' },
+ "0x00070013": { 'name': 'P', 'class': 'keyboard' },
+ "0x00070014": { 'name': 'Q', 'class': 'keyboard' },
+ "0x00070015": { 'name': 'R', 'class': 'keyboard' },
+ "0x00070016": { 'name': 'S', 'class': 'keyboard' },
+ "0x00070017": { 'name': 'T', 'class': 'keyboard' },
+ "0x00070018": { 'name': 'U', 'class': 'keyboard' },
+ "0x00070019": { 'name': 'V', 'class': 'keyboard' },
+ "0x0007001a": { 'name': 'W', 'class': 'keyboard' },
+ "0x0007001b": { 'name': 'X', 'class': 'keyboard' },
+ "0x0007001c": { 'name': 'Y', 'class': 'keyboard' },
+ "0x0007001d": { 'name': 'Z', 'class': 'keyboard' },
+ "0x0007001e": { 'name': '1', 'class': 'keyboard' },
+ "0x0007001f": { 'name': '2', 'class': 'keyboard' },
+ "0x00070020": { 'name': '3', 'class': 'keyboard' },
+ "0x00070021": { 'name': '4', 'class': 'keyboard' },
+ "0x00070022": { 'name': '5', 'class': 'keyboard' },
+ "0x00070023": { 'name': '6', 'class': 'keyboard' },
+ "0x00070024": { 'name': '7', 'class': 'keyboard' },
+ "0x00070025": { 'name': '8', 'class': 'keyboard' },
+ "0x00070026": { 'name': '9', 'class': 'keyboard' },
+ "0x00070027": { 'name': '0', 'class': 'keyboard' },
+ "0x00070028": { 'name': 'Enter', 'class': 'keyboard' },
+ "0x00070029": { 'name': 'Escape', 'class': 'keyboard' },
+ "0x0007002a": { 'name': 'Backspace', 'class': 'keyboard' },
+ "0x0007002b": { 'name': 'Tab', 'class': 'keyboard' },
+ "0x0007002c": { 'name': 'Space', 'class': 'keyboard' },
+ "0x00070039": { 'name': 'Caps Lock', 'class': 'keyboard' },
+ "0x00070046": { 'name': 'PrintScreen', 'class': 'keyboard' },
+ "0x00070047": { 'name': 'Scroll Lock', 'class': 'keyboard' },
+ "0x00070048": { 'name': 'Pause', 'class': 'keyboard' },
+ "0x00070049": { 'name': 'Insert', 'class': 'keyboard' },
+ "0x0007004a": { 'name': 'Home', 'class': 'keyboard' },
+ "0x0007004b": { 'name': 'PageUp', 'class': 'keyboard' },
+ "0x0007004c": { 'name': 'Delete', 'class': 'keyboard' },
+ "0x0007004d": { 'name': 'End', 'class': 'keyboard' },
+ "0x0007004e": { 'name': 'PageDown', 'class': 'keyboard' },
+ "0x0007004f": { 'name': 'Right arrow', 'class': 'keyboard' },
+ "0x00070050": { 'name': 'Left arrow', 'class': 'keyboard' },
+ "0x00070051": { 'name': 'Down arrow', 'class': 'keyboard' },
+ "0x00070052": { 'name': 'Up arrow', 'class': 'keyboard' },
+ "0x00070053": { 'name': 'Num Lock', 'class': 'keyboard' },
+ "0x0007002d": { 'name': '- _', 'class': 'keyboard' },
+ "0x0007002e": { 'name': '= +', 'class': 'keyboard' },
+ "0x0007002f": { 'name': '[ {', 'class': 'keyboard' },
+ "0x00070030": { 'name': '] }', 'class': 'keyboard' },
+ "0x00070031": { 'name': '\\ |', 'class': 'keyboard' },
+ "0x00070033": { 'name': '; :', 'class': 'keyboard' },
+ "0x00070034": { 'name': '‘ “', 'class': 'keyboard' },
+ "0x00070035": { 'name': '` ~', 'class': 'keyboard' },
+ "0x00070036": { 'name': ', <', 'class': 'keyboard' },
+ "0x00070037": { 'name': '. >', 'class': 'keyboard' },
+ "0x00070038": { 'name': '/ ?', 'class': 'keyboard' },
+ "0x0007003a": { 'name': 'F1', 'class': 'keyboard' },
+ "0x0007003b": { 'name': 'F2', 'class': 'keyboard' },
+ "0x0007003c": { 'name': 'F3', 'class': 'keyboard' },
+ "0x0007003d": { 'name': 'F4', 'class': 'keyboard' },
+ "0x0007003e": { 'name': 'F5', 'class': 'keyboard' },
+ "0x0007003f": { 'name': 'F6', 'class': 'keyboard' },
+ "0x00070040": { 'name': 'F7', 'class': 'keyboard' },
+ "0x00070041": { 'name': 'F8', 'class': 'keyboard' },
+ "0x00070042": { 'name': 'F9', 'class': 'keyboard' },
+ "0x00070043": { 'name': 'F10', 'class': 'keyboard' },
+ "0x00070044": { 'name': 'F11', 'class': 'keyboard' },
+ "0x00070045": { 'name': 'F12', 'class': 'keyboard' },
+ "0x00070068": { 'name': 'F13', 'class': 'keyboard' },
+ "0x00070069": { 'name': 'F14', 'class': 'keyboard' },
+ "0x0007006a": { 'name': 'F15', 'class': 'keyboard' },
+ "0x0007006b": { 'name': 'F16', 'class': 'keyboard' },
+ "0x0007006c": { 'name': 'F17', 'class': 'keyboard' },
+ "0x0007006d": { 'name': 'F18', 'class': 'keyboard' },
+ "0x0007006e": { 'name': 'F19', 'class': 'keyboard' },
+ "0x0007006f": { 'name': 'F20', 'class': 'keyboard' },
+ "0x00070070": { 'name': 'F21', 'class': 'keyboard' },
+ "0x00070071": { 'name': 'F22', 'class': 'keyboard' },
+ "0x00070072": { 'name': 'F23', 'class': 'keyboard' },
+ "0x00070073": { 'name': 'F24', 'class': 'keyboard' },
+ "0x00070054": { 'name': 'Keypad /', 'class': 'keyboard' },
+ "0x00070055": { 'name': 'Keypad *', 'class': 'keyboard' },
+ "0x00070056": { 'name': 'Keypad -', 'class': 'keyboard' },
+ "0x00070057": { 'name': 'Keypad +', 'class': 'keyboard' },
+ "0x00070058": { 'name': 'Keypad Enter', 'class': 'keyboard' },
+ "0x00070059": { 'name': 'Keypad 1', 'class': 'keyboard' },
+ "0x0007005a": { 'name': 'Keypad 2', 'class': 'keyboard' },
+ "0x0007005b": { 'name': 'Keypad 3', 'class': 'keyboard' },
+ "0x0007005c": { 'name': 'Keypad 4', 'class': 'keyboard' },
+ "0x0007005d": { 'name': 'Keypad 5', 'class': 'keyboard' },
+ "0x0007005e": { 'name': 'Keypad 6', 'class': 'keyboard' },
+ "0x0007005f": { 'name': 'Keypad 7', 'class': 'keyboard' },
+ "0x00070060": { 'name': 'Keypad 8', 'class': 'keyboard' },
+ "0x00070061": { 'name': 'Keypad 9', 'class': 'keyboard' },
+ "0x00070062": { 'name': 'Keypad 0', 'class': 'keyboard' },
+ "0x00070063": { 'name': 'Keypad .', 'class': 'keyboard' },
+ "0x00070067": { 'name': 'Keypad =', 'class': 'keyboard' },
+ "0x00070064": { 'name': 'Non-US \\ |', 'class': 'keyboard' },
+ "0x00070032": { 'name': 'Non-US # ~', 'class': 'keyboard' },
+ "0x00070065": { 'name': 'Application', 'class': 'keyboard' },
+ "0x00070066": { 'name': 'Power', 'class': 'keyboard' },
+ "0x00070087": { 'name': '\\ _', 'class': 'keyboard' },
+ "0x00070089": { 'name': '¥ |', 'class': 'keyboard' },
+ "0x0007008a": { 'name': 'Henkan', 'class': 'keyboard' },
+ "0x0007008b": { 'name': 'Muhenkan', 'class': 'keyboard' },
+ "0x00070088": { 'name': 'Kana', 'class': 'keyboard' },
+ "0x00070090": { 'name': 'Kana (Mac)', 'class': 'keyboard' },
+ "0x00070091": { 'name': 'Eisū (Mac)', 'class': 'keyboard' },
+ "0x00080001": { 'name': 'Num Lock LED', 'class': 'keyboard' },
+ "0x00080002": { 'name': 'Caps Lock LED', 'class': 'keyboard' },
+ "0x00080003": { 'name': 'Scroll Lock LED', 'class': 'keyboard' },
+ "0x00080004": { 'name': 'Compose LED', 'class': 'keyboard' },
+ "0x00080005": { 'name': 'Kana LED', 'class': 'keyboard' },
- "0x000c00e9": { 'name': 'Volume up', 'class': 'media' },
- "0x000c00ea": { 'name': 'Volume down', 'class': 'media' },
- "0x000c00e2": { 'name': 'Mute', 'class': 'media' },
- "0x000b002f": { 'name': 'Mic mute', 'class': 'media' },
- "0x000c00cd": { 'name': 'Play/pause', 'class': 'media' },
- "0x000c00b7": { 'name': 'Stop', 'class': 'media' },
- "0x000c00b5": { 'name': 'Next track', 'class': 'media' },
- "0x000c00b6": { 'name': 'Previous track', 'class': 'media' },
+ "0x000c00e9": { 'name': 'Volume up', 'class': 'media' },
+ "0x000c00ea": { 'name': 'Volume down', 'class': 'media' },
+ "0x000c00e2": { 'name': 'Mute', 'class': 'media' },
+ "0x000b002f": { 'name': 'Mic mute', 'class': 'media' },
+ "0x000c00cd": { 'name': 'Play/pause', 'class': 'media' },
+ "0x000c00b7": { 'name': 'Stop', 'class': 'media' },
+ "0x000c00b5": { 'name': 'Next track', 'class': 'media' },
+ "0x000c00b6": { 'name': 'Previous track', 'class': 'media' },
+ "0x00000000": { 'name': 'Nothing', 'class': 'other' },
+ "0xfff30001": { 'name': 'Expression 1', 'class': 'other' },
+ "0xfff30002": { 'name': 'Expression 2', 'class': 'other' },
+ "0xfff30003": { 'name': 'Expression 3', 'class': 'other' },
+ "0xfff30004": { 'name': 'Expression 4', 'class': 'other' },
+ "0xfff30005": { 'name': 'Expression 5', 'class': 'other' },
+ "0xfff30006": { 'name': 'Expression 6', 'class': 'other' },
+ "0xfff30007": { 'name': 'Expression 7', 'class': 'other' },
+ "0xfff30008": { 'name': 'Expression 8', 'class': 'other' },
+ "0xfff50001": { 'name': 'Register 1', 'class': 'other' },
+ "0xfff50002": { 'name': 'Register 2', 'class': 'other' },
+ "0xfff50003": { 'name': 'Register 3', 'class': 'other' },
+ "0xfff50004": { 'name': 'Register 4', 'class': 'other' },
+ "0xfff50005": { 'name': 'Register 5', 'class': 'other' },
+ "0xfff50006": { 'name': 'Register 6', 'class': 'other' },
+ "0xfff50007": { 'name': 'Register 7', 'class': 'other' },
+ "0xfff50008": { 'name': 'Register 8', 'class': 'other' },
+ "0xfff50009": { 'name': 'Register 9', 'class': 'other' },
+ "0xfff5000a": { 'name': 'Register 10', 'class': 'other' },
+ "0xfff5000b": { 'name': 'Register 11', 'class': 'other' },
+ "0xfff5000c": { 'name': 'Register 12', 'class': 'other' },
+ "0xfff5000d": { 'name': 'Register 13', 'class': 'other' },
+ "0xfff5000e": { 'name': 'Register 14', 'class': 'other' },
+ "0xfff5000f": { 'name': 'Register 15', 'class': 'other' },
+ "0xfff50010": { 'name': 'Register 16', 'class': 'other' },
+ "0xfff50011": { 'name': 'Register 17', 'class': 'other' },
+ "0xfff50012": { 'name': 'Register 18', 'class': 'other' },
+ "0xfff50013": { 'name': 'Register 19', 'class': 'other' },
+ "0xfff50014": { 'name': 'Register 20', 'class': 'other' },
+ "0xfff50015": { 'name': 'Register 21', 'class': 'other' },
+ "0xfff50016": { 'name': 'Register 22', 'class': 'other' },
+ "0xfff50017": { 'name': 'Register 23', 'class': 'other' },
+ "0xfff50018": { 'name': 'Register 24', 'class': 'other' },
+ "0xfff50019": { 'name': 'Register 25', 'class': 'other' },
+ "0xfff5001a": { 'name': 'Register 26', 'class': 'other' },
+ "0xfff5001b": { 'name': 'Register 27', 'class': 'other' },
+ "0xfff5001c": { 'name': 'Register 28', 'class': 'other' },
+ "0xfff5001d": { 'name': 'Register 29', 'class': 'other' },
+ "0xfff5001e": { 'name': 'Register 30', 'class': 'other' },
+ "0xfff5001f": { 'name': 'Register 31', 'class': 'other' },
+ "0xfff50020": { 'name': 'Register 32', 'class': 'other' },
+ "0xfff40002": { 'name': 'GPIO 2', 'class': 'other' },
+ "0xfff40003": { 'name': 'GPIO 3', 'class': 'other' },
+ "0xfff40004": { 'name': 'GPIO 4', 'class': 'other' },
+ "0xfff40005": { 'name': 'GPIO 5', 'class': 'other' },
+ "0xfff40006": { 'name': 'GPIO 6', 'class': 'other' },
+ "0xfff40007": { 'name': 'GPIO 7', 'class': 'other' },
+ "0xfff40008": { 'name': 'GPIO 8', 'class': 'other' },
+ "0xfff40009": { 'name': 'GPIO 9', 'class': 'other' },
+ },
+ 0: {
+ "0x00090001": { 'name': 'Left button', 'class': 'mouse' },
+ "0x00090002": { 'name': 'Right button', 'class': 'mouse' },
+ "0x00090003": { 'name': 'Middle button', 'class': 'mouse' },
+ "0x00090004": { 'name': 'Back', 'class': 'mouse' },
+ "0x00090005": { 'name': 'Forward', 'class': 'mouse' },
+ "0x00090006": { 'name': 'Button 6', 'class': 'mouse' },
+ "0x00090007": { 'name': 'Button 7', 'class': 'mouse' },
+ "0x00090008": { 'name': 'Button 8', 'class': 'mouse' },
+ "0x00010030": { 'name': 'Cursor X', 'class': 'mouse' },
+ "0x00010031": { 'name': 'Cursor Y', 'class': 'mouse' },
+ "0x00010038": { 'name': 'V scroll', 'class': 'mouse' },
+ "0x000c0238": { 'name': 'H scroll', 'class': 'mouse' },
+
+ "0x000700e0": { 'name': 'Left Control', 'class': 'keyboard' },
+ "0x000700e1": { 'name': 'Left Shift', 'class': 'keyboard' },
+ "0x000700e2": { 'name': 'Left Alt', 'class': 'keyboard' },
+ "0x000700e3": { 'name': 'Left GUI', 'class': 'keyboard' },
+ "0x000700e4": { 'name': 'Right Control', 'class': 'keyboard' },
+ "0x000700e5": { 'name': 'Right Shift', 'class': 'keyboard' },
+ "0x000700e6": { 'name': 'Right Alt', 'class': 'keyboard' },
+ "0x000700e7": { 'name': 'Right GUI', 'class': 'keyboard' },
+ "0x00070004": { 'name': 'A', 'class': 'keyboard' },
+ "0x00070005": { 'name': 'B', 'class': 'keyboard' },
+ "0x00070006": { 'name': 'C', 'class': 'keyboard' },
+ "0x00070007": { 'name': 'D', 'class': 'keyboard' },
+ "0x00070008": { 'name': 'E', 'class': 'keyboard' },
+ "0x00070009": { 'name': 'F', 'class': 'keyboard' },
+ "0x0007000a": { 'name': 'G', 'class': 'keyboard' },
+ "0x0007000b": { 'name': 'H', 'class': 'keyboard' },
+ "0x0007000c": { 'name': 'I', 'class': 'keyboard' },
+ "0x0007000d": { 'name': 'J', 'class': 'keyboard' },
+ "0x0007000e": { 'name': 'K', 'class': 'keyboard' },
+ "0x0007000f": { 'name': 'L', 'class': 'keyboard' },
+ "0x00070010": { 'name': 'M', 'class': 'keyboard' },
+ "0x00070011": { 'name': 'N', 'class': 'keyboard' },
+ "0x00070012": { 'name': 'O', 'class': 'keyboard' },
+ "0x00070013": { 'name': 'P', 'class': 'keyboard' },
+ "0x00070014": { 'name': 'Q', 'class': 'keyboard' },
+ "0x00070015": { 'name': 'R', 'class': 'keyboard' },
+ "0x00070016": { 'name': 'S', 'class': 'keyboard' },
+ "0x00070017": { 'name': 'T', 'class': 'keyboard' },
+ "0x00070018": { 'name': 'U', 'class': 'keyboard' },
+ "0x00070019": { 'name': 'V', 'class': 'keyboard' },
+ "0x0007001a": { 'name': 'W', 'class': 'keyboard' },
+ "0x0007001b": { 'name': 'X', 'class': 'keyboard' },
+ "0x0007001c": { 'name': 'Y', 'class': 'keyboard' },
+ "0x0007001d": { 'name': 'Z', 'class': 'keyboard' },
+ "0x0007001e": { 'name': '1', 'class': 'keyboard' },
+ "0x0007001f": { 'name': '2', 'class': 'keyboard' },
+ "0x00070020": { 'name': '3', 'class': 'keyboard' },
+ "0x00070021": { 'name': '4', 'class': 'keyboard' },
+ "0x00070022": { 'name': '5', 'class': 'keyboard' },
+ "0x00070023": { 'name': '6', 'class': 'keyboard' },
+ "0x00070024": { 'name': '7', 'class': 'keyboard' },
+ "0x00070025": { 'name': '8', 'class': 'keyboard' },
+ "0x00070026": { 'name': '9', 'class': 'keyboard' },
+ "0x00070027": { 'name': '0', 'class': 'keyboard' },
+ "0x00070028": { 'name': 'Enter', 'class': 'keyboard' },
+ "0x00070029": { 'name': 'Escape', 'class': 'keyboard' },
+ "0x0007002a": { 'name': 'Backspace', 'class': 'keyboard' },
+ "0x0007002b": { 'name': 'Tab', 'class': 'keyboard' },
+ "0x0007002c": { 'name': 'Space', 'class': 'keyboard' },
+ "0x00070039": { 'name': 'Caps Lock', 'class': 'keyboard' },
+ "0x00070046": { 'name': 'PrintScreen', 'class': 'keyboard' },
+ "0x00070047": { 'name': 'Scroll Lock', 'class': 'keyboard' },
+ "0x00070048": { 'name': 'Pause', 'class': 'keyboard' },
+ "0x00070049": { 'name': 'Insert', 'class': 'keyboard' },
+ "0x0007004a": { 'name': 'Home', 'class': 'keyboard' },
+ "0x0007004b": { 'name': 'PageUp', 'class': 'keyboard' },
+ "0x0007004c": { 'name': 'Delete', 'class': 'keyboard' },
+ "0x0007004d": { 'name': 'End', 'class': 'keyboard' },
+ "0x0007004e": { 'name': 'PageDown', 'class': 'keyboard' },
+ "0x0007004f": { 'name': 'Right arrow', 'class': 'keyboard' },
+ "0x00070050": { 'name': 'Left arrow', 'class': 'keyboard' },
+ "0x00070051": { 'name': 'Down arrow', 'class': 'keyboard' },
+ "0x00070052": { 'name': 'Up arrow', 'class': 'keyboard' },
+ "0x00070053": { 'name': 'Num Lock', 'class': 'keyboard' },
+ "0x0007002d": { 'name': '- _', 'class': 'keyboard' },
+ "0x0007002e": { 'name': '= +', 'class': 'keyboard' },
+ "0x0007002f": { 'name': '[ {', 'class': 'keyboard' },
+ "0x00070030": { 'name': '] }', 'class': 'keyboard' },
+ "0x00070031": { 'name': '\\ |', 'class': 'keyboard' },
+ "0x00070033": { 'name': '; :', 'class': 'keyboard' },
+ "0x00070034": { 'name': '‘ “', 'class': 'keyboard' },
+ "0x00070035": { 'name': '` ~', 'class': 'keyboard' },
+ "0x00070036": { 'name': ', <', 'class': 'keyboard' },
+ "0x00070037": { 'name': '. >', 'class': 'keyboard' },
+ "0x00070038": { 'name': '/ ?', 'class': 'keyboard' },
+ "0x0007003a": { 'name': 'F1', 'class': 'keyboard' },
+ "0x0007003b": { 'name': 'F2', 'class': 'keyboard' },
+ "0x0007003c": { 'name': 'F3', 'class': 'keyboard' },
+ "0x0007003d": { 'name': 'F4', 'class': 'keyboard' },
+ "0x0007003e": { 'name': 'F5', 'class': 'keyboard' },
+ "0x0007003f": { 'name': 'F6', 'class': 'keyboard' },
+ "0x00070040": { 'name': 'F7', 'class': 'keyboard' },
+ "0x00070041": { 'name': 'F8', 'class': 'keyboard' },
+ "0x00070042": { 'name': 'F9', 'class': 'keyboard' },
+ "0x00070043": { 'name': 'F10', 'class': 'keyboard' },
+ "0x00070044": { 'name': 'F11', 'class': 'keyboard' },
+ "0x00070045": { 'name': 'F12', 'class': 'keyboard' },
+ "0x00070068": { 'name': 'F13', 'class': 'keyboard' },
+ "0x00070069": { 'name': 'F14', 'class': 'keyboard' },
+ "0x0007006a": { 'name': 'F15', 'class': 'keyboard' },
+ "0x0007006b": { 'name': 'F16', 'class': 'keyboard' },
+ "0x0007006c": { 'name': 'F17', 'class': 'keyboard' },
+ "0x0007006d": { 'name': 'F18', 'class': 'keyboard' },
+ "0x0007006e": { 'name': 'F19', 'class': 'keyboard' },
+ "0x0007006f": { 'name': 'F20', 'class': 'keyboard' },
+ "0x00070070": { 'name': 'F21', 'class': 'keyboard' },
+ "0x00070071": { 'name': 'F22', 'class': 'keyboard' },
+ "0x00070072": { 'name': 'F23', 'class': 'keyboard' },
+ "0x00070073": { 'name': 'F24', 'class': 'keyboard' },
+ "0x00070054": { 'name': 'Keypad /', 'class': 'keyboard' },
+ "0x00070055": { 'name': 'Keypad *', 'class': 'keyboard' },
+ "0x00070056": { 'name': 'Keypad -', 'class': 'keyboard' },
+ "0x00070057": { 'name': 'Keypad +', 'class': 'keyboard' },
+ "0x00070058": { 'name': 'Keypad Enter', 'class': 'keyboard' },
+ "0x00070059": { 'name': 'Keypad 1', 'class': 'keyboard' },
+ "0x0007005a": { 'name': 'Keypad 2', 'class': 'keyboard' },
+ "0x0007005b": { 'name': 'Keypad 3', 'class': 'keyboard' },
+ "0x0007005c": { 'name': 'Keypad 4', 'class': 'keyboard' },
+ "0x0007005d": { 'name': 'Keypad 5', 'class': 'keyboard' },
+ "0x0007005e": { 'name': 'Keypad 6', 'class': 'keyboard' },
+ "0x0007005f": { 'name': 'Keypad 7', 'class': 'keyboard' },
+ "0x00070060": { 'name': 'Keypad 8', 'class': 'keyboard' },
+ "0x00070061": { 'name': 'Keypad 9', 'class': 'keyboard' },
+ "0x00070062": { 'name': 'Keypad 0', 'class': 'keyboard' },
+ "0x00070063": { 'name': 'Keypad .', 'class': 'keyboard' },
+ "0x00070067": { 'name': 'Keypad =', 'class': 'keyboard' },
+ "0x00070064": { 'name': 'Non-US \\ |', 'class': 'keyboard' },
+ "0x00070032": { 'name': 'Non-US # ~', 'class': 'keyboard' },
+ "0x00070065": { 'name': 'Application', 'class': 'keyboard' },
+ "0x00070066": { 'name': 'Power', 'class': 'keyboard' },
+ "0x00070087": { 'name': '\\ _', 'class': 'keyboard' },
+ "0x00070089": { 'name': '¥ |', 'class': 'keyboard' },
+ "0x0007008a": { 'name': 'Henkan', 'class': 'keyboard' },
+ "0x0007008b": { 'name': 'Muhenkan', 'class': 'keyboard' },
+ "0x00070088": { 'name': 'Kana', 'class': 'keyboard' },
+ "0x00070090": { 'name': 'Kana (Mac)', 'class': 'keyboard' },
+ "0x00070091": { 'name': 'Eisū (Mac)', 'class': 'keyboard' },
+ "0x00080001": { 'name': 'Num Lock LED', 'class': 'keyboard' },
+ "0x00080002": { 'name': 'Caps Lock LED', 'class': 'keyboard' },
+ "0x00080003": { 'name': 'Scroll Lock LED', 'class': 'keyboard' },
+ "0x00080004": { 'name': 'Compose LED', 'class': 'keyboard' },
+ "0x00080005": { 'name': 'Kana LED', 'class': 'keyboard' },
+
+ "0x000c00e9": { 'name': 'Volume up', 'class': 'media' },
+ "0x000c00ea": { 'name': 'Volume down', 'class': 'media' },
+ "0x000c00e2": { 'name': 'Mute', 'class': 'media' },
+ "0x000b002f": { 'name': 'Mic mute', 'class': 'media' },
+ "0x000c00cd": { 'name': 'Play/pause', 'class': 'media' },
+ "0x000c00b7": { 'name': 'Stop', 'class': 'media' },
+ "0x000c00b5": { 'name': 'Next track', 'class': 'media' },
+ "0x000c00b6": { 'name': 'Previous track', 'class': 'media' },
+ },
+ 2: {
+ "0x00090001": { 'name': 'Y', 'class': 'mouse' },
+ "0x00090002": { 'name': 'B', 'class': 'mouse' },
+ "0x00090003": { 'name': 'A', 'class': 'mouse' },
+ "0x00090004": { 'name': 'X', 'class': 'mouse' },
+ "0x00090005": { 'name': 'L', 'class': 'mouse' },
+ "0x00090006": { 'name': 'R', 'class': 'mouse' },
+ "0x00090007": { 'name': 'ZL', 'class': 'mouse' },
+ "0x00090008": { 'name': 'ZR', 'class': 'mouse' },
+ "0x00090009": { 'name': 'Minus', 'class': 'mouse' },
+ "0x0009000a": { 'name': 'Plus', 'class': 'mouse' },
+ "0x0009000b": { 'name': 'LS', 'class': 'mouse' },
+ "0x0009000c": { 'name': 'RS', 'class': 'mouse' },
+ "0x0009000d": { 'name': 'Home', 'class': 'mouse' },
+ "0x0009000e": { 'name': 'Capture', 'class': 'mouse' },
+ "0x0009000f": { 'name': 'Button 15', 'class': 'mouse' },
+ "0x00090010": { 'name': 'Button 16', 'class': 'mouse' },
+ "0x00010039": { 'name': 'D-pad', 'class': 'mouse' },
+ "0x00010030": { 'name': 'Left stick X', 'class': 'mouse' },
+ "0x00010031": { 'name': 'Left stick Y', 'class': 'mouse' },
+ "0x00010032": { 'name': 'Right stick X', 'class': 'mouse' },
+ "0x00010035": { 'name': 'Right stick Y', 'class': 'mouse' },
+ },
+ 3: {
+ "0x00090001": { 'name': 'Square', 'class': 'mouse' },
+ "0x00090002": { 'name': 'Cross', 'class': 'mouse' },
+ "0x00090003": { 'name': 'Circle', 'class': 'mouse' },
+ "0x00090004": { 'name': 'Triangle', 'class': 'mouse' },
+ "0x00090005": { 'name': 'L1', 'class': 'mouse' },
+ "0x00090006": { 'name': 'R1', 'class': 'mouse' },
+ "0x00090007": { 'name': 'L2', 'class': 'mouse' },
+ "0x00090008": { 'name': 'R2', 'class': 'mouse' },
+ "0x00090009": { 'name': 'Share', 'class': 'mouse' },
+ "0x0009000a": { 'name': 'Options', 'class': 'mouse' },
+ "0x0009000b": { 'name': 'L3', 'class': 'mouse' },
+ "0x0009000c": { 'name': 'R3', 'class': 'mouse' },
+ "0x0009000d": { 'name': 'PS', 'class': 'mouse' },
+ "0x0009000e": { 'name': 'Touchpad', 'class': 'mouse' },
+ "0x00010039": { 'name': 'D-pad', 'class': 'mouse' },
+ "0x00010030": { 'name': 'Left stick X', 'class': 'mouse' },
+ "0x00010031": { 'name': 'Left stick Y', 'class': 'mouse' },
+ "0x00010032": { 'name': 'Right stick X', 'class': 'mouse' },
+ "0x00010035": { 'name': 'Right stick Y', 'class': 'mouse' },
+ "0x00010033": { 'name': 'L2 axis', 'class': 'mouse' },
+ "0x00010034": { 'name': 'R2 axis', 'class': 'mouse' },
+ },
+};
+
+const common_target_usages = {
"0x00000000": { 'name': 'Nothing', 'class': 'other' },
"0xfff10001": { 'name': 'Layer 1', 'class': 'other' },
"0xfff10002": { 'name': 'Layer 2', 'class': 'other' },
@@ -190,54 +446,11 @@ const usages = {
"0xfff2001e": { 'name': 'Macro 30', 'class': 'other' },
"0xfff2001f": { 'name': 'Macro 31', 'class': 'other' },
"0xfff20020": { 'name': 'Macro 32', 'class': 'other' },
- "0xfff30001": { 'name': 'Expression 1', 'class': 'other' },
- "0xfff30002": { 'name': 'Expression 2', 'class': 'other' },
- "0xfff30003": { 'name': 'Expression 3', 'class': 'other' },
- "0xfff30004": { 'name': 'Expression 4', 'class': 'other' },
- "0xfff30005": { 'name': 'Expression 5', 'class': 'other' },
- "0xfff30006": { 'name': 'Expression 6', 'class': 'other' },
- "0xfff30007": { 'name': 'Expression 7', 'class': 'other' },
- "0xfff30008": { 'name': 'Expression 8', 'class': 'other' },
- "0xfff50001": { 'name': 'Register 1', 'class': 'other' },
- "0xfff50002": { 'name': 'Register 2', 'class': 'other' },
- "0xfff50003": { 'name': 'Register 3', 'class': 'other' },
- "0xfff50004": { 'name': 'Register 4', 'class': 'other' },
- "0xfff50005": { 'name': 'Register 5', 'class': 'other' },
- "0xfff50006": { 'name': 'Register 6', 'class': 'other' },
- "0xfff50007": { 'name': 'Register 7', 'class': 'other' },
- "0xfff50008": { 'name': 'Register 8', 'class': 'other' },
- "0xfff50009": { 'name': 'Register 9', 'class': 'other' },
- "0xfff5000a": { 'name': 'Register 10', 'class': 'other' },
- "0xfff5000b": { 'name': 'Register 11', 'class': 'other' },
- "0xfff5000c": { 'name': 'Register 12', 'class': 'other' },
- "0xfff5000d": { 'name': 'Register 13', 'class': 'other' },
- "0xfff5000e": { 'name': 'Register 14', 'class': 'other' },
- "0xfff5000f": { 'name': 'Register 15', 'class': 'other' },
- "0xfff50010": { 'name': 'Register 16', 'class': 'other' },
- "0xfff50011": { 'name': 'Register 17', 'class': 'other' },
- "0xfff50012": { 'name': 'Register 18', 'class': 'other' },
- "0xfff50013": { 'name': 'Register 19', 'class': 'other' },
- "0xfff50014": { 'name': 'Register 20', 'class': 'other' },
- "0xfff50015": { 'name': 'Register 21', 'class': 'other' },
- "0xfff50016": { 'name': 'Register 22', 'class': 'other' },
- "0xfff50017": { 'name': 'Register 23', 'class': 'other' },
- "0xfff50018": { 'name': 'Register 24', 'class': 'other' },
- "0xfff50019": { 'name': 'Register 25', 'class': 'other' },
- "0xfff5001a": { 'name': 'Register 26', 'class': 'other' },
- "0xfff5001b": { 'name': 'Register 27', 'class': 'other' },
- "0xfff5001c": { 'name': 'Register 28', 'class': 'other' },
- "0xfff5001d": { 'name': 'Register 29', 'class': 'other' },
- "0xfff5001e": { 'name': 'Register 30', 'class': 'other' },
- "0xfff5001f": { 'name': 'Register 31', 'class': 'other' },
- "0xfff50020": { 'name': 'Register 32', 'class': 'other' },
- "0xfff40002": { 'name': 'GPIO 2', 'class': 'other' },
- "0xfff40003": { 'name': 'GPIO 3', 'class': 'other' },
- "0xfff40004": { 'name': 'GPIO 4', 'class': 'other' },
- "0xfff40005": { 'name': 'GPIO 5', 'class': 'other' },
- "0xfff40006": { 'name': 'GPIO 6', 'class': 'other' },
- "0xfff40007": { 'name': 'GPIO 7', 'class': 'other' },
- "0xfff40008": { 'name': 'GPIO 8', 'class': 'other' },
- "0xfff40009": { 'name': 'GPIO 9', 'class': 'other' },
-};
+}
+
+Object.assign(usages[0], common_target_usages);
+Object.assign(usages[2], common_target_usages);
+Object.assign(usages[3], common_target_usages);
+usages[1] = usages[0]; // absolute mouse & keyboard is the same as regular mouse & keyboard
export default usages;
diff --git a/config-tool/common.py b/config-tool/common.py
index e442495..22b7b88 100644
--- a/config-tool/common.py
+++ b/config-tool/common.py
@@ -9,7 +9,7 @@
CONFIG_USAGE_PAGE = 0xFF00
CONFIG_USAGE = 0x0020
-CONFIG_VERSION = 8
+CONFIG_VERSION = 9
CONFIG_SIZE = 32
REPORT_ID_CONFIG = 100
@@ -49,6 +49,8 @@
TAP_FLAG = 1 << 1
HOLD_FLAG = 1 << 2
+IGNORE_AUTH_DEV_INPUTS_FLAG = 1 << 4
+
NMACROS = 32
NEXPRESSIONS = 8
MACRO_ITEMS_IN_PACKET = 6
@@ -105,7 +107,7 @@ def add_crc(buf):
def get_device():
devices = [
d
- for d in hid.enumerate(VENDOR_ID, PRODUCT_ID)
+ for d in hid.enumerate()
if d["usage_page"] == CONFIG_USAGE_PAGE and d["usage"] == CONFIG_USAGE
]
if len(devices) == 0:
diff --git a/config-tool/get_config.py b/config-tool/get_config.py
index e48434a..c29f802 100755
--- a/config-tool/get_config.py
+++ b/config-tool/get_config.py
@@ -23,9 +23,10 @@
interval_override,
tap_hold_threshold,
gpio_debounce_time_ms,
+ our_descriptor_number,
*_,
crc,
-) = struct.unpack(" 0) && (*len > 0)) {
- handle_set_report(request_value[0], (*data) + 1, (*len) - 1);
+ if (dev == hid_dev0) {
+ handle_set_report0(request_value[0], (*data) + 1, (*len) - 1);
+ } else if (dev == hid_dev1) {
+ handle_set_report1(request_value[0], (*data) + 1, (*len) - 1);
+ }
} else {
LOG_ERR("no report ID?");
}
@@ -573,7 +577,11 @@ static int get_report_cb(const struct device* dev, struct usb_setup_packet* setu
LOG_INF("report_id=%d, %d, len=%d", request_value[0], request_value[1], *len);
*data[0] = request_value[0];
- *len = handle_get_report(request_value[0], (*data) + 1, CONFIG_SIZE);
+ if (dev == hid_dev0) {
+ *len = handle_get_report0(request_value[0], (*data) + 1, CONFIG_SIZE);
+ } else if (dev == hid_dev1) {
+ *len = handle_get_report1(request_value[0], (*data) + 1, CONFIG_SIZE);
+ }
(*len)++;
return 0;
@@ -661,7 +669,7 @@ static void usb_init() {
return;
}
- usb_hid_register_device(hid_dev0, our_report_descriptor, our_report_descriptor_length, &ops0);
+ usb_hid_register_device(hid_dev0, our_descriptor->descriptor, our_descriptor->descriptor_length, &ops0);
usb_hid_register_device(hid_dev1, config_report_descriptor, config_report_descriptor_length, &ops1);
CHK(usb_hid_init(hid_dev0));
CHK(usb_hid_init(hid_dev1));
@@ -764,17 +772,26 @@ void queue_out_report(uint16_t interface, uint8_t report_id, const uint8_t* buff
// TODO
}
+void queue_set_feature_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len) {
+ // TODO
+}
+
+void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len) {
+ // TODO
+}
+
int main() {
LOG_INF("HID Remapper Bluetooth");
my_mutexes_init();
button_init();
leds_init();
- usb_init();
bt_init();
CHK(settings_subsys_init());
CHK(settings_register(&our_settings_handlers));
settings_load();
+ our_descriptor = &our_descriptors[our_descriptor_number];
+ usb_init();
scan_init();
parse_our_descriptor();
set_mapping_from_config();
diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt
index 840d4a9..4fe573c 100644
--- a/firmware/CMakeLists.txt
+++ b/firmware/CMakeLists.txt
@@ -37,6 +37,7 @@ add_executable(remapper
src/out_report.cc
src/tick.cc
src/activity_led.cc
+ src/ps_auth.cc
)
if(PICO_BOARD STREQUAL "pico")
@@ -87,6 +88,7 @@ add_executable(remapper_dual_a
src/pico_debug/flash.c
src/pico_debug/adi.c
dual_b_binary.c
+ src/ps_auth.cc
)
target_include_directories(remapper_dual_a PRIVATE
src
@@ -144,6 +146,7 @@ add_executable(remapper_serial
src/interval_override.cc
src/tick.cc
src/activity_led.cc
+ src/ps_auth.cc
)
target_include_directories(remapper_serial PRIVATE
src
diff --git a/firmware/src/config.cc b/firmware/src/config.cc
index f988d77..2ed7bb1 100644
--- a/firmware/src/config.cc
+++ b/firmware/src/config.cc
@@ -9,11 +9,12 @@
#include "platform.h"
#include "remapper.h"
-const uint8_t CONFIG_VERSION = 8;
+const uint8_t CONFIG_VERSION = 9;
const uint8_t CONFIG_FLAG_UNMAPPED_PASSTHROUGH = 0x01;
const uint8_t CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK = 0b00001111;
const uint8_t CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT = 0;
+const uint8_t CONFIG_FLAG_IGNORE_AUTH_DEV_INPUTS_BIT = 4;
ConfigCommand last_config_command = ConfigCommand::NO_COMMAND;
uint32_t requested_index = 0;
@@ -161,6 +162,62 @@ void load_config_v6(const uint8_t* persisted_config) {
my_mutex_exit(MutexId::EXPRESSIONS);
}
+void load_config_v7_v8(const uint8_t* persisted_config) {
+ // v8 is same as v7, it just introduces some new expression ops
+
+ persist_config_v7_t* config = (persist_config_v7_t*) persisted_config;
+ unmapped_passthrough_layer_mask =
+ (config->flags & CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK) >> CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT;
+ partial_scroll_timeout = config->partial_scroll_timeout;
+ tap_hold_threshold = config->tap_hold_threshold;
+ gpio_debounce_time = config->gpio_debounce_time_ms * 1000;
+ interval_override = config->interval_override;
+ mapping_config_t* buffer_mappings = (mapping_config_t*) (persisted_config + sizeof(persist_config_v7_t));
+ for (uint32_t i = 0; i < config->mapping_count; i++) {
+ config_mappings.push_back(buffer_mappings[i]);
+ }
+
+ const uint8_t* macros_config_ptr = (persisted_config + sizeof(persist_config_v7_t) + config->mapping_count * sizeof(mapping_config_t));
+ my_mutex_enter(MutexId::MACROS);
+ for (int i = 0; i < NMACROS; i++) {
+ macros[i].clear();
+ uint8_t macro_len = *macros_config_ptr;
+ macros_config_ptr++;
+ macros[i].reserve(macro_len);
+ for (int j = 0; j < macro_len; j++) {
+ uint8_t entry_len = *macros_config_ptr;
+ macros_config_ptr++;
+ macros[i].push_back({});
+ macros[i].back().reserve(entry_len);
+ for (int k = 0; k < entry_len; k++) {
+ macros[i].back().push_back(((macro_item_t*) macros_config_ptr)->usage);
+ macros_config_ptr += sizeof(macro_item_t);
+ }
+ }
+ }
+ my_mutex_exit(MutexId::MACROS);
+
+ const uint8_t* expr_config_ptr = macros_config_ptr;
+ my_mutex_enter(MutexId::EXPRESSIONS);
+ for (int i = 0; i < NEXPRESSIONS; i++) {
+ expressions[i].clear();
+ uint8_t expr_len = *expr_config_ptr;
+ expr_config_ptr++;
+ expressions[i].reserve(expr_len);
+ for (int j = 0; j < expr_len; j++) {
+ uint8_t op = *expr_config_ptr;
+ expr_config_ptr++;
+ uint32_t val = 0;
+ if ((op == (uint8_t) Op::PUSH) || (op == (uint8_t) Op::PUSH_USAGE)) {
+ val = ((expr_val_t*) expr_config_ptr)->val;
+ expr_config_ptr += sizeof(expr_val_t);
+ }
+ expressions[i].push_back((expr_elem_t){ .op = (Op) op, .val = val });
+ }
+ }
+ my_mutex_exit(MutexId::EXPRESSIONS);
+}
+
void load_config(const uint8_t* persisted_config) {
if (!checksum_ok(persisted_config, PERSISTED_CONFIG_SIZE) || !persisted_version_ok(persisted_config)) {
return;
@@ -183,21 +240,29 @@ void load_config(const uint8_t* persisted_config) {
return;
}
- // v8 is same as v7, it just introduces some new expression ops
+ if ((version == 7) || (version == 8)) {
+ load_config_v7_v8(persisted_config);
+ return;
+ }
- persist_config_v7_t* config = (persist_config_v7_t*) persisted_config;
+ persist_config_v9_t* config = (persist_config_v9_t*) persisted_config;
unmapped_passthrough_layer_mask =
(config->flags & CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK) >> CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT;
+ ignore_auth_dev_inputs = config->flags & (1 << CONFIG_FLAG_IGNORE_AUTH_DEV_INPUTS_BIT);
partial_scroll_timeout = config->partial_scroll_timeout;
tap_hold_threshold = config->tap_hold_threshold;
gpio_debounce_time = config->gpio_debounce_time_ms * 1000;
interval_override = config->interval_override;
- mapping_config_t* buffer_mappings = (mapping_config_t*) (persisted_config + sizeof(persist_config_v7_t));
+ our_descriptor_number = config->our_descriptor_number;
+ if (our_descriptor_number >= NOUR_DESCRIPTORS) {
+ our_descriptor_number = 0;
+ }
+ mapping_config_t* buffer_mappings = (mapping_config_t*) (persisted_config + sizeof(persist_config_v9_t));
for (uint32_t i = 0; i < config->mapping_count; i++) {
config_mappings.push_back(buffer_mappings[i]);
}
- const uint8_t* macros_config_ptr = (persisted_config + sizeof(persist_config_v7_t) + config->mapping_count * sizeof(mapping_config_t));
+ const uint8_t* macros_config_ptr = (persisted_config + sizeof(persist_config_v9_t) + config->mapping_count * sizeof(mapping_config_t));
my_mutex_enter(MutexId::MACROS);
for (int i = 0; i < NMACROS; i++) {
macros[i].clear();
@@ -243,6 +308,7 @@ void fill_get_config(get_config_t* config) {
config->flags = 0;
config->flags |=
(unmapped_passthrough_layer_mask << CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT) & CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK;
+ config->flags |= ignore_auth_dev_inputs << CONFIG_FLAG_IGNORE_AUTH_DEV_INPUTS_BIT;
config->partial_scroll_timeout = partial_scroll_timeout;
config->tap_hold_threshold = tap_hold_threshold;
config->gpio_debounce_time_ms = gpio_debounce_time / 1000;
@@ -250,6 +316,7 @@ void fill_get_config(get_config_t* config) {
config->our_usage_count = our_usages_rle.size();
config->their_usage_count = their_usages_rle.size();
config->interval_override = interval_override;
+ config->our_descriptor_number = our_descriptor_number;
}
void fill_persist_config(persist_config_t* config) {
@@ -257,11 +324,13 @@ void fill_persist_config(persist_config_t* config) {
config->flags = 0;
config->flags |=
(unmapped_passthrough_layer_mask << CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT) & CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK;
+ config->flags |= ignore_auth_dev_inputs << CONFIG_FLAG_IGNORE_AUTH_DEV_INPUTS_BIT;
config->partial_scroll_timeout = partial_scroll_timeout;
config->tap_hold_threshold = tap_hold_threshold;
config->gpio_debounce_time_ms = gpio_debounce_time / 1000;
config->mapping_count = config_mappings.size();
config->interval_override = interval_override;
+ config->our_descriptor_number = our_descriptor_number;
}
void persist_config() {
@@ -318,11 +387,7 @@ void reset_resolution_multiplier() {
resolution_multiplier = 0;
}
-uint16_t handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen) {
- if (report_id == REPORT_ID_MULTIPLIER && reqlen >= 1) {
- memcpy(buffer, &resolution_multiplier, 1);
- return 1;
- }
+uint16_t handle_get_report1(uint8_t report_id, uint8_t* buffer, uint16_t reqlen) {
if (report_id == REPORT_ID_CONFIG && reqlen >= CONFIG_SIZE) {
get_feature_t* config_buffer = (get_feature_t*) buffer;
memset(config_buffer, 0, sizeof(get_feature_t));
@@ -433,10 +498,7 @@ uint16_t handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen)
return 0;
}
-void handle_set_report(uint8_t report_id, uint8_t const* buffer, uint16_t bufsize) {
- if (report_id == REPORT_ID_MULTIPLIER && bufsize >= 1) {
- memcpy(&resolution_multiplier, buffer, 1);
- }
+void handle_set_report1(uint8_t report_id, uint8_t const* buffer, uint16_t bufsize) {
if (report_id == REPORT_ID_CONFIG && bufsize >= CONFIG_SIZE) {
if (checksum_ok(buffer, CONFIG_SIZE) && command_version_ok(buffer)) {
set_feature_t* config_buffer = (set_feature_t*) buffer;
@@ -451,6 +513,7 @@ void handle_set_report(uint8_t report_id, uint8_t const* buffer, uint16_t bufsiz
set_config_t* config = (set_config_t*) config_buffer->data;
unmapped_passthrough_layer_mask =
(config->flags & CONFIG_FLAG_UNMAPPED_PASSTHROUGH_MASK) >> CONFIG_FLAG_UNMAPPED_PASSTHROUGH_BIT;
+ ignore_auth_dev_inputs = config->flags & (1 << CONFIG_FLAG_IGNORE_AUTH_DEV_INPUTS_BIT);
partial_scroll_timeout = config->partial_scroll_timeout;
tap_hold_threshold = config->tap_hold_threshold;
gpio_debounce_time = config->gpio_debounce_time_ms * 1000;
@@ -459,6 +522,10 @@ void handle_set_report(uint8_t report_id, uint8_t const* buffer, uint16_t bufsiz
if (prev_interval_override != interval_override) {
interval_override_updated();
}
+ our_descriptor_number = config->our_descriptor_number;
+ if (our_descriptor_number >= NOUR_DESCRIPTORS) {
+ our_descriptor_number = 0;
+ }
config_updated = true;
break;
}
diff --git a/firmware/src/config.h b/firmware/src/config.h
index 992e514..6d7c0d2 100644
--- a/firmware/src/config.h
+++ b/firmware/src/config.h
@@ -6,8 +6,8 @@
void load_config(const uint8_t* persisted_config);
void persist_config();
-uint16_t handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen);
-void handle_set_report(uint8_t report_id, uint8_t const* buffer, uint16_t bufsize);
+uint16_t handle_get_report1(uint8_t report_id, uint8_t* buffer, uint16_t reqlen);
+void handle_set_report1(uint8_t report_id, uint8_t const* buffer, uint16_t bufsize);
void reset_resolution_multiplier();
diff --git a/firmware/src/descriptor_parser.cc b/firmware/src/descriptor_parser.cc
index 4616168..dd64fea 100644
--- a/firmware/src/descriptor_parser.cc
+++ b/firmware/src/descriptor_parser.cc
@@ -20,8 +20,19 @@ const uint8_t HID_USAGE_MAXIMUM = 0x28;
const uint8_t HID_LOGICAL_MINIMUM = 0x14;
const uint8_t HID_LOGICAL_MAXIMUM = 0x24;
-void mark_usage(std::unordered_map>& usage_map, uint32_t usage, uint8_t report_id, uint16_t bitpos, uint8_t size, bool is_relative, int32_t logical_minimum, bool is_array = false, uint32_t index = 0, uint32_t count = 0, uint32_t usage_maximum = 0) {
- usage_map[report_id].try_emplace(usage,
+void mark_usage(
+ std::unordered_map>* usage_map,
+ uint32_t usage,
+ uint8_t report_id,
+ uint16_t bitpos,
+ uint8_t size,
+ bool is_relative,
+ int32_t logical_minimum,
+ bool is_array = false,
+ uint32_t index = 0,
+ uint32_t count = 0,
+ uint32_t usage_maximum = 0) {
+ (*usage_map)[report_id].try_emplace(usage,
(usage_def_t){
.report_id = report_id,
.size = size,
@@ -53,12 +64,17 @@ void assign_interface_index(uint16_t interface) {
void parse_descriptor(uint16_t vendor_id, uint16_t product_id, const uint8_t* report_descriptor, int len, uint16_t interface) {
my_mutex_enter(MutexId::THEIR_USAGES);
- parse_descriptor(their_usages[interface], has_report_id_theirs[interface], report_descriptor, len);
+ auto their_report_sizes_map = parse_descriptor(
+ their_usages[interface],
+ their_out_usages[interface],
+ their_feature_usages[interface],
+ has_report_id_theirs[interface],
+ report_descriptor,
+ len);
apply_quirks(vendor_id, product_id, their_usages[interface], report_descriptor, len);
assign_interface_index(interface);
- auto their_out_report_sizes_map = parse_descriptor(their_out_usages[interface], has_report_id_theirs_out[interface], report_descriptor, len, true);
- for (auto const& [report_id, size] : their_out_report_sizes_map) {
+ for (auto const& [report_id, size] : their_report_sizes_map[ReportType::OUTPUT]) {
out_report_sizes[(interface << 16) | report_id] = size;
out_reports[(interface << 16) | report_id] = new uint8_t[size];
memset(out_reports[(interface << 16) | report_id], 0, size);
@@ -75,11 +91,29 @@ void parse_descriptor(uint16_t vendor_id, uint16_t product_id, const uint8_t* re
their_descriptor_updated = true;
}
-std::unordered_map parse_descriptor(std::unordered_map>& usage_map, bool& has_report_id, const uint8_t* report_descriptor, int len, bool output) {
+static ReportType item_to_report_type(uint8_t item) {
+ switch (item) {
+ default:
+ case HID_INPUT:
+ return ReportType::INPUT;
+ case HID_OUTPUT:
+ return ReportType::OUTPUT;
+ case HID_FEATURE:
+ return ReportType::FEATURE;
+ }
+}
+
+std::unordered_map> parse_descriptor(
+ std::unordered_map>& input_usage_map,
+ std::unordered_map>& output_usage_map,
+ std::unordered_map>& feature_usage_map,
+ bool& has_report_id,
+ const uint8_t* report_descriptor,
+ int len) {
int idx = 0;
uint8_t report_id = 0;
- std::unordered_map bitpos; // report_id -> bitpos
+ std::unordered_map> bitpos; // in/out/feature -> report_id -> bitpos
uint32_t report_size = 0;
uint32_t report_count = 0;
uint32_t usage_page = 0;
@@ -89,6 +123,11 @@ std::unordered_map parse_descriptor(std::unordered_map>*> usage_map;
+ usage_map[ReportType::INPUT] = &input_usage_map;
+ usage_map[ReportType::OUTPUT] = &output_usage_map;
+ usage_map[ReportType::FEATURE] = &feature_usage_map;
+
while (idx < len) {
if (report_descriptor[idx] == 0 && idx == len - 1) {
continue;
@@ -107,50 +146,92 @@ std::unordered_map parse_descriptor(std::unordered_map parse_descriptor(std::unordered_map parse_descriptor(std::unordered_mapfirst;
+ if (dev_addr_interface >> 8 == dev_addr) {
+ it = their_feature_usages.erase(it);
+ } else {
+ it++;
+ }
+ }
+
for (auto it = their_out_usages.cbegin(); it != their_out_usages.cend();) {
uint16_t dev_addr_interface = it->first;
if (dev_addr_interface >> 8 == dev_addr) {
- has_report_id_theirs_out.erase(dev_addr_interface);
it = their_out_usages.erase(it);
} else {
it++;
diff --git a/firmware/src/descriptor_parser.h b/firmware/src/descriptor_parser.h
index 8966d06..1f46ce7 100644
--- a/firmware/src/descriptor_parser.h
+++ b/firmware/src/descriptor_parser.h
@@ -8,7 +8,19 @@
#include
#include "types.h"
-std::unordered_map parse_descriptor(std::unordered_map>& usage_map, bool& has_report_id, const uint8_t* report_descriptor, int len, bool output = false);
+enum class ReportType : uint8_t {
+ INPUT,
+ OUTPUT,
+ FEATURE,
+};
+
+std::unordered_map> parse_descriptor(
+ std::unordered_map>& input_usage_map,
+ std::unordered_map>& output_usage_map,
+ std::unordered_map>& feature_usage_map,
+ bool& has_report_id,
+ const uint8_t* report_descriptor,
+ int len);
extern "C" {
#endif
diff --git a/firmware/src/dual.h b/firmware/src/dual.h
index c11ded9..5419db5 100644
--- a/firmware/src/dual.h
+++ b/firmware/src/dual.h
@@ -12,6 +12,10 @@ enum class DualCommand : uint8_t {
RESTART = 6,
SEND_OUT_REPORT = 7,
START_OF_FRAME = 8,
+ SET_FEATURE_REPORT = 9,
+ GET_FEATURE_REPORT = 10,
+ GET_FEATURE_RESPONSE = 11,
+ SET_FEATURE_COMPLETE = 12,
};
struct __attribute__((packed)) device_connected_t {
@@ -61,4 +65,35 @@ struct __attribute__((packed)) start_of_frame_t {
DualCommand command = DualCommand::START_OF_FRAME;
};
+struct __attribute__((packed)) set_feature_report_t {
+ DualCommand command = DualCommand::SET_FEATURE_REPORT;
+ uint8_t dev_addr;
+ uint8_t interface;
+ uint8_t report_id;
+ uint8_t report[0];
+};
+
+struct __attribute__((packed)) get_feature_report_t {
+ DualCommand command = DualCommand::GET_FEATURE_REPORT;
+ uint8_t dev_addr;
+ uint8_t interface;
+ uint8_t report_id;
+ uint8_t len;
+};
+
+struct __attribute__((packed)) get_feature_response_t {
+ DualCommand command = DualCommand::GET_FEATURE_RESPONSE;
+ uint8_t dev_addr;
+ uint8_t interface;
+ uint8_t report_id;
+ uint8_t report[0];
+};
+
+struct __attribute__((packed)) set_feature_complete_t {
+ DualCommand command = DualCommand::SET_FEATURE_COMPLETE;
+ uint8_t dev_addr;
+ uint8_t interface;
+ uint8_t report_id;
+};
+
#endif
diff --git a/firmware/src/globals.cc b/firmware/src/globals.cc
index 51ea005..8694406 100644
--- a/firmware/src/globals.cc
+++ b/firmware/src/globals.cc
@@ -2,9 +2,9 @@
std::unordered_map>> their_usages;
std::unordered_map>> their_out_usages;
+std::unordered_map>> their_feature_usages;
std::unordered_map has_report_id_theirs;
-std::unordered_map has_report_id_theirs_out;
std::unordered_map out_reports;
std::unordered_map prev_out_reports;
@@ -26,6 +26,8 @@ uint8_t unmapped_passthrough_layer_mask = 0b00001111;
uint32_t partial_scroll_timeout = 1000000;
uint32_t tap_hold_threshold = 200000;
uint64_t gpio_debounce_time = 5000;
+uint8_t our_descriptor_number = 0;
+bool ignore_auth_dev_inputs = false;
std::vector config_mappings;
@@ -36,3 +38,5 @@ std::vector> macros[NMACROS];
std::vector expressions[NEXPRESSIONS];
bool monitor_enabled = false;
+
+const our_descriptor_def_t* our_descriptor;
diff --git a/firmware/src/globals.h b/firmware/src/globals.h
index 98415f8..64cab51 100644
--- a/firmware/src/globals.h
+++ b/firmware/src/globals.h
@@ -4,16 +4,15 @@
#include
#include
+#include "our_descriptor.h"
#include "types.h"
-extern std::unordered_map>> their_usages; // dev_addr+interface -> report_id -> usage -> usage_def
-
-extern std::unordered_map>> their_out_usages; // dev_addr+interface -> report_id -> usage -> usage_def
+extern std::unordered_map>> their_usages; // dev_addr+interface -> report_id -> usage -> usage_def
+extern std::unordered_map>> their_out_usages; // dev_addr+interface -> report_id -> usage -> usage_def
+extern std::unordered_map>> their_feature_usages; // dev_addr+interface -> report_id -> usage -> usage_def
extern std::unordered_map has_report_id_theirs; // dev_addr+interface -> bool
-extern std::unordered_map has_report_id_theirs_out; // dev_addr+interface -> bool
-
extern std::unordered_map out_reports; // dev_addr+interface << 16 | report_id -> buffer
extern std::unordered_map prev_out_reports; // dev_addr+interface << 16 | report_id -> buffer
extern std::unordered_map out_report_sizes; // dev_addr+interface << 16 | report_id -> size
@@ -34,6 +33,8 @@ extern uint8_t unmapped_passthrough_layer_mask;
extern uint32_t partial_scroll_timeout;
extern uint32_t tap_hold_threshold;
extern uint64_t gpio_debounce_time;
+extern uint8_t our_descriptor_number;
+extern bool ignore_auth_dev_inputs;
extern std::vector config_mappings;
@@ -48,4 +49,6 @@ extern std::vector expressions[NEXPRESSIONS];
extern bool monitor_enabled;
+extern const our_descriptor_def_t* our_descriptor;
+
#endif
diff --git a/firmware/src/main.cc b/firmware/src/main.cc
index eeb1af4..313cee7 100644
--- a/firmware/src/main.cc
+++ b/firmware/src/main.cc
@@ -145,8 +145,9 @@ int main() {
my_mutexes_init();
gpio_pins_init();
tick_init();
- parse_our_descriptor();
load_config(FLASH_CONFIG_IN_MEMORY);
+ our_descriptor = &our_descriptors[our_descriptor_number];
+ parse_our_descriptor();
set_mapping_from_config();
board_init();
extra_init();
@@ -186,6 +187,9 @@ int main() {
if (monitor_enabled && tud_hid_n_ready(1)) {
send_monitor_report(do_send_report);
}
+ if (our_descriptor->main_loop_task != nullptr) {
+ our_descriptor->main_loop_task();
+ }
send_out_report();
if (need_to_persist_config) {
persist_config();
diff --git a/firmware/src/our_descriptor.cc b/firmware/src/our_descriptor.cc
index c87e545..e65f529 100644
--- a/firmware/src/our_descriptor.cc
+++ b/firmware/src/our_descriptor.cc
@@ -1,10 +1,15 @@
+#include
+
+#include "globals.h"
#include "our_descriptor.h"
+#include "ps_auth.h"
+#include "remapper.h"
const uint8_t REPORT_ID_MOUSE = 1;
const uint8_t REPORT_ID_KEYBOARD = 2;
const uint8_t REPORT_ID_CONSUMER = 3;
-const uint8_t our_report_descriptor[] = {
+const uint8_t our_report_descriptor_kb_mouse[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
@@ -133,7 +138,315 @@ const uint8_t our_report_descriptor[] = {
0xC0, // End Collection
};
-const uint32_t our_report_descriptor_length = sizeof(our_report_descriptor);
+const uint8_t our_report_descriptor_absolute[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x02, // Usage (Mouse)
+ 0xA1, 0x01, // Collection (Application)
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x02, // Usage (Mouse)
+ 0xA1, 0x02, // Collection (Logical)
+ 0x85, REPORT_ID_MOUSE, // Report ID (REPORT_ID_MOUSE)
+ 0x09, 0x01, // Usage (Pointer)
+ 0xA1, 0x00, // Collection (Physical)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (0x01)
+ 0x29, 0x08, // Usage Maximum (0x08)
+ 0x95, 0x08, // Report Count (8)
+ 0x75, 0x01, // Report Size (1)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x95, 0x02, // Report Count (2)
+ 0x75, 0x10, // Report Size (16)
+ 0x16, 0x00, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0xA1, 0x02, // Collection (Logical)
+ 0x85, REPORT_ID_MULTIPLIER, // Report ID (REPORT_ID_MULTIPLIER)
+ 0x09, 0x48, // Usage (Resolution Multiplier)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x02, // Report Size (2)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x01, // Physical Minimum (1)
+ 0x45, RESOLUTION_MULTIPLIER, // Physical Maximum (RESOLUTION_MULTIPLIER)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, REPORT_ID_MOUSE, // Report ID (REPORT_ID_MOUSE)
+ 0x09, 0x38, // Usage (Wheel)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x00, // Physical Maximum (0)
+ 0x16, 0x00, 0x80, // Logical Minimum (-32768)
+ 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
+ 0x75, 0x10, // Report Size (16)
+ 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+ 0xA1, 0x02, // Collection (Logical)
+ 0x85, REPORT_ID_MULTIPLIER, // Report ID (REPORT_ID_MULTIPLIER)
+ 0x09, 0x48, // Usage (Resolution Multiplier)
+ 0x75, 0x02, // Report Size (2)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x01, // Physical Minimum (1)
+ 0x45, RESOLUTION_MULTIPLIER, // Physical Maximum (RESOLUTION_MULTIPLIER)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x00, // Physical Maximum (0)
+ 0x75, 0x04, // Report Size (4)
+ 0xB1, 0x03, // Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, REPORT_ID_MOUSE, // Report ID (REPORT_ID_MOUSE)
+ 0x05, 0x0C, // Usage Page (Consumer)
+ 0x16, 0x00, 0x80, // Logical Minimum (-32768)
+ 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
+ 0x75, 0x10, // Report Size (16)
+ 0x0A, 0x38, 0x02, // Usage (AC Pan)
+ 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+ 0xC0, // End Collection
+ 0xC0, // End Collection
+ 0xC0, // End Collection
+
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x06, // Usage (Keyboard)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, REPORT_ID_KEYBOARD, // Report ID (REPORT_ID_KEYBOARD)
+ 0x05, 0x07, // Usage Page (Kbrd/Keypad)
+ 0x19, 0xE0, // Usage Minimum (0xE0)
+ 0x29, 0xE7, // Usage Maximum (0xE7)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x19, 0x04, // Usage Minimum (0x04)
+ 0x29, 0x73, // Usage Maximum (0x73)
+ 0x95, 0x70, // Report Count (112)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x19, 0x87, // Usage Minimum (0x87)
+ 0x29, 0x8B, // Usage Maximum (0x8B)
+ 0x95, 0x05, // Report Count (5)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x09, 0x90, // Usage (0x90)
+ 0x09, 0x91, // Usage (0x91)
+ 0x95, 0x02, // Report Count (2)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x85, REPORT_ID_LEDS, // Report ID (REPORT_ID_LEDS)
+ 0x05, 0x08, // Usage Page (LEDs)
+ 0x95, 0x05, // Report Count (5)
+ 0x19, 0x01, // Usage Minimum (Num Lock)
+ 0x29, 0x05, // Usage Maximum (Kana)
+ 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x03, // Report Size (3)
+ 0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, // End Collection
+
+ 0x05, 0x0C, // Usage Page (Consumer)
+ 0x09, 0x01, // Usage (Consumer Control)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, REPORT_ID_CONSUMER, // Report ID (REPORT_ID_CONSUMER)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x09, 0xB5, // Usage (Scan Next Track)
+ 0x09, 0xB6, // Usage (Scan Previous Track)
+ 0x09, 0xB7, // Usage (Stop)
+ 0x09, 0xCD, // Usage (Play/Pause)
+ 0x09, 0xE2, // Usage (Mute)
+ 0x09, 0xE9, // Usage (Volume Increment)
+ 0x09, 0xEA, // Usage (Volume Decrement)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x07, // Report Count (7)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x05, 0x0B, // Usage Page (Telephony)
+ 0x09, 0x2F, // Usage (Phone Mute)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+};
+
+const uint8_t our_report_descriptor_gamepad[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x05, // Usage (Game Pad)
+ 0xA1, 0x01, // Collection (Application)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x10, // Report Count (16)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (0x01)
+ 0x29, 0x10, // Usage Maximum (0x10)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x25, 0x07, // Logical Maximum (7)
+ 0x46, 0x3B, 0x01, // Physical Maximum (315)
+ 0x75, 0x04, // Report Size (4)
+ 0x95, 0x01, // Report Count (1)
+ 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+ 0x09, 0x39, // Usage (Hat switch)
+ 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
+ 0x65, 0x00, // Unit (None)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x46, 0xFF, 0x00, // Physical Maximum (255)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x09, 0x32, // Usage (Z)
+ 0x09, 0x35, // Usage (Rz)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x04, // Report Count (4)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ 0x09, 0x20, // Usage (0x20)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x0A, 0x21, 0x26, // Usage (0x2621)
+ 0x95, 0x08, // Report Count (8)
+ 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, // End Collection
+};
+
+uint8_t const our_report_descriptor_ps4[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x05, // Usage (Game Pad)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0x01, // Report ID (1)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x09, 0x32, // Usage (Z)
+ 0x09, 0x35, // Usage (Rz)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x04, // Report Count (4)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x09, 0x39, // Usage (Hat switch)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x07, // Logical Maximum (7)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0x3B, 0x01, // Physical Maximum (315)
+ 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+ 0x75, 0x04, // Report Size (4)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
+ 0x65, 0x00, // Unit (None)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (0x01)
+ 0x29, 0x0E, // Usage Maximum (0x0E)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x0E, // Report Count (14)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ 0x09, 0x20, // Usage (0x20)
+ 0x75, 0x06, // Report Size (6)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ 0x09, 0x33, // Usage (Rx)
+ 0x09, 0x34, // Usage (Ry)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x02, // Report Count (2)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ 0x09, 0x21, // Usage (0x21)
+ 0x95, 0x36, // Report Count (54)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x85, 0x05, // Report ID (5)
+ 0x09, 0x22, // Usage (0x22)
+ 0x95, 0x1F, // Report Count (31)
+ 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, 0x03, // Report ID (3)
+ 0x0A, 0x21, 0x27, // Usage (0x2721)
+ 0x95, 0x2F, // Report Count (47)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
+ 0x85, 0xE0, // Report ID (-32)
+ 0x09, 0x57, // Usage (0x57)
+ 0x95, 0x02, // Report Count (2)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, // End Collection
+ 0x06, 0xF0, 0xFF, // Usage Page (Vendor Defined 0xFFF0)
+ 0x09, 0x40, // Usage (0x40)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0xF0, // Report ID (-16)
+ 0x09, 0x47, // Usage (0x47)
+ 0x95, 0x3F, // Report Count (63)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, 0xF1, // Report ID (-15)
+ 0x09, 0x48, // Usage (0x48)
+ 0x95, 0x3F, // Report Count (63)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, 0xF2, // Report ID (-14)
+ 0x09, 0x49, // Usage (0x49)
+ 0x95, 0x0F, // Report Count (15)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x85, 0xF3, // Report ID (-13)
+ 0x0A, 0x01, 0x47, // Usage (0x4701)
+ 0x95, 0x07, // Report Count (7)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0xC0, // End Collection
+};
+
+void kb_mouse_handle_set_report(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen) {
+ if (report_id == REPORT_ID_MULTIPLIER && reqlen >= 1) {
+ memcpy(&resolution_multiplier, buffer, 1);
+ } else if (report_id == REPORT_ID_LEDS) {
+ handle_received_report(buffer, reqlen, OUR_OUT_INTERFACE, report_id);
+ }
+}
+
+uint16_t kb_mouse_handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen) {
+ if (report_id == REPORT_ID_MULTIPLIER && reqlen >= 1) {
+ memcpy(buffer, &resolution_multiplier, 1);
+ return 1;
+ }
+ return 0;
+}
+
+const our_descriptor_def_t our_descriptors[] = {
+ {
+ .descriptor = our_report_descriptor_kb_mouse,
+ .descriptor_length = sizeof(our_report_descriptor_kb_mouse),
+ .handle_received_report = do_handle_received_report,
+ .handle_get_report = kb_mouse_handle_get_report,
+ .handle_set_report = kb_mouse_handle_set_report,
+ },
+ {
+ .descriptor = our_report_descriptor_absolute,
+ .descriptor_length = sizeof(our_report_descriptor_absolute),
+ .handle_received_report = do_handle_received_report,
+ .handle_get_report = kb_mouse_handle_get_report,
+ .handle_set_report = kb_mouse_handle_set_report,
+ },
+ {
+ .descriptor = our_report_descriptor_gamepad,
+ .descriptor_length = sizeof(our_report_descriptor_gamepad),
+ .vid = 0x0F0D,
+ .pid = 0x0092,
+ .handle_received_report = do_handle_received_report,
+ },
+ {
+ .descriptor = our_report_descriptor_ps4,
+ .descriptor_length = sizeof(our_report_descriptor_ps4),
+ .device_connected = ps4_device_connected,
+ .device_disconnected = ps4_device_disconnected,
+ .main_loop_task = ps4_main_loop_task,
+ .handle_received_report = ps4_handle_received_report,
+ .handle_get_report = ps4_handle_get_report,
+ .handle_set_report = ps4_handle_set_report,
+ .handle_get_report_response = ps4_handle_get_report_response,
+ .handle_set_report_complete = ps4_handle_set_report_complete,
+ }
+};
const uint8_t config_report_descriptor[] = {
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
diff --git a/firmware/src/our_descriptor.h b/firmware/src/our_descriptor.h
index b36510a..e7c2c08 100644
--- a/firmware/src/our_descriptor.h
+++ b/firmware/src/our_descriptor.h
@@ -13,8 +13,33 @@
#define MAX_INPUT_REPORT_ID 3
-extern const uint8_t our_report_descriptor[];
-extern const uint32_t our_report_descriptor_length;
+#define NOUR_DESCRIPTORS 4
+
+typedef void (*device_connected_t)(uint16_t interface, uint16_t vid, uint16_t pid);
+typedef void (*device_disconnected_t)(uint8_t dev_addr);
+typedef void (*main_loop_task_t)();
+typedef void (*handle_received_report_t)(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id);
+typedef uint16_t (*handle_get_report_t)(uint8_t report_id, uint8_t* buffer, uint16_t reqlen);
+typedef void (*handle_set_report_t)(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen);
+typedef void (*handle_get_report_response_t)(uint16_t interface, uint8_t report_id, uint8_t* report, uint16_t len);
+typedef void (*handle_set_report_complete_t)(uint16_t interface, uint8_t report_id);
+
+struct our_descriptor_def_t {
+ const uint8_t* descriptor;
+ uint32_t descriptor_length;
+ uint16_t vid = 0;
+ uint16_t pid = 0;
+ device_connected_t device_connected = nullptr;
+ device_disconnected_t device_disconnected = nullptr;
+ main_loop_task_t main_loop_task = nullptr;
+ handle_received_report_t handle_received_report = nullptr;
+ handle_get_report_t handle_get_report = nullptr;
+ handle_set_report_t handle_set_report = nullptr;
+ handle_get_report_response_t handle_get_report_response = nullptr;
+ handle_set_report_complete_t handle_set_report_complete = nullptr;
+};
+
+extern const our_descriptor_def_t our_descriptors[];
extern const uint8_t config_report_descriptor[];
extern const uint32_t config_report_descriptor_length;
diff --git a/firmware/src/out_report.cc b/firmware/src/out_report.cc
index d2d3c71..1cf70c8 100644
--- a/firmware/src/out_report.cc
+++ b/firmware/src/out_report.cc
@@ -10,6 +10,7 @@ struct outgoing_out_report_t {
uint8_t interface;
uint8_t report_id;
uint16_t len;
+ OutType type;
uint8_t report[64]; // XXX
};
@@ -19,9 +20,11 @@ static uint8_t oor_head = 0;
static uint8_t oor_tail = 0;
static uint8_t oor_items = 0;
+static uint8_t get_buffer[64];
+
static bool ready_to_send = true;
-void do_queue_out_report(const uint8_t* report, uint16_t len, uint8_t report_id, uint8_t dev_addr, uint8_t interface) {
+void do_queue_out_report(const uint8_t* report, uint16_t len, uint8_t report_id, uint8_t dev_addr, uint8_t interface, OutType type) {
if (oor_items == OOR_BUFSIZE) {
printf("out overflow!\n");
return;
@@ -33,22 +36,51 @@ void do_queue_out_report(const uint8_t* report, uint16_t len, uint8_t report_id,
outgoing_out_reports[oor_tail].interface = interface;
outgoing_out_reports[oor_tail].report_id = report_id;
outgoing_out_reports[oor_tail].len = len;
+ outgoing_out_reports[oor_tail].type = type;
memcpy(outgoing_out_reports[oor_tail].report, report, len);
oor_tail = (oor_tail + 1) % OOR_BUFSIZE;
oor_items++;
}
+void do_queue_get_report(uint8_t report_id, uint8_t dev_addr, uint8_t interface, uint8_t len) {
+ if (oor_items == OOR_BUFSIZE) {
+ printf("out overflow!\n");
+ return;
+ }
+ outgoing_out_reports[oor_tail].dev_addr = dev_addr;
+ outgoing_out_reports[oor_tail].interface = interface;
+ outgoing_out_reports[oor_tail].report_id = report_id;
+ outgoing_out_reports[oor_tail].type = OutType::GET_FEATURE;
+ outgoing_out_reports[oor_tail].len = len;
+ oor_tail = (oor_tail + 1) % OOR_BUFSIZE;
+ oor_items++;
+}
+
void do_send_out_report() {
if ((oor_items > 0) && ready_to_send) {
outgoing_out_report_t* out = &(outgoing_out_reports[oor_head]);
- if (tuh_hid_set_report(out->dev_addr, out->interface, out->report_id, HID_REPORT_TYPE_OUTPUT, out->report, out->len)) {
- ready_to_send = false;
- oor_head = (oor_head + 1) % OOR_BUFSIZE;
- oor_items--;
+ if ((out->type == OutType::OUTPUT) || (out->type == OutType::SET_FEATURE)) {
+ if (tuh_hid_set_report(out->dev_addr, out->interface, out->report_id, (out->type == OutType::OUTPUT) ? HID_REPORT_TYPE_OUTPUT : HID_REPORT_TYPE_FEATURE, out->report, out->len)) {
+ ready_to_send = false;
+ oor_head = (oor_head + 1) % OOR_BUFSIZE;
+ oor_items--;
+ }
+ } else if (out->type == OutType::GET_FEATURE) {
+ if (tuh_hid_get_report(out->dev_addr, out->interface, out->report_id, HID_REPORT_TYPE_FEATURE, get_buffer, out->len)) {
+ ready_to_send = false;
+ oor_head = (oor_head + 1) % OOR_BUFSIZE;
+ oor_items--;
+ }
}
}
}
void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {
ready_to_send = true;
+ set_report_complete_cb(dev_addr, instance, report_id);
+}
+
+void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len) {
+ ready_to_send = true;
+ get_report_cb(dev_addr, idx, report_id, report_type, get_buffer, len);
}
diff --git a/firmware/src/out_report.h b/firmware/src/out_report.h
index b2c41d0..df23622 100644
--- a/firmware/src/out_report.h
+++ b/firmware/src/out_report.h
@@ -3,7 +3,17 @@
#include
-void do_queue_out_report(const uint8_t* report, uint16_t len, uint8_t report_id, uint8_t dev_addr, uint8_t interface);
+enum class OutType : int8_t {
+ OUTPUT = 0,
+ GET_FEATURE = 1,
+ SET_FEATURE = 2,
+};
+
+void do_queue_out_report(const uint8_t* report, uint16_t len, uint8_t report_id, uint8_t dev_addr, uint8_t interface, OutType type);
+void do_queue_get_report(uint8_t report_id, uint8_t dev_addr, uint8_t interface, uint8_t len);
void do_send_out_report();
+void get_report_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id, uint8_t report_type, uint8_t* report, uint16_t len);
+void set_report_complete_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id);
+
#endif
diff --git a/firmware/src/ps_auth.cc b/firmware/src/ps_auth.cc
new file mode 100644
index 0000000..0d32e23
--- /dev/null
+++ b/firmware/src/ps_auth.cc
@@ -0,0 +1,178 @@
+#include
+#include
+#include
+
+#include "globals.h"
+#include "ps_auth.h"
+#include "remapper.h"
+
+static uint16_t auth_dev;
+static uint8_t nonce_id;
+static uint8_t nonce[280];
+static uint8_t nonce_part = 0;
+static uint8_t signature[1064];
+static uint8_t signature_part = 0;
+static uint8_t signature_ready = 0;
+static uint8_t nonce_ready = 0;
+
+static uint8_t set_buffer[64];
+static bool busy = false;
+
+enum {
+ IDLE = 0,
+ SENDING_RESET = 1,
+ SENDING_NONCE = 2,
+ WAITING_FOR_SIG = 3,
+ RECEIVING_SIG = 4,
+};
+
+static uint8_t state = IDLE;
+
+// Razer Raion
+static const uint8_t output_0x03[] = {
+ 0x21, 0x27, 0x04, 0xc0, 0x07, 0x2c, 0x56,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 };
+
+void ps4_device_connected(uint16_t interface, uint16_t vid, uint16_t pid) {
+ if (their_feature_usages[interface].count(0x03) &&
+ their_feature_usages[interface].count(0xF0) &&
+ their_feature_usages[interface].count(0xF1) &&
+ their_feature_usages[interface].count(0xF2) &&
+ their_feature_usages[interface].count(0xF3)) {
+ printf("ps auth candidate detected\n");
+ if (auth_dev == 0) {
+ auth_dev = interface;
+ }
+ }
+}
+
+void ps4_device_disconnected(uint8_t dev_addr) {
+ if (dev_addr == (auth_dev >> 8)) {
+ auth_dev = 0;
+ }
+}
+
+void ps4_main_loop_task() {
+ if (!busy && auth_dev) {
+ switch (state) {
+ case IDLE:
+ break;
+ case SENDING_RESET:
+ queue_get_feature_report(auth_dev, 0xF3, 7 + 1);
+ busy = true;
+ break;
+ case SENDING_NONCE:
+ set_buffer[0] = 0xF0;
+ set_buffer[1] = nonce_id;
+ set_buffer[2] = nonce_part;
+ set_buffer[3] = 0;
+ memcpy(set_buffer + 4, nonce + (nonce_part * 56), 56);
+ queue_set_feature_report(auth_dev, 0xF0, set_buffer, 64);
+ busy = true;
+ nonce_part++;
+ break;
+ case WAITING_FOR_SIG:
+ queue_get_feature_report(auth_dev, 0xF2, 15 + 1);
+ busy = true;
+ break;
+ case RECEIVING_SIG:
+ queue_get_feature_report(auth_dev, 0xF1, 63 + 1);
+ busy = true;
+ break;
+ }
+ }
+}
+
+void ps4_handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id) {
+ if (!ignore_auth_dev_inputs || (interface != auth_dev)) {
+ do_handle_received_report(report, len, interface, external_report_id);
+ }
+}
+
+uint16_t ps4_handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen) {
+ switch (report_id) {
+ case 0x03:
+ memcpy(buffer, output_0x03, reqlen);
+ return reqlen;
+ case 0xF3:
+ memcpy(buffer, output_0xf3, reqlen);
+ signature_ready = false;
+ return reqlen;
+ case 0xF1: { // GET_SIGNATURE_NONCE
+ buffer[0] = nonce_id;
+ buffer[1] = signature_part;
+ buffer[2] = 0;
+ memcpy(&buffer[3], &signature[signature_part * 56], 56);
+ signature_part++;
+ if (signature_part == 19) {
+ signature_part = 0;
+ }
+ return reqlen;
+ }
+ case 0xF2: { // GET_SIGNING_STATE
+ buffer[0] = nonce_id;
+ buffer[1] = signature_ready ? 0 : 16;
+ memset(&buffer[2], 0, 9);
+ return reqlen;
+ }
+ }
+ return reqlen;
+}
+
+void ps4_handle_set_report(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen) {
+ if (report_id == 0xF0) { // SET_AUTH_PAYLOAD
+ nonce_id = buffer[0];
+ uint8_t part = buffer[1];
+ if (part > 4) {
+ return;
+ }
+ memcpy(&nonce[part * 56], &buffer[3], 56);
+ if (part == 4) {
+ nonce_ready = 1;
+ state = SENDING_RESET;
+ nonce_part = 0;
+ }
+ }
+}
+
+void ps4_handle_get_report_response(uint16_t interface, uint8_t report_id, uint8_t* report, uint16_t len) {
+ if (interface == auth_dev) {
+ busy = false;
+ switch (report_id) {
+ case 0xF3:
+ state = SENDING_NONCE;
+ break;
+ case 0xF2:
+ if (report[2] == 0) {
+ signature_part = 0;
+ state = RECEIVING_SIG;
+ }
+ break;
+ case 0xF1:
+ memcpy(signature + (signature_part * 56), report + 4, 56);
+ signature_part++;
+ if (signature_part == 19) {
+ state = IDLE;
+ signature_ready = true;
+ signature_part = 0;
+ }
+ break;
+ }
+ }
+}
+
+void ps4_handle_set_report_complete(uint16_t interface, uint8_t report_id) {
+ if ((interface == auth_dev) && (report_id == 0xF0)) {
+ busy = false;
+ if (nonce_part == 5) {
+ state = WAITING_FOR_SIG;
+ }
+ }
+}
diff --git a/firmware/src/ps_auth.h b/firmware/src/ps_auth.h
new file mode 100644
index 0000000..cb46fb3
--- /dev/null
+++ b/firmware/src/ps_auth.h
@@ -0,0 +1,13 @@
+#ifndef _PS_AUTH_H_
+#define _PS_AUTH_H_
+
+void ps4_device_connected(uint16_t interface, uint16_t vid, uint16_t pid);
+void ps4_device_disconnected(uint8_t dev_addr);
+void ps4_main_loop_task();
+void ps4_handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id);
+uint16_t ps4_handle_get_report(uint8_t report_id, uint8_t* buffer, uint16_t reqlen);
+void ps4_handle_set_report(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen);
+void ps4_handle_get_report_response(uint16_t interface, uint8_t report_id, uint8_t* report, uint16_t len);
+void ps4_handle_set_report_complete(uint16_t interface, uint8_t report_id);
+
+#endif
diff --git a/firmware/src/remapper.cc b/firmware/src/remapper.cc
index 842ea5f..b1755e2 100644
--- a/firmware/src/remapper.cc
+++ b/firmware/src/remapper.cc
@@ -1040,6 +1040,12 @@ inline void monitor_read_input_range(const uint8_t* report, int len, uint32_t so
}
void handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id) {
+ if (our_descriptor->handle_received_report != nullptr) {
+ our_descriptor->handle_received_report(report, len, interface, external_report_id);
+ }
+}
+
+void do_handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id) {
reports_received++;
my_mutex_enter(MutexId::THEIR_USAGES);
@@ -1188,9 +1194,17 @@ void update_their_descriptor_derivates() {
}
void parse_our_descriptor() {
- bool has_report_id_ours;
- std::unordered_map report_sizes_map = parse_descriptor(our_usages, has_report_id_ours, our_report_descriptor, our_report_descriptor_length);
- for (auto const& [report_id, size] : report_sizes_map) {
+ std::unordered_map> our_feature_usages;
+
+ auto report_sizes_map = parse_descriptor(
+ our_usages,
+ their_usages[OUR_OUT_INTERFACE],
+ our_feature_usages,
+ has_report_id_theirs[OUR_OUT_INTERFACE],
+ our_descriptor->descriptor,
+ our_descriptor->descriptor_length);
+
+ for (auto const& [report_id, size] : report_sizes_map[ReportType::INPUT]) {
report_sizes[report_id] = size;
reports[report_id] = new uint8_t[size];
memset(reports[report_id], 0, size);
@@ -1219,8 +1233,6 @@ void parse_our_descriptor() {
}
rlencode(our_usage_ranges_set, our_usages_rle);
-
- parse_descriptor(their_usages[OUR_OUT_INTERFACE], has_report_id_theirs[OUR_OUT_INTERFACE], our_report_descriptor, our_report_descriptor_length, true);
}
void print_stats() {
@@ -1235,3 +1247,41 @@ void set_monitor_enabled(bool enabled) {
monitor_enabled = enabled;
}
}
+
+void device_connected_callback(uint16_t interface, uint16_t vid, uint16_t pid) {
+ if (our_descriptor->device_connected != nullptr) {
+ our_descriptor->device_connected(interface, vid, pid);
+ }
+}
+
+void device_disconnected_callback(uint8_t dev_addr) {
+ if (our_descriptor->device_disconnected != nullptr) {
+ our_descriptor->device_disconnected(dev_addr);
+ }
+ clear_descriptor_data(dev_addr);
+}
+
+uint16_t handle_get_report0(uint8_t report_id, uint8_t* buffer, uint16_t reqlen) {
+ if (our_descriptor->handle_get_report != nullptr) {
+ return our_descriptor->handle_get_report(report_id, buffer, reqlen);
+ }
+ return 0;
+}
+
+void handle_set_report0(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen) {
+ if (our_descriptor->handle_set_report != nullptr) {
+ our_descriptor->handle_set_report(report_id, buffer, reqlen);
+ }
+}
+
+void handle_get_report_response(uint16_t interface, uint8_t report_id, uint8_t* report, uint16_t len) {
+ if (our_descriptor->handle_get_report_response != nullptr) {
+ our_descriptor->handle_get_report_response(interface, report_id, report, len);
+ }
+}
+
+void handle_set_report_complete(uint16_t interface, uint8_t report_id) {
+ if (our_descriptor->handle_set_report_complete != nullptr) {
+ our_descriptor->handle_set_report_complete(interface, report_id);
+ }
+}
diff --git a/firmware/src/remapper.h b/firmware/src/remapper.h
index ea75673..13d4ae9 100644
--- a/firmware/src/remapper.h
+++ b/firmware/src/remapper.h
@@ -7,6 +7,7 @@ typedef bool (*send_report_t)(uint8_t interface, const uint8_t* report_with_id,
void set_mapping_from_config();
void handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id = 0);
+void do_handle_received_report(const uint8_t* report, int len, uint16_t interface, uint8_t external_report_id = 0);
void set_input_state(uint32_t usage, int32_t state);
void extra_init();
@@ -19,6 +20,8 @@ void process_mapping(bool auto_repeat);
void update_their_descriptor_derivates();
bool send_report(send_report_t do_send_report);
void queue_out_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len);
+void queue_set_feature_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len);
+void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len);
void send_out_report();
bool send_monitor_report(send_report_t do_send_report);
void print_stats();
@@ -28,4 +31,11 @@ void monitor_usage(uint32_t usage, int32_t value);
void sof_callback();
+void device_connected_callback(uint16_t interface, uint16_t vid, uint16_t pid);
+void device_disconnected_callback(uint8_t interface);
+uint16_t handle_get_report0(uint8_t report_id, uint8_t* buffer, uint16_t reqlen);
+void handle_set_report0(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen);
+void handle_get_report_response(uint16_t interface, uint8_t report_id, uint8_t* report, uint16_t len);
+void handle_set_report_complete(uint16_t interface, uint8_t report_id);
+
#endif
diff --git a/firmware/src/remapper_dual_a.cc b/firmware/src/remapper_dual_a.cc
index 48c3974..29dee30 100644
--- a/firmware/src/remapper_dual_a.cc
+++ b/firmware/src/remapper_dual_a.cc
@@ -35,11 +35,12 @@ bool serial_callback(const uint8_t* data, uint16_t len) {
case DualCommand::DEVICE_CONNECTED: {
device_connected_t* msg = (device_connected_t*) data;
parse_descriptor(msg->vid, msg->pid, msg->report_descriptor, len - sizeof(device_connected_t), (uint16_t) (msg->dev_addr << 8) | msg->interface);
+ device_connected_callback((uint16_t) (msg->dev_addr << 8) | msg->interface, msg->vid, msg->pid);
break;
}
case DualCommand::DEVICE_DISCONNECTED: {
device_disconnected_t* msg = (device_disconnected_t*) data;
- clear_descriptor_data(msg->dev_addr);
+ device_disconnected_callback(msg->dev_addr);
break;
}
case DualCommand::REPORT_RECEIVED: {
@@ -54,6 +55,16 @@ bool serial_callback(const uint8_t* data, uint16_t len) {
case DualCommand::START_OF_FRAME:
add_alarm_in_us(300, tick_timer_callback, NULL, true);
break;
+ case DualCommand::GET_FEATURE_RESPONSE: {
+ get_feature_response_t* msg = (get_feature_response_t*) data;
+ handle_get_report_response((uint16_t) (msg->dev_addr << 8) | msg->interface, msg->report_id, msg->report, len - sizeof(get_feature_response_t));
+ break;
+ }
+ case DualCommand::SET_FEATURE_COMPLETE: {
+ set_feature_complete_t* msg = (set_feature_complete_t*) data;
+ handle_set_report_complete((uint16_t) (msg->dev_addr << 8) | msg->interface, msg->report_id);
+ break;
+ }
default:
break;
}
@@ -109,6 +120,26 @@ void queue_out_report(uint16_t interface, uint8_t report_id, const uint8_t* repo
serial_write((uint8_t*) msg, len + sizeof(send_out_report_t));
}
+void queue_set_feature_report(uint16_t interface, uint8_t report_id, const uint8_t* report, uint8_t len) {
+ set_feature_report_t* msg = (set_feature_report_t*) buffer;
+ msg->command = DualCommand::SET_FEATURE_REPORT;
+ msg->dev_addr = interface >> 8;
+ msg->interface = interface & 0xFF;
+ msg->report_id = report_id;
+ memcpy(msg->report, report, len);
+ serial_write((uint8_t*) msg, len + sizeof(set_feature_report_t));
+}
+
+void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len) {
+ get_feature_report_t* msg = (get_feature_report_t*) buffer;
+ msg->command = DualCommand::GET_FEATURE_REPORT;
+ msg->dev_addr = interface >> 8;
+ msg->interface = interface & 0xFF;
+ msg->report_id = report_id;
+ msg->len = len;
+ serial_write((uint8_t*) msg, sizeof(get_feature_report_t));
+}
+
void send_out_report() {
}
diff --git a/firmware/src/remapper_dual_b.cc b/firmware/src/remapper_dual_b.cc
index 542c5f1..11fa9c0 100644
--- a/firmware/src/remapper_dual_b.cc
+++ b/firmware/src/remapper_dual_b.cc
@@ -25,7 +25,17 @@ bool serial_callback(const uint8_t* data, uint16_t len) {
break;
case DualCommand::SEND_OUT_REPORT: {
send_out_report_t* msg = (send_out_report_t*) data;
- do_queue_out_report(msg->report, len - sizeof(send_out_report_t), msg->report_id, msg->dev_addr, msg->interface);
+ do_queue_out_report(msg->report, len - sizeof(send_out_report_t), msg->report_id, msg->dev_addr, msg->interface, OutType::OUTPUT);
+ break;
+ }
+ case DualCommand::SET_FEATURE_REPORT: {
+ set_feature_report_t* msg = (set_feature_report_t*) data;
+ do_queue_out_report(msg->report, len - sizeof(set_feature_report_t), msg->report_id, msg->dev_addr, msg->interface, OutType::SET_FEATURE);
+ break;
+ }
+ case DualCommand::GET_FEATURE_REPORT: {
+ get_feature_report_t* msg = (get_feature_report_t*) data;
+ do_queue_get_report(msg->report_id, msg->dev_addr, msg->interface, msg->len);
break;
}
default:
@@ -104,3 +114,22 @@ void tuh_sof_cb() {
start_of_frame_t msg;
serial_write((uint8_t*) &msg, sizeof(msg));
}
+
+void get_report_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id, uint8_t report_type, uint8_t* report, uint16_t len) {
+ get_feature_response_t* msg = (get_feature_response_t*) buffer;
+ msg->command = DualCommand::GET_FEATURE_RESPONSE;
+ msg->dev_addr = dev_addr;
+ msg->interface = interface;
+ msg->report_id = report_id;
+ memcpy(msg->report, report, len);
+ serial_write((uint8_t*) msg, len + sizeof(get_feature_response_t));
+}
+
+void set_report_complete_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id) {
+ set_feature_complete_t* msg = (set_feature_complete_t*) buffer;
+ msg->command = DualCommand::SET_FEATURE_COMPLETE;
+ msg->dev_addr = dev_addr;
+ msg->interface = interface;
+ msg->report_id = report_id;
+ serial_write((uint8_t*) msg, sizeof(set_feature_complete_t));
+}
diff --git a/firmware/src/remapper_serial.cc b/firmware/src/remapper_serial.cc
index d045fdd..553c916 100644
--- a/firmware/src/remapper_serial.cc
+++ b/firmware/src/remapper_serial.cc
@@ -125,6 +125,12 @@ void flash_b_side() {
void queue_out_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len) {
}
+void queue_set_feature_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len) {
+}
+
+void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len) {
+}
+
void send_out_report() {
}
diff --git a/firmware/src/remapper_single.cc b/firmware/src/remapper_single.cc
index b9fda37..354f415 100644
--- a/firmware/src/remapper_single.cc
+++ b/firmware/src/remapper_single.cc
@@ -41,12 +41,14 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
parse_descriptor(vid, pid, desc_report, desc_len, (uint16_t) (dev_addr << 8) | instance);
+ device_connected_callback((uint16_t) (dev_addr << 8) | instance, vid, pid);
+
tuh_hid_receive_report(dev_addr, instance);
}
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
printf("tuh_hid_umount_cb\n");
- clear_descriptor_data(dev_addr);
+ device_disconnected_callback(dev_addr);
}
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
@@ -60,7 +62,15 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
}
void queue_out_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len) {
- do_queue_out_report(buffer, len, report_id, interface >> 8, interface & 0xFF);
+ do_queue_out_report(buffer, len, report_id, interface >> 8, interface & 0xFF, OutType::OUTPUT);
+}
+
+void queue_set_feature_report(uint16_t interface, uint8_t report_id, const uint8_t* buffer, uint8_t len) {
+ do_queue_out_report(buffer, len, report_id, interface >> 8, interface & 0xFF, OutType::SET_FEATURE);
+}
+
+void queue_get_feature_report(uint16_t interface, uint8_t report_id, uint8_t len) {
+ do_queue_get_report(report_id, interface >> 8, interface & 0xFF, len);
}
void send_out_report() {
@@ -76,3 +86,11 @@ static int64_t manual_sof(alarm_id_t id, void* user_data) {
void sof_callback() {
add_alarm_in_us(150, manual_sof, NULL, true);
}
+
+void get_report_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id, uint8_t report_type, uint8_t* report, uint16_t len) {
+ handle_get_report_response((uint16_t) (dev_addr << 8) | interface, report_id, report, len);
+}
+
+void set_report_complete_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id) {
+ handle_set_report_complete((uint16_t) (dev_addr << 8) | interface, report_id);
+}
diff --git a/firmware/src/tinyusb_stuff.cc b/firmware/src/tinyusb_stuff.cc
index 4752f81..22e4951 100644
--- a/firmware/src/tinyusb_stuff.cc
+++ b/firmware/src/tinyusb_stuff.cc
@@ -27,6 +27,7 @@
#include
#include "config.h"
+#include "globals.h"
#include "our_descriptor.h"
#include "platform.h"
#include "remapper.h"
@@ -36,7 +37,7 @@
#define USB_VID 0xCAFE
#define USB_PID 0xBAF2
-tusb_desc_device_t const desc_device = {
+tusb_desc_device_t desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
@@ -56,17 +57,12 @@ tusb_desc_device_t const desc_device = {
.bNumConfigurations = 0x01,
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_HID_DESC_LEN)
-#define EPNUM_HID1 0x81
-#define EPNUM_HID2 0x82
-
-uint8_t const desc_configuration[] = {
- // Config number, interface count, string index, total length, attribute, power in mA
- TUD_CONFIG_DESCRIPTOR(1, 2, 0, CONFIG_TOTAL_LEN, 0, 100),
-
- // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
- TUD_HID_DESCRIPTOR(0, 0, HID_ITF_PROTOCOL_NONE, our_report_descriptor_length, EPNUM_HID1, CFG_TUD_HID_EP_BUFSIZE, 1),
- TUD_HID_DESCRIPTOR(1, 0, HID_ITF_PROTOCOL_NONE, config_report_descriptor_length, EPNUM_HID2, CFG_TUD_HID_EP_BUFSIZE, 1),
+uint8_t desc_configuration[] = {
+ /* Config number, interface count, string index, total length, attribute, power in mA */
+ TUD_CONFIG_DESCRIPTOR(1, 2, 0, TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN + TUD_HID_DESC_LEN, 0, 100),
+ /* Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval */
+ TUD_HID_INOUT_DESCRIPTOR(0, 0, HID_ITF_PROTOCOL_NONE, /* placeholder */ 0x00, 0x02, 0x81, CFG_TUD_HID_EP_BUFSIZE, 1),
+ TUD_HID_DESCRIPTOR(1, 0, HID_ITF_PROTOCOL_NONE, config_report_descriptor_length, 0x83, CFG_TUD_HID_EP_BUFSIZE, 1),
};
char const* string_desc_arr[] = {
@@ -78,6 +74,10 @@ char const* string_desc_arr[] = {
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const* tud_descriptor_device_cb() {
+ if ((our_descriptor->vid != 0) && (our_descriptor->pid != 0)) {
+ desc_device.idVendor = our_descriptor->vid;
+ desc_device.idProduct = our_descriptor->pid;
+ }
return (uint8_t const*) &desc_device;
}
@@ -85,6 +85,7 @@ uint8_t const* tud_descriptor_device_cb() {
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
+ desc_configuration[25] = our_descriptor->descriptor_length; // XXX there has to be a better way
return desc_configuration;
}
@@ -93,7 +94,7 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
// Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) {
if (itf == 0) {
- return our_report_descriptor;
+ return our_descriptor->descriptor;
} else if (itf == 1) {
return config_report_descriptor;
}
@@ -147,16 +148,23 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
}
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
- // we don't pass interface number, but report IDs are unique across interfaces
- return handle_get_report(report_id, buffer, reqlen);
+ if (itf == 0) {
+ return handle_get_report0(report_id, buffer, reqlen);
+ } else {
+ return handle_get_report1(report_id, buffer, reqlen);
+ }
}
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
- if (report_id == REPORT_ID_LEDS) {
- handle_received_report(buffer, bufsize, OUR_OUT_INTERFACE, report_id);
+ if (itf == 0) {
+ if ((report_id == 0) && (report_type == 0) && (bufsize > 0)) {
+ report_id = buffer[0];
+ buffer++;
+ }
+ handle_set_report0(report_id, buffer, bufsize);
+ } else {
+ handle_set_report1(report_id, buffer, bufsize);
}
- // we don't pass interface number, but report IDs are unique across interfaces
- handle_set_report(report_id, buffer, bufsize);
}
void tud_mount_cb() {
diff --git a/firmware/src/types.h b/firmware/src/types.h
index 7092ac2..c56ec3a 100644
--- a/firmware/src/types.h
+++ b/firmware/src/types.h
@@ -190,7 +190,18 @@ struct __attribute__((packed)) persist_config_v7_t {
uint8_t gpio_debounce_time_ms;
};
-typedef persist_config_v7_t persist_config_t;
+struct __attribute__((packed)) persist_config_v9_t {
+ uint8_t version;
+ uint8_t flags;
+ uint32_t partial_scroll_timeout;
+ uint32_t mapping_count;
+ uint8_t interval_override;
+ uint32_t tap_hold_threshold;
+ uint8_t gpio_debounce_time_ms;
+ uint8_t our_descriptor_number;
+};
+
+typedef persist_config_v9_t persist_config_t;
struct __attribute__((packed)) get_config_t {
uint8_t version;
@@ -202,6 +213,7 @@ struct __attribute__((packed)) get_config_t {
uint8_t interval_override;
uint32_t tap_hold_threshold;
uint8_t gpio_debounce_time_ms;
+ uint8_t our_descriptor_number;
};
struct __attribute__((packed)) set_config_t {
@@ -210,6 +222,7 @@ struct __attribute__((packed)) set_config_t {
uint8_t interval_override;
uint32_t tap_hold_threshold;
uint8_t gpio_debounce_time_ms;
+ uint8_t our_descriptor_number;
};
struct __attribute__((packed)) get_indexed_t {