first working prototype
Signed-off-by: Szymon Łopaciuk <szymon@lopaciuk.eu>
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
# stm32-adb2usb [WIP]
|
||||
# stm32-adb2usb
|
||||
|
||||
A simple implementation of an ADB to USB converter for the STM32F103 'Blue Pill'.
|
||||
This is work in progress and is not yet functional.
|
||||
It is currently functional, but there are many ways in which it could be improved upon (see TODO).
|
||||
Testing done on an STM32F103 (or rather actually a Chinese clone), but in the end should be compatible with other STM32 microcontrollers/boards.
|
||||
This code is a Platform IO project reliant on ST's stm32duino, although I am sure it could be easily converted to something else.
|
||||
|
||||
## Useful resources
|
||||
|
||||
I aim to make the code as easy to follow as it is possible in this case, especially the part relating to the ADB protocol.
|
||||
However, there are some resources that are very useful in understanding how the protocol works, and which I used:
|
||||
By far the best and most comprehensive description of the ADB protocol and devices is Apple's [Guide to the Macintosh© Family Hardware (2nd ed.)](https://archive.org/details/apple-guide-macintosh-family-hardware) (chapter 8, p. 287).
|
||||
Some other resources that were useful to me as well:
|
||||
|
||||
- [ADB - The Untold Story: Space Aliens Ate My Mouse'](https://developer.apple.com/library/archive/technotes/hw/hw_01.html#//apple_ref/doc/uid/DTS10002470) by Apple, the most 'authoritative' source, but lacks some key spec features
|
||||
- [ADB - The Untold Story: Space Aliens Ate My Mouse'](https://developer.apple.com/library/archive/technotes/hw/hw_01.html#//apple_ref/doc/uid/DTS10002470) by Apple, quick introduction to what ADB is about, but lacks some key spec features
|
||||
- https://web.archive.org/save/http://85.226.187.247/_pdf/Processor_Memory/PIC1617/MIDRANGE/00591A.PDF
|
||||
- Inside Macintosh volume V, pages 191-192, for the keycodes
|
||||
- Inside Macintosh volume V, pages 191-192, for keycodes
|
||||
- [This blog post](https://www.bigmessowires.com/2016/03/30/understanding-the-adb-service-request-signal/) which explains `Srq` and `Tlt`
|
||||
|
||||
## TODO
|
||||
|
||||
- [x] Make the keyboard work
|
||||
- [ ] Make the mouse work
|
||||
- [ ] Ditch bitfields as the ordering of bytes/bits is confusing and not super portable (see tests failing; passing around uint16_t and then casting to bitfield structs is really dodgy and I shouldn't be doing that)
|
||||
- [ ] Handle SRQs and multiple devices of the same type properly
|
||||
- [ ] Make the layout easier to customise (swap a control, or num lock, for fn?)
|
||||
|
||||
+4
-1
@@ -19,8 +19,10 @@ build_flags =
|
||||
-D USBD_VID=0x0483
|
||||
-D USBD_PID=0x5711
|
||||
-D USB_MANUFACTURER="STMicroelectronics"
|
||||
-D USB_PRODUCT="Apple Desktop Bus Device"
|
||||
-D USB_PRODUCT="Apple Desktop Bus Device"
|
||||
-D HAL_PCD_MODULE_ENABLED
|
||||
;-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||
;-D PIO_FRAMEWORK_ARDUINO_USB_FULLSPEED_FULLMODE
|
||||
upload_flags = -c set CPUTAPID 0x2ba01477 ; Chinese clone, genuine is 0x1ba01477
|
||||
debug_tool = stlink
|
||||
upload_protocol = stlink
|
||||
@@ -39,5 +41,6 @@ platform = native
|
||||
build_flags =
|
||||
-D USBCON
|
||||
-D USBD_USE_HID_COMPOSITE
|
||||
-D PIO_FRAMEWORK_ARDUINO_ENABLE_HID
|
||||
-I $PROJECT_DIR/test/test_desktop/include
|
||||
test_build_project_src = true
|
||||
@@ -2,21 +2,20 @@
|
||||
#define ADB_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stm32f1xx_hal_gpio.h>
|
||||
|
||||
#define ADB_DATA_PIN PB4
|
||||
#define ADB_DATA_PORT GPIOB
|
||||
#define ADB_DATA_PIN_NO 4
|
||||
#define ADB_WRITE(bit) digitalWrite(ADB_DATA_PIN, bit)
|
||||
//#define ADB_WRITE(bit) HAL_GPIO_WritePin(ADB_DATA_PORT, ADB_DATA_PIN_NO, (GPIO_PinState)(bit));
|
||||
#define ADB_READ() (digitalRead(ADB_DATA_PIN))
|
||||
//#define ADB_READ() HAL_GPIO_ReadPin(ADB_DATA_PORT, ADB_DATA_PIN_NO)
|
||||
|
||||
#define ADB_ADDRESS(addr) (addr << 4)
|
||||
#define ADB_REGISTER(reg) (reg)
|
||||
#define ADB_CMD_TALK 0b1100
|
||||
#define ADB_CMD_LISTEN 0b1000
|
||||
#define ADB_CMD_FLUSH 0b0001
|
||||
#define ADB_CMD_TALK (0b11 << 2)
|
||||
#define ADB_CMD_LISTEN (0b10 << 2)
|
||||
#define ADB_CMD_FLUSH (0b01 << 2)
|
||||
|
||||
#define ADB_BIT_ERROR 0xFF
|
||||
|
||||
// Reset: signal low for 3 ms.
|
||||
static void adb_reset() {
|
||||
@@ -69,6 +68,13 @@ static void adb_write_bits(uint16_t bits, uint8_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
// Like adb_write_bits, but add start and stop bits
|
||||
static void adb_write_data_packet(uint16_t bits, uint8_t length) {
|
||||
adb_write_bit(1);
|
||||
adb_write_bits(bits, length);
|
||||
adb_write_bit(0);
|
||||
}
|
||||
|
||||
// Send the '0' stop bit, and listen for an SRQ.
|
||||
// ``If a device in need of service issues a service request,
|
||||
// it must do so within the 65 μs of the Stop Bit’s low time
|
||||
@@ -92,13 +98,17 @@ void adb_write_command(uint8_t command_byte) {
|
||||
adb_stop_bit_srq_listen(); // TODO: Handle the SRQ
|
||||
}
|
||||
|
||||
// Stop-to-start time: period of 160 - 240 μs before device's
|
||||
// Stop-to-start time: period of 140 - 260 μs before device's
|
||||
// response when the bus is held high.
|
||||
// Returns: true if the response is starting, false if timeout
|
||||
static bool adb_wait_tlt() {
|
||||
// spec says 160 μs, but it seems that Macintoshes allowed 140 μs,
|
||||
// (see `ADB - The Untold Story: Space Aliens Ate My Mouse'):
|
||||
static bool adb_wait_tlt(bool response_expected) {
|
||||
ADB_WRITE(HIGH);
|
||||
delayMicroseconds(140);
|
||||
uint8_t i = 0;
|
||||
while (ADB_READ() == HIGH && i < 240 && response_expected) {
|
||||
delayMicroseconds(1);
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -111,7 +121,7 @@ static uint8_t adb_read_bit() {
|
||||
// devices need to stick to 30% precision, 65 * 1.3 = 85 μs
|
||||
// if this time is exceeded assume timeout
|
||||
if (micros() - time_start > 85)
|
||||
return 0xFF;
|
||||
return ADB_BIT_ERROR;
|
||||
}
|
||||
auto low_time = micros() - time_start;
|
||||
|
||||
@@ -119,7 +129,7 @@ static uint8_t adb_read_bit() {
|
||||
// devices need to stick to 30% precision, 65 * 1.3 = 85 μs
|
||||
// if this time is exceeded assume timeout
|
||||
if (micros() - time_start - low_time > 85)
|
||||
return 0xFF;
|
||||
return ADB_BIT_ERROR;
|
||||
}
|
||||
auto high_time = micros() - time_start - low_time;
|
||||
|
||||
@@ -129,14 +139,17 @@ static uint8_t adb_read_bit() {
|
||||
// Read `length` bits from the bus into `buffer`.
|
||||
bool adb_read_data_packet(uint16_t* buffer, uint8_t length)
|
||||
{
|
||||
uint8_t start_bit = adb_read_bit(); // should equal to '1'
|
||||
if (start_bit != 0x1) {return false;}
|
||||
if (adb_read_bit() != 0x1) { // start bit should equal to '1'
|
||||
return false;
|
||||
}
|
||||
|
||||
*buffer = 0;
|
||||
for (uint8_t i = 0; i < length; i++)
|
||||
{
|
||||
uint8_t current_bit = adb_read_bit();
|
||||
if (current_bit == 0xFF) return false;
|
||||
if (current_bit == ADB_BIT_ERROR) {
|
||||
return false;
|
||||
}
|
||||
*buffer <<= 1;
|
||||
*buffer |= current_bit;
|
||||
}
|
||||
@@ -147,7 +160,7 @@ bool adb_read_data_packet(uint16_t* buffer, uint8_t length)
|
||||
|
||||
void adb_init() {
|
||||
pinMode(ADB_DATA_PIN, OUTPUT_OPEN_DRAIN);
|
||||
digitalWrite(ADB_DATA_PIN, HIGH);
|
||||
ADB_WRITE(HIGH);
|
||||
|
||||
while (ADB_READ() == LOW); // wait for the bus
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef ADB_DEVICES_h
|
||||
#define ADB_DEVICES_h
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "adb.h"
|
||||
#include "hid_keyboard.h"
|
||||
#include "adb_structures.h"
|
||||
|
||||
adb_kb_data<adb_kb_modifiers> adb_keyboard_read_modifiers(bool* error) {
|
||||
adb_kb_data<adb_kb_modifiers> modifiers = {0};
|
||||
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(2));
|
||||
adb_wait_tlt(true);
|
||||
*error = !adb_read_data_packet(&modifiers.raw, 16);
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
adb_kb_data<adb_kb_keypress> adb_keyboard_read_key_press(bool* error) {
|
||||
adb_kb_data<adb_kb_keypress> key_press = {0};
|
||||
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(0));
|
||||
adb_wait_tlt(true);
|
||||
*error = !adb_read_data_packet(&key_press.raw, 16);
|
||||
return key_press;
|
||||
}
|
||||
|
||||
adb_kb_data<adb_register3> adb_keyboard_read_register3(bool* error) {
|
||||
adb_kb_data<adb_register3> reg3 = {0};
|
||||
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(3));
|
||||
adb_wait_tlt(true);
|
||||
*error = !adb_read_data_packet(®3.raw, 16);
|
||||
return reg3;
|
||||
}
|
||||
|
||||
|
||||
bool adb_keyboard_update_register3(adb_kb_data<adb_register3> new_reg3, uint16_t mask, bool* error) {
|
||||
// Read the initial value
|
||||
adb_kb_data<adb_register3> reg3 = adb_keyboard_read_register3(error);
|
||||
if (*error) return false;
|
||||
delay(ADB_POLL_DELAY);
|
||||
|
||||
// Apply the change
|
||||
reg3.raw = (reg3.raw & ~mask) | (new_reg3.raw & mask);
|
||||
|
||||
// Write the new value
|
||||
adb_write_command(ADB_CMD_LISTEN | ADB_ADDRESS(2) | ADB_REGISTER(3));
|
||||
adb_wait_tlt(false);
|
||||
adb_write_data_packet(reg3.raw, 16);
|
||||
delay(ADB_POLL_DELAY);
|
||||
|
||||
// Read the current value
|
||||
reg3 = adb_keyboard_read_register3(error);
|
||||
if (*error) return false;
|
||||
|
||||
// Check if update worked, return true
|
||||
if ((reg3.raw & mask) == (new_reg3.raw & mask))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void adb_keyboard_write_leds(bool scroll, bool caps, bool num) {
|
||||
adb_kb_data<adb_kb_modifiers> modifiers = {0};
|
||||
modifiers.data.led_scroll = !scroll;
|
||||
modifiers.data.led_caps = !caps;
|
||||
modifiers.data.led_num = !num;
|
||||
|
||||
adb_write_command(ADB_CMD_LISTEN | ADB_ADDRESS(2) | ADB_REGISTER(2));
|
||||
adb_wait_tlt(false);
|
||||
adb_write_data_packet(modifiers.raw, 16);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef ADB_STRUCTURES_h
|
||||
#define ADB_STRUCTURES_h
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define KEY_POWER 0x66
|
||||
|
||||
#define ADB_KEY_POWER_DOWN 0x7F7F
|
||||
#define ADB_KEY_POWER_UP 0xFFFF
|
||||
|
||||
#define ADB_KEY_LEFT_SHIFT 0x38
|
||||
#define ADB_KEY_RIGHT_SHIFT 0x7B
|
||||
#define ADB_KEY_LEFT_CONTROL 0x36
|
||||
#define ADB_KEY_RIGHT_CONTROL 0x7D
|
||||
#define ADB_KEY_LEFT_OPTION 0x3A
|
||||
#define ADB_KEY_RIGHT_OPTION 0x7C
|
||||
#define ADB_KEY_LEFT_COMMAND 0x37
|
||||
#define ADB_KEY_RIGHT_COMMAND 0x37
|
||||
#define ADB_KEY_CAPS_LOCK 0x39
|
||||
|
||||
struct adb_kb_keypress {
|
||||
uint8_t key1 : 7;
|
||||
bool released1 : 1;
|
||||
uint8_t key0 : 7;
|
||||
bool released0 : 1;
|
||||
};
|
||||
|
||||
struct adb_kb_modifiers {
|
||||
// Only on Apple Extended Keyboard:
|
||||
bool led_num : 1; // 0, ditto
|
||||
bool led_caps : 1; // 1, ditto
|
||||
bool led_scroll : 1; // 2, changeable with `listen' command
|
||||
uint8_t reserved1 : 3; // 5–3
|
||||
bool scroll_lock : 1; // 6
|
||||
bool num_lock : 1; // 7
|
||||
// Apple Standard Keyboard:
|
||||
bool command : 1; // 8
|
||||
bool option : 1; // 9
|
||||
bool shift : 1; // 10
|
||||
bool control : 1; // 11
|
||||
bool reset : 1; // 12
|
||||
bool caps_lock : 1; // 13
|
||||
bool backspace : 1; // 14
|
||||
uint8_t reserved0 : 1; // 15
|
||||
};
|
||||
|
||||
// Contains device info and params
|
||||
struct adb_register3 {
|
||||
uint8_t device_handler_id : 8;
|
||||
uint8_t device_address : 4;
|
||||
uint8_t reserved1 : 1; // must be 0
|
||||
uint8_t srq_enable : 1;
|
||||
uint8_t exceptional_event : 1; // device specific, always 1 if not used
|
||||
uint8_t reserved0 : 1; // must be 0
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
union adb_kb_data {
|
||||
uint16_t raw;
|
||||
T data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "hid_keyboard.h"
|
||||
#include "usbd_hid_composite_if.h"
|
||||
#include <Arduino.h>
|
||||
#include "keymap.h"
|
||||
|
||||
void hid_keyboard_init()
|
||||
{
|
||||
HID_Composite_Init(HID_KEYBOARD);
|
||||
}
|
||||
|
||||
void hid_keyboard_close()
|
||||
{
|
||||
HID_Composite_DeInit(HID_KEYBOARD);
|
||||
}
|
||||
|
||||
void hid_keyboard_send_report(hid_key_report* report)
|
||||
{
|
||||
uint8_t buf[8] = {report->modifiers, 0, report->keys[0],
|
||||
report->keys[1], report->keys[2], report->keys[3], report->keys[4],
|
||||
report->keys[5]
|
||||
};
|
||||
HID_Composite_keyboard_sendReport(buf, 8);
|
||||
}
|
||||
|
||||
bool hid_keyboard_set_keys_from_adb_register(
|
||||
hid_key_report* report, adb_kb_data<adb_kb_keypress> key_press) {
|
||||
// Power button is a special case, residing in both octets:
|
||||
if (key_press.raw == ADB_KEY_POWER_DOWN)
|
||||
return hid_keyboard_update_key_in_report(report, KEY_POWER, false);
|
||||
else if (key_press.raw == ADB_KEY_POWER_UP)
|
||||
return hid_keyboard_update_key_in_report(report, KEY_POWER, true);
|
||||
|
||||
// Other keys:
|
||||
bool report_changed = false;
|
||||
// Higher octet key:
|
||||
uint8_t key0 = key_press.data.key0;
|
||||
if (adb_keymap_is_modifier(key0))
|
||||
report_changed = hid_keyboard_update_modifier_in_report(
|
||||
report, key0, key_press.data.released0);
|
||||
else
|
||||
report_changed = hid_keyboard_update_key_in_report(
|
||||
report, adb_keycode_to_hid[key0], key_press.data.released0);
|
||||
|
||||
// Lower octet key:
|
||||
uint8_t key1 = key_press.data.key1;
|
||||
if (adb_keymap_is_modifier(key1))
|
||||
report_changed = hid_keyboard_update_modifier_in_report(
|
||||
report, key1, key_press.data.released1) || report_changed;
|
||||
else
|
||||
report_changed = hid_keyboard_update_key_in_report(
|
||||
report, adb_keycode_to_hid[key1], key_press.data.released1) || report_changed;
|
||||
|
||||
return report_changed;
|
||||
}
|
||||
|
||||
bool hid_keyboard_set_modifiers_from_adb_register(
|
||||
hid_key_report* report, adb_kb_data<adb_kb_keypress> reg) {
|
||||
// TODO: don't seem necessary, as modifiers still register normal keypresses
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hid_keyboard_update_key_in_report(hid_key_report* report, uint8_t hid_keycode, bool released) {
|
||||
// Sometimes the response from the ADB keyboard is rubbish:
|
||||
// either an invalid key, or lifting a key that's not been pressed.
|
||||
// This detects the first case, so we don't waste time processing it.
|
||||
if (hid_keycode == KEY_NONE) return false;
|
||||
|
||||
if (released)
|
||||
return hid_keyboard_remove_key_from_report(report, hid_keycode);
|
||||
else
|
||||
return hid_keyboard_add_key_to_report(report, hid_keycode);
|
||||
}
|
||||
|
||||
bool hid_keyboard_update_modifier_in_report(hid_key_report* report, uint8_t adb_keycode, bool released) {
|
||||
auto put_key = [released, report](uint8_t mask) mutable {
|
||||
// no change if the modifier is already set
|
||||
if (released == !(report->modifiers & mask)) return false;
|
||||
|
||||
// flip the modifier
|
||||
if (!released) report->modifiers |= mask;
|
||||
else report->modifiers &= ~mask;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (adb_keycode == ADB_KEY_LEFT_SHIFT) return put_key(KEY_MOD_LSHIFT);
|
||||
if (adb_keycode == ADB_KEY_RIGHT_SHIFT) return put_key(KEY_MOD_RSHIFT);
|
||||
if (adb_keycode == ADB_KEY_LEFT_CONTROL) return put_key(KEY_MOD_LCTRL);
|
||||
if (adb_keycode == ADB_KEY_RIGHT_CONTROL) return put_key(KEY_MOD_RCTRL);
|
||||
if (adb_keycode == ADB_KEY_LEFT_OPTION) return put_key(KEY_MOD_LALT);
|
||||
if (adb_keycode == ADB_KEY_RIGHT_OPTION) return put_key(KEY_MOD_RALT);
|
||||
if (adb_keycode == ADB_KEY_LEFT_COMMAND) return put_key(KEY_MOD_LMETA);
|
||||
if (adb_keycode == ADB_KEY_RIGHT_COMMAND) return put_key(KEY_MOD_RMETA);
|
||||
|
||||
return false; // unreachable
|
||||
}
|
||||
|
||||
// Returns true if after execution the key is in the report
|
||||
// in other words, returns false if insertion unsuccessful (report unchanged)
|
||||
bool hid_keyboard_add_key_to_report(hid_key_report* report, uint8_t hid_keycode) {
|
||||
int8_t free_slot = -1;
|
||||
|
||||
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
|
||||
if (report->keys[i] == hid_keycode)
|
||||
return true; // key is already in the report
|
||||
|
||||
if (report->keys[i] == 0 && free_slot == -1)
|
||||
free_slot = i; // memorise empty entry idx
|
||||
}
|
||||
|
||||
if (free_slot == -1)
|
||||
return false; // key report is full
|
||||
|
||||
report->keys[free_slot] = hid_keycode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hid_keyboard_remove_key_from_report(hid_key_report* report, uint8_t hid_keycode) {
|
||||
bool report_changed = false;
|
||||
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
|
||||
if (report->keys[i] == hid_keycode) {
|
||||
report->keys[i] = 0;
|
||||
report_changed = true;
|
||||
}
|
||||
}
|
||||
return report_changed;
|
||||
}
|
||||
|
||||
//#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef HID_KEYBOARD_h
|
||||
#define HID_KEYBOARD_h
|
||||
|
||||
#include <cstdint>
|
||||
#include "adb_structures.h"
|
||||
|
||||
#define KEY_REPORT_KEYS_COUNT 6
|
||||
|
||||
struct hid_key_report {
|
||||
uint8_t modifiers;
|
||||
uint8_t keys[KEY_REPORT_KEYS_COUNT];
|
||||
};
|
||||
|
||||
void hid_keyboard_init();
|
||||
void hid_keyboard_close();
|
||||
void hid_keyboard_send_report(hid_key_report* report);
|
||||
bool hid_keyboard_set_keys_from_adb_register(hid_key_report* report, adb_kb_data<adb_kb_keypress> reg);
|
||||
bool hid_keyboard_set_modifiers_from_adb_register(hid_key_report* report, adb_kb_data<adb_kb_keypress> reg);
|
||||
bool hid_keyboard_update_key_in_report(hid_key_report* report, uint8_t hid_keycode, bool released);
|
||||
bool hid_keyboard_update_modifier_in_report(hid_key_report* report, uint8_t adb_keycode, bool released);
|
||||
bool hid_keyboard_add_key_to_report(hid_key_report* report, uint8_t hid_keycode);
|
||||
bool hid_keyboard_remove_key_from_report(hid_key_report* report, uint8_t hid_keycode);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,274 @@
|
||||
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf, pp. 53
|
||||
// adapted from https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2
|
||||
|
||||
#ifndef HID_TABLES_h
|
||||
#define HID_TABLES_h
|
||||
|
||||
#define KEY_MOD_LCTRL 0x01
|
||||
#define KEY_MOD_LSHIFT 0x02
|
||||
#define KEY_MOD_LALT 0x04
|
||||
#define KEY_MOD_LMETA 0x08
|
||||
#define KEY_MOD_RCTRL 0x10
|
||||
#define KEY_MOD_RSHIFT 0x20
|
||||
#define KEY_MOD_RALT 0x40
|
||||
#define KEY_MOD_RMETA 0x80
|
||||
|
||||
/**
|
||||
* 0x00 if no key pressed.
|
||||
*
|
||||
* If more than N keys are pressed, the HID reports
|
||||
* KEY_ERR_OVF in all slots to indicate this condition.
|
||||
*/
|
||||
|
||||
#define KEY_NONE 0x00 // No key pressed
|
||||
#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
|
||||
// 0x02 // Keyboard POST Fail
|
||||
// 0x03 // Keyboard Error Undefined
|
||||
#define KEY_A 0x04 // Keyboard a and A
|
||||
#define KEY_B 0x05 // Keyboard b and B
|
||||
#define KEY_C 0x06 // Keyboard c and C
|
||||
#define KEY_D 0x07 // Keyboard d and D
|
||||
#define KEY_E 0x08 // Keyboard e and E
|
||||
#define KEY_F 0x09 // Keyboard f and F
|
||||
#define KEY_G 0x0a // Keyboard g and G
|
||||
#define KEY_H 0x0b // Keyboard h and H
|
||||
#define KEY_I 0x0c // Keyboard i and I
|
||||
#define KEY_J 0x0d // Keyboard j and J
|
||||
#define KEY_K 0x0e // Keyboard k and K
|
||||
#define KEY_L 0x0f // Keyboard l and L
|
||||
#define KEY_M 0x10 // Keyboard m and M
|
||||
#define KEY_N 0x11 // Keyboard n and N
|
||||
#define KEY_O 0x12 // Keyboard o and O
|
||||
#define KEY_P 0x13 // Keyboard p and P
|
||||
#define KEY_Q 0x14 // Keyboard q and Q
|
||||
#define KEY_R 0x15 // Keyboard r and R
|
||||
#define KEY_S 0x16 // Keyboard s and S
|
||||
#define KEY_T 0x17 // Keyboard t and T
|
||||
#define KEY_U 0x18 // Keyboard u and U
|
||||
#define KEY_V 0x19 // Keyboard v and V
|
||||
#define KEY_W 0x1a // Keyboard w and W
|
||||
#define KEY_X 0x1b // Keyboard x and X
|
||||
#define KEY_Y 0x1c // Keyboard y and Y
|
||||
#define KEY_Z 0x1d // Keyboard z and Z
|
||||
|
||||
#define KEY_1 0x1e // Keyboard 1 and !
|
||||
#define KEY_2 0x1f // Keyboard 2 and @
|
||||
#define KEY_3 0x20 // Keyboard 3 and #
|
||||
#define KEY_4 0x21 // Keyboard 4 and $
|
||||
#define KEY_5 0x22 // Keyboard 5 and %
|
||||
#define KEY_6 0x23 // Keyboard 6 and ^
|
||||
#define KEY_7 0x24 // Keyboard 7 and &
|
||||
#define KEY_8 0x25 // Keyboard 8 and *
|
||||
#define KEY_9 0x26 // Keyboard 9 and (
|
||||
#define KEY_0 0x27 // Keyboard 0 and )
|
||||
|
||||
#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
|
||||
#define KEY_ESC 0x29 // Keyboard ESCAPE
|
||||
#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
|
||||
#define KEY_TAB 0x2b // Keyboard Tab
|
||||
#define KEY_SPACE 0x2c // Keyboard Spacebar
|
||||
#define KEY_MINUS 0x2d // Keyboard - and _
|
||||
#define KEY_EQUAL 0x2e // Keyboard = and +
|
||||
#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
|
||||
#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
|
||||
#define KEY_BACKSLASH 0x31 // Keyboard \ and |
|
||||
#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
|
||||
#define KEY_SEMICOLON 0x33 // Keyboard ; and :
|
||||
#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
|
||||
#define KEY_GRAVE 0x35 // Keyboard ` and ~
|
||||
#define KEY_COMMA 0x36 // Keyboard , and <
|
||||
#define KEY_DOT 0x37 // Keyboard . and >
|
||||
#define KEY_SLASH 0x38 // Keyboard / and ?
|
||||
#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
|
||||
|
||||
#define KEY_F1 0x3a // Keyboard F1
|
||||
#define KEY_F2 0x3b // Keyboard F2
|
||||
#define KEY_F3 0x3c // Keyboard F3
|
||||
#define KEY_F4 0x3d // Keyboard F4
|
||||
#define KEY_F5 0x3e // Keyboard F5
|
||||
#define KEY_F6 0x3f // Keyboard F6
|
||||
#define KEY_F7 0x40 // Keyboard F7
|
||||
#define KEY_F8 0x41 // Keyboard F8
|
||||
#define KEY_F9 0x42 // Keyboard F9
|
||||
#define KEY_F10 0x43 // Keyboard F10
|
||||
#define KEY_F11 0x44 // Keyboard F11
|
||||
#define KEY_F12 0x45 // Keyboard F12
|
||||
|
||||
#define KEY_SYSRQ 0x46 // Keyboard Print Screen
|
||||
#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
|
||||
#define KEY_PAUSE 0x48 // Keyboard Pause
|
||||
#define KEY_INSERT 0x49 // Keyboard Insert
|
||||
#define KEY_HOME 0x4a // Keyboard Home
|
||||
#define KEY_PAGEUP 0x4b // Keyboard Page Up
|
||||
#define KEY_DELETE 0x4c // Keyboard Delete Forward
|
||||
#define KEY_END 0x4d // Keyboard End
|
||||
#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
|
||||
#define KEY_RIGHT 0x4f // Keyboard Right Arrow
|
||||
#define KEY_LEFT 0x50 // Keyboard Left Arrow
|
||||
#define KEY_DOWN 0x51 // Keyboard Down Arrow
|
||||
#define KEY_UP 0x52 // Keyboard Up Arrow
|
||||
|
||||
#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
|
||||
#define KEY_KPSLASH 0x54 // Keypad /
|
||||
#define KEY_KPASTERISK 0x55 // Keypad *
|
||||
#define KEY_KPMINUS 0x56 // Keypad -
|
||||
#define KEY_KPPLUS 0x57 // Keypad +
|
||||
#define KEY_KPENTER 0x58 // Keypad ENTER
|
||||
#define KEY_KP1 0x59 // Keypad 1 and End
|
||||
#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
|
||||
#define KEY_KP3 0x5b // Keypad 3 and PageDn
|
||||
#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
|
||||
#define KEY_KP5 0x5d // Keypad 5
|
||||
#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
|
||||
#define KEY_KP7 0x5f // Keypad 7 and Home
|
||||
#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
|
||||
#define KEY_KP9 0x61 // Keypad 9 and Page Up
|
||||
#define KEY_KP0 0x62 // Keypad 0 and Insert
|
||||
#define KEY_KPDOT 0x63 // Keypad . and Delete
|
||||
|
||||
#define KEY_102ND 0x64 // Keyboard Non-US \ and |
|
||||
#define KEY_COMPOSE 0x65 // Keyboard Application
|
||||
#define KEY_POWER 0x66 // Keyboard Power
|
||||
#define KEY_KPEQUAL 0x67 // Keypad =
|
||||
|
||||
#define KEY_F13 0x68 // Keyboard F13
|
||||
#define KEY_F14 0x69 // Keyboard F14
|
||||
#define KEY_F15 0x6a // Keyboard F15
|
||||
#define KEY_F16 0x6b // Keyboard F16
|
||||
#define KEY_F17 0x6c // Keyboard F17
|
||||
#define KEY_F18 0x6d // Keyboard F18
|
||||
#define KEY_F19 0x6e // Keyboard F19
|
||||
#define KEY_F20 0x6f // Keyboard F20
|
||||
#define KEY_F21 0x70 // Keyboard F21
|
||||
#define KEY_F22 0x71 // Keyboard F22
|
||||
#define KEY_F23 0x72 // Keyboard F23
|
||||
#define KEY_F24 0x73 // Keyboard F24
|
||||
|
||||
#define KEY_OPEN 0x74 // Keyboard Execute
|
||||
#define KEY_HELP 0x75 // Keyboard Help
|
||||
#define KEY_PROPS 0x76 // Keyboard Menu
|
||||
#define KEY_FRONT 0x77 // Keyboard Select
|
||||
#define KEY_STOP 0x78 // Keyboard Stop
|
||||
#define KEY_AGAIN 0x79 // Keyboard Again
|
||||
#define KEY_UNDO 0x7a // Keyboard Undo
|
||||
#define KEY_CUT 0x7b // Keyboard Cut
|
||||
#define KEY_COPY 0x7c // Keyboard Copy
|
||||
#define KEY_PASTE 0x7d // Keyboard Paste
|
||||
#define KEY_FIND 0x7e // Keyboard Find
|
||||
#define KEY_MUTE 0x7f // Keyboard Mute
|
||||
#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
|
||||
#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
|
||||
// 0x82 Keyboard Locking Caps Lock
|
||||
// 0x83 Keyboard Locking Num Lock
|
||||
// 0x84 Keyboard Locking Scroll Lock
|
||||
#define KEY_KPCOMMA 0x85 // Keypad Comma
|
||||
// 0x86 Keypad Equal Sign
|
||||
#define KEY_RO 0x87 // Keyboard International1
|
||||
#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
|
||||
#define KEY_YEN 0x89 // Keyboard International3
|
||||
#define KEY_HENKAN 0x8a // Keyboard International4
|
||||
#define KEY_MUHENKAN 0x8b // Keyboard International5
|
||||
#define KEY_KPJPCOMMA 0x8c // Keyboard International6
|
||||
// 0x8d Keyboard International7
|
||||
// 0x8e Keyboard International8
|
||||
// 0x8f Keyboard International9
|
||||
#define KEY_HANGEUL 0x90 // Keyboard LANG1
|
||||
#define KEY_HANJA 0x91 // Keyboard LANG2
|
||||
#define KEY_KATAKANA 0x92 // Keyboard LANG3
|
||||
#define KEY_HIRAGANA 0x93 // Keyboard LANG4
|
||||
#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
|
||||
// 0x95 Keyboard LANG6
|
||||
// 0x96 Keyboard LANG7
|
||||
// 0x97 Keyboard LANG8
|
||||
// 0x98 Keyboard LANG9
|
||||
// 0x99 Keyboard Alternate Erase
|
||||
// 0x9a Keyboard SysReq/Attention
|
||||
// 0x9b Keyboard Cancel
|
||||
// 0x9c Keyboard Clear
|
||||
// 0x9d Keyboard Prior
|
||||
// 0x9e Keyboard Return
|
||||
// 0x9f Keyboard Separator
|
||||
// 0xa0 Keyboard Out
|
||||
// 0xa1 Keyboard Oper
|
||||
// 0xa2 Keyboard Clear/Again
|
||||
// 0xa3 Keyboard CrSel/Props
|
||||
// 0xa4 Keyboard ExSel
|
||||
|
||||
// 0xb0 Keypad 00
|
||||
// 0xb1 Keypad 000
|
||||
// 0xb2 Thousands Separator
|
||||
// 0xb3 Decimal Separator
|
||||
// 0xb4 Currency Unit
|
||||
// 0xb5 Currency Sub-unit
|
||||
#define KEY_KPLEFTPAREN 0xb6 // Keypad (
|
||||
#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
|
||||
// 0xb8 Keypad {
|
||||
// 0xb9 Keypad }
|
||||
// 0xba Keypad Tab
|
||||
// 0xbb Keypad Backspace
|
||||
// 0xbc Keypad A
|
||||
// 0xbd Keypad B
|
||||
// 0xbe Keypad C
|
||||
// 0xbf Keypad D
|
||||
// 0xc0 Keypad E
|
||||
// 0xc1 Keypad F
|
||||
// 0xc2 Keypad XOR
|
||||
// 0xc3 Keypad ^
|
||||
// 0xc4 Keypad %
|
||||
// 0xc5 Keypad <
|
||||
// 0xc6 Keypad >
|
||||
// 0xc7 Keypad &
|
||||
// 0xc8 Keypad &&
|
||||
// 0xc9 Keypad |
|
||||
// 0xca Keypad ||
|
||||
// 0xcb Keypad :
|
||||
// 0xcc Keypad #
|
||||
// 0xcd Keypad Space
|
||||
// 0xce Keypad @
|
||||
// 0xcf Keypad !
|
||||
// 0xd0 Keypad Memory Store
|
||||
// 0xd1 Keypad Memory Recall
|
||||
// 0xd2 Keypad Memory Clear
|
||||
// 0xd3 Keypad Memory Add
|
||||
// 0xd4 Keypad Memory Subtract
|
||||
// 0xd5 Keypad Memory Multiply
|
||||
// 0xd6 Keypad Memory Divide
|
||||
// 0xd7 Keypad +/-
|
||||
// 0xd8 Keypad Clear
|
||||
// 0xd9 Keypad Clear Entry
|
||||
// 0xda Keypad Binary
|
||||
// 0xdb Keypad Octal
|
||||
// 0xdc Keypad Decimal
|
||||
// 0xdd Keypad Hexadecimal
|
||||
|
||||
#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
|
||||
#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
|
||||
#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
|
||||
#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
|
||||
#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
|
||||
#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
|
||||
#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
|
||||
#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
|
||||
|
||||
#define KEY_MEDIA_PLAYPAUSE 0xe8
|
||||
#define KEY_MEDIA_STOPCD 0xe9
|
||||
#define KEY_MEDIA_PREVIOUSSONG 0xea
|
||||
#define KEY_MEDIA_NEXTSONG 0xeb
|
||||
#define KEY_MEDIA_EJECTCD 0xec
|
||||
#define KEY_MEDIA_VOLUMEUP 0xed
|
||||
#define KEY_MEDIA_VOLUMEDOWN 0xee
|
||||
#define KEY_MEDIA_MUTE 0xef
|
||||
#define KEY_MEDIA_WWW 0xf0
|
||||
#define KEY_MEDIA_BACK 0xf1
|
||||
#define KEY_MEDIA_FORWARD 0xf2
|
||||
#define KEY_MEDIA_STOP 0xf3
|
||||
#define KEY_MEDIA_FIND 0xf4
|
||||
#define KEY_MEDIA_SCROLLUP 0xf5
|
||||
#define KEY_MEDIA_SCROLLDOWN 0xf6
|
||||
#define KEY_MEDIA_EDIT 0xf7
|
||||
#define KEY_MEDIA_SLEEP 0xf8
|
||||
#define KEY_MEDIA_COFFEE 0xf9
|
||||
#define KEY_MEDIA_REFRESH 0xfa
|
||||
#define KEY_MEDIA_CALC 0xfb
|
||||
|
||||
#endif
|
||||
+142
-5
@@ -1,12 +1,149 @@
|
||||
#ifndef KEYMAP_h
|
||||
#define KEYMAP_h
|
||||
#include <cstdint>
|
||||
#include "hid_tables.h"
|
||||
|
||||
#define KEY_POWER 0x66
|
||||
bool adb_keymap_is_modifier(uint8_t key) {
|
||||
return \
|
||||
(key == ADB_KEY_LEFT_SHIFT) ||
|
||||
(key == ADB_KEY_RIGHT_SHIFT) ||
|
||||
(key == ADB_KEY_LEFT_OPTION) ||
|
||||
(key == ADB_KEY_RIGHT_OPTION) ||
|
||||
(key == ADB_KEY_LEFT_COMMAND) ||
|
||||
(key == ADB_KEY_RIGHT_COMMAND) ||
|
||||
(key == ADB_KEY_LEFT_CONTROL) ||
|
||||
(key == ADB_KEY_RIGHT_CONTROL);
|
||||
}
|
||||
|
||||
#define ADB_KEY_POWER_DOWN 0x7F7F
|
||||
#define ADB_KEY_POWER_UP 0xFFFF
|
||||
|
||||
uint8_t* adb_keycode_to_hid = {0x0}; // TODO
|
||||
uint8_t adb_keycode_to_hid[128] = {
|
||||
/* 0x00 = */ KEY_A,
|
||||
/* 0x01 = */ KEY_S,
|
||||
/* 0x02 = */ KEY_D,
|
||||
/* 0x03 = */ KEY_F,
|
||||
/* 0x04 = */ KEY_H,
|
||||
/* 0x05 = */ KEY_G,
|
||||
/* 0x06 = */ KEY_Z,
|
||||
/* 0x07 = */ KEY_X,
|
||||
/* 0x08 = */ KEY_C,
|
||||
/* 0x09 = */ KEY_V,
|
||||
/* 0x0a = */ KEY_102ND,
|
||||
/* 0x0b = */ KEY_B,
|
||||
/* 0x0c = */ KEY_Q,
|
||||
/* 0x0d = */ KEY_W,
|
||||
/* 0x0e = */ KEY_E,
|
||||
/* 0x0f = */ KEY_R,
|
||||
/* 0x10 = */ KEY_Y,
|
||||
/* 0x11 = */ KEY_T,
|
||||
/* 0x12 = */ KEY_1,
|
||||
/* 0x13 = */ KEY_2,
|
||||
/* 0x14 = */ KEY_3,
|
||||
/* 0x15 = */ KEY_4,
|
||||
/* 0x16 = */ KEY_6,
|
||||
/* 0x17 = */ KEY_5,
|
||||
/* 0x18 = */ KEY_EQUAL,
|
||||
/* 0x19 = */ KEY_9,
|
||||
/* 0x1a = */ KEY_7,
|
||||
/* 0x1b = */ KEY_MINUS,
|
||||
/* 0x1c = */ KEY_8,
|
||||
/* 0x1d = */ KEY_0,
|
||||
/* 0x1e = */ KEY_RIGHTBRACE,
|
||||
/* 0x1f = */ KEY_O,
|
||||
/* 0x20 = */ KEY_U,
|
||||
/* 0x21 = */ KEY_LEFTBRACE,
|
||||
/* 0x22 = */ KEY_I,
|
||||
/* 0x23 = */ KEY_P,
|
||||
/* 0x24 = */ KEY_ENTER,
|
||||
/* 0x25 = */ KEY_L,
|
||||
/* 0x26 = */ KEY_J,
|
||||
/* 0x27 = */ KEY_APOSTROPHE,
|
||||
/* 0x28 = */ KEY_K,
|
||||
/* 0x29 = */ KEY_SEMICOLON,
|
||||
/* 0x2a = */ KEY_HASHTILDE,
|
||||
/* 0x2b = */ KEY_COMMA,
|
||||
/* 0x2c = */ KEY_SLASH,
|
||||
/* 0x2d = */ KEY_N,
|
||||
/* 0x2e = */ KEY_M,
|
||||
/* 0x2f = */ KEY_DOT,
|
||||
/* 0x30 = */ KEY_TAB,
|
||||
/* 0x31 = */ KEY_SPACE,
|
||||
/* 0x32 = */ KEY_GRAVE,
|
||||
/* 0x33 = */ KEY_BACKSPACE,
|
||||
/* 0x34 = */ 0,
|
||||
/* 0x35 = */ KEY_ESC,
|
||||
/* 0x36 = */ KEY_LEFTCTRL,
|
||||
/* 0x37 = */ KEY_LEFTMETA,
|
||||
/* 0x38 = */ KEY_LEFTSHIFT,
|
||||
/* 0x39 = */ KEY_CAPSLOCK,
|
||||
/* 0x3a = */ KEY_LEFTALT,
|
||||
/* 0x3b = */ KEY_LEFT,
|
||||
/* 0x3c = */ KEY_RIGHT,
|
||||
/* 0x3d = */ KEY_DOWN,
|
||||
/* 0x3e = */ KEY_UP,
|
||||
/* 0x3f = */ 0,
|
||||
/* 0x40 = */ 0,
|
||||
/* 0x41 = */ KEY_KPDOT,
|
||||
/* 0x42 = */ 0,
|
||||
/* 0x43 = */ KEY_KPASTERISK,
|
||||
/* 0x44 = */ 0,
|
||||
/* 0x45 = */ KEY_KPPLUS,
|
||||
/* 0x46 = */ 0,
|
||||
/* 0x47 = */ KEY_NUMLOCK,
|
||||
/* 0x48 = */ 0,
|
||||
/* 0x49 = */ 0,
|
||||
/* 0x4a = */ 0,
|
||||
/* 0x4b = */ KEY_KPSLASH,
|
||||
/* 0x4c = */ KEY_KPENTER,
|
||||
/* 0x4d = */ 0,
|
||||
/* 0x4e = */ KEY_KPMINUS,
|
||||
/* 0x4f = */ 0,
|
||||
/* 0x50 = */ 0,
|
||||
/* 0x51 = */ KEY_KPEQUAL,
|
||||
/* 0x52 = */ KEY_KP0,
|
||||
/* 0x53 = */ KEY_KP1,
|
||||
/* 0x54 = */ KEY_KP2,
|
||||
/* 0x55 = */ KEY_KP3,
|
||||
/* 0x56 = */ KEY_KP4,
|
||||
/* 0x57 = */ KEY_KP5,
|
||||
/* 0x58 = */ KEY_KP6,
|
||||
/* 0x59 = */ KEY_KP7,
|
||||
/* 0x5a = */ 0,
|
||||
/* 0x5b = */ KEY_KP8,
|
||||
/* 0x5c = */ KEY_KP9,
|
||||
/* 0x5d = */ 0,
|
||||
/* 0x5e = */ 0,
|
||||
/* 0x5f = */ 0,
|
||||
/* 0x60 = */ KEY_F5,
|
||||
/* 0x61 = */ KEY_F6,
|
||||
/* 0x62 = */ KEY_F7,
|
||||
/* 0x63 = */ KEY_F3,
|
||||
/* 0x64 = */ KEY_F8,
|
||||
/* 0x65 = */ KEY_F9,
|
||||
/* 0x66 = */ 0,
|
||||
/* 0x67 = */ KEY_VOLUMEDOWN, //KEY_F11,
|
||||
/* 0x68 = */ 0,
|
||||
/* 0x69 = */ KEY_F13,
|
||||
/* 0x6a = */ 0,
|
||||
/* 0x6b = */ KEY_F14,
|
||||
/* 0x6c = */ 0,
|
||||
/* 0x6d = */ KEY_MUTE, //KEY_F10,
|
||||
/* 0x6e = */ 0,
|
||||
/* 0x6f = */ KEY_VOLUMEUP, //KEY_F12,
|
||||
/* 0x70 = */ 0,
|
||||
/* 0x71 = */ KEY_F15,
|
||||
/* 0x72 = */ KEY_HELP, // or KEY_INSERT
|
||||
/* 0x73 = */ KEY_HOME,
|
||||
/* 0x74 = */ KEY_PAGEUP,
|
||||
/* 0x75 = */ KEY_DELETE,
|
||||
/* 0x76 = */ KEY_F4,
|
||||
/* 0x77 = */ KEY_END,
|
||||
/* 0x78 = */ KEY_F2,
|
||||
/* 0x79 = */ KEY_PAGEDOWN,
|
||||
/* 0x7a = */ KEY_F1,
|
||||
/* 0x7b = */ KEY_RIGHTSHIFT,
|
||||
/* 0x7c = */ KEY_RIGHTALT,
|
||||
/* 0x7d = */ KEY_RIGHTCTRL,
|
||||
/* 0x7e = */ 0,
|
||||
/* 0x7f = */ KEY_POWER, // Special key, repeated in both bytes of the register
|
||||
};
|
||||
|
||||
#endif
|
||||
+98
-44
@@ -2,66 +2,120 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stm32f1xx_hal_gpio.h>
|
||||
#include <Keyboard.h>
|
||||
#include "adb.h"
|
||||
#include "hid_tables.h"
|
||||
#include "adb_structures.h"
|
||||
#include "hid_keyboard.h"
|
||||
#include "adb_devices.h"
|
||||
|
||||
void setup() {
|
||||
Keyboard.begin();
|
||||
pinMode(PC13, OUTPUT);
|
||||
digitalWrite(PC13, LOW);
|
||||
#define POLL_DELAY 5
|
||||
|
||||
delay(5000);
|
||||
digitalWrite(PC13, HIGH);
|
||||
|
||||
Keyboard.print("Setting up IO...\n");
|
||||
pinMode(ADB_DATA_PIN, OUTPUT_OPEN_DRAIN);
|
||||
ADB_WRITE(HIGH);
|
||||
Keyboard.print("Waiting for ADB high... ");
|
||||
|
||||
while(LOW == ADB_READ());
|
||||
Keyboard.print("Ready.\n");
|
||||
|
||||
Keyboard.print("Resetting... ");
|
||||
adb_reset();
|
||||
delay(500); // A wait for good measure, apparently AEKII can take a moment to reset
|
||||
Keyboard.print("Ready.\n");
|
||||
}
|
||||
bool apple_extended_detected = false;
|
||||
|
||||
#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||
void print16b(uint16_t buff) {
|
||||
uint16_t mask = (1 << 15);
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
Keyboard.write(buff & mask ? '1' : '0');
|
||||
Serial.write(buff & mask ? '1' : '0');
|
||||
mask >>= 1;
|
||||
}
|
||||
Serial.write('\n');
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
void printkbresp(uint16_t buff) {
|
||||
void printkbresp(adb_kb_keypress buff) {
|
||||
//Keyboard.print(" key1 ");
|
||||
Keyboard.print(buff & (1 << 15) ? "u" : "d");
|
||||
Keyboard.print((buff & (0x7F << 8)) >> 8, 16);
|
||||
//Keyboard.print(" key2 ");
|
||||
//Keyboard.print(buff & (1 << 7) ? "up \t" : "down\t");
|
||||
//Keyboard.print(buff & 0x7F, 16);
|
||||
Keyboard.print("\n");
|
||||
Serial.print(buff.released0 ? "u" : "d");
|
||||
Serial.print(buff.key0, 16);
|
||||
Serial.print(", ");
|
||||
Serial.print(buff.released1 ? "u" : "d");
|
||||
Serial.print(buff.key1, 16);
|
||||
Serial.print("\n");
|
||||
Serial.flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
// Turn the led on at the beginning of setup
|
||||
pinMode(PC13, OUTPUT);
|
||||
digitalWrite(PC13, LOW);
|
||||
|
||||
#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
|
||||
Serial.begin(115200);
|
||||
#endif
|
||||
|
||||
// Set up HID
|
||||
hid_keyboard_init();
|
||||
|
||||
// Set up the ADB bus
|
||||
adb_init();
|
||||
|
||||
delay(1000); // A wait for good measure, apparently AEKII can take a moment to reset
|
||||
|
||||
// Initialise the ADB devices
|
||||
// Switch the keyboard to Apple Extended if available
|
||||
bool error = false;
|
||||
adb_kb_data<adb_register3> reg3 = {0}, mask = {0};
|
||||
reg3.data.device_handler_id = 0x03;
|
||||
mask.data.device_handler_id = 0xFF;
|
||||
apple_extended_detected = adb_keyboard_update_register3(reg3, mask.raw, &error);
|
||||
|
||||
// Set-up successful, turn of the LED
|
||||
digitalWrite(PC13, HIGH);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//Keyboard.print("Talk addr 3 reg 0... ");
|
||||
//noInterrupts();
|
||||
uint16_t buffer = 0;
|
||||
adb_write_command(ADB_CMD_TALK | ADB_ADDRESS(2) | ADB_REGISTER(0));
|
||||
adb_wait_tlt();
|
||||
bool success = adb_read_data_packet(&buffer, 17);
|
||||
|
||||
//interrupts();
|
||||
if (success) {
|
||||
//print16b(buffer);
|
||||
printkbresp(buffer);
|
||||
// TODO: Add proper polling based on SRQ
|
||||
static bool led_caps = false;
|
||||
static hid_key_report key_report = {0};
|
||||
bool error = false;
|
||||
|
||||
auto key_press = adb_keyboard_read_key_press(&error);
|
||||
|
||||
if (error) return; // don't continue changing the hid report if there was
|
||||
// an error reading from ADB – most often it's a timeout
|
||||
|
||||
bool report_changed = hid_keyboard_set_keys_from_adb_register(&key_report, key_press);
|
||||
|
||||
// Handle the `toggle' caps lock key.
|
||||
// Every action reported by an ADB keyboard on the caps lock key
|
||||
// should be interpreted as key down, followed by key released,
|
||||
// unless the keypress was so fast, that it was pressed and depressed
|
||||
// within the same `register'. Then ignore.
|
||||
bool caps_lock_action = key_press.data.key0 == ADB_KEY_CAPS_LOCK ||
|
||||
key_press.data.key1 == ADB_KEY_CAPS_LOCK;
|
||||
|
||||
bool caps_lock_twice_in_register = key_press.data.key0 == ADB_KEY_CAPS_LOCK &&
|
||||
key_press.data.key1 == ADB_KEY_CAPS_LOCK &&
|
||||
key_press.data.released0 != key_press.data.released1;
|
||||
|
||||
if (caps_lock_action && !caps_lock_twice_in_register)
|
||||
{
|
||||
hid_keyboard_add_key_to_report(&key_report, KEY_CAPSLOCK);
|
||||
|
||||
// Send the preliminary report, with caps lock down
|
||||
hid_keyboard_send_report(&key_report);
|
||||
|
||||
led_caps = !led_caps;
|
||||
adb_keyboard_write_leds(0, led_caps, 0);
|
||||
|
||||
// Wait a little bit
|
||||
delay(80);
|
||||
|
||||
// Now just release the caps lock key, and continue as before
|
||||
hid_keyboard_remove_key_from_report(&key_report, KEY_CAPSLOCK);
|
||||
|
||||
report_changed = true;
|
||||
}
|
||||
//else
|
||||
// Keyboard.print("timeout.\n");
|
||||
delay(5);
|
||||
|
||||
// Send the finished report
|
||||
if (report_changed)
|
||||
hid_keyboard_send_report(&key_report);
|
||||
|
||||
// Wait a tiny bit before polling again,
|
||||
// while ADB seems fairly tolarent of quick requests
|
||||
// we don't want to overwhelm USB either
|
||||
delay(POLL_DELAY);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include "raw_keyboard.h"
|
||||
#include "keymap.h"
|
||||
|
||||
#if defined(USBCON)
|
||||
#include "usbd_hid_composite_if.h"
|
||||
|
||||
RawKeyboard::RawKeyboard() {
|
||||
keyReport = (KeyReport) {0};
|
||||
}
|
||||
|
||||
void RawKeyboard::begin(void)
|
||||
{
|
||||
HID_Composite_Init(HID_KEYBOARD);
|
||||
}
|
||||
|
||||
void RawKeyboard::end(void)
|
||||
{
|
||||
HID_Composite_DeInit(HID_KEYBOARD);
|
||||
}
|
||||
|
||||
void RawKeyboard::sendReport()
|
||||
{
|
||||
uint8_t buf[8] = {keyReport.modifiers, keyReport.reserved, keyReport.keys[0],
|
||||
keyReport.keys[1], keyReport.keys[2], keyReport.keys[3], keyReport.keys[4],
|
||||
keyReport.keys[5]
|
||||
};
|
||||
|
||||
HID_Composite_keyboard_sendReport(buf, 8);
|
||||
|
||||
//delay required to prevent persistent key when call print
|
||||
delay(20);
|
||||
}
|
||||
|
||||
void RawKeyboard::setKeysFromADBRegister(uint16_t reg) {
|
||||
if (reg == ADB_KEY_POWER_DOWN) // power button is a special case
|
||||
{ // residing in both octets
|
||||
updateKeyInReport(KEY_POWER, false);
|
||||
}
|
||||
else if (reg == ADB_KEY_POWER_UP) {
|
||||
updateKeyInReport(KEY_POWER, true);
|
||||
}
|
||||
else {
|
||||
// Higher octet key:
|
||||
uint8_t key0 = (reg >> 8) & 0x7F;
|
||||
bool released0 = (reg >> 8) & 0x80;
|
||||
updateKeyInReport(adb_keycode_to_hid[key0], released0);
|
||||
|
||||
// Lower octet key:
|
||||
uint8_t key1 = reg & 0x7F;
|
||||
bool released1 = reg & 0x80;
|
||||
updateKeyInReport(adb_keycode_to_hid[key1], released1);
|
||||
}
|
||||
}
|
||||
|
||||
void RawKeyboard::setModifiersFromADBRegister(uint16_t reg) {
|
||||
|
||||
}
|
||||
|
||||
void RawKeyboard::updateKeyInReport(uint8_t hid_keycode, bool released) {
|
||||
if (released)
|
||||
removeKeyFromReport(hid_keycode);
|
||||
else
|
||||
addKeyToReport(hid_keycode);
|
||||
}
|
||||
|
||||
// Returns true if after execution the key is in the report
|
||||
bool RawKeyboard::addKeyToReport(uint8_t hid_keycode) {
|
||||
int8_t free_slot = -1;
|
||||
|
||||
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
|
||||
if (keyReport.keys[i] == hid_keycode)
|
||||
return true; // key is already in the report
|
||||
|
||||
if (keyReport.keys[i] == 0 && free_slot == -1)
|
||||
free_slot = i; // memorise empty entry idx
|
||||
}
|
||||
|
||||
if (free_slot == -1)
|
||||
return false; // key report is full
|
||||
|
||||
keyReport.keys[free_slot] = hid_keycode;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RawKeyboard::removeKeyFromReport(uint8_t hid_keycode) {
|
||||
for (uint8_t i = 0; i < KEY_REPORT_KEYS_COUNT; i++) {
|
||||
if (keyReport.keys[i] == hid_keycode) {
|
||||
keyReport.keys[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef RAWKEYBOARD_h
|
||||
#define RAWKEYBOARD_h
|
||||
|
||||
#if !defined(USBCON) || !defined(USBD_USE_HID_COMPOSITE)
|
||||
|
||||
#error "USB HID not enabled! Select 'HID' in the 'Tools->USB interface' menu."
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define KEY_REPORT_KEYS_COUNT 6
|
||||
|
||||
typedef struct {
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keys[6];
|
||||
} KeyReport;
|
||||
|
||||
|
||||
class RawKeyboard {
|
||||
private:
|
||||
RawKeyboard();
|
||||
KeyReport keyReport;
|
||||
void updateKeyInReport(uint8_t hid_keycode, bool released);
|
||||
bool addKeyToReport(uint8_t hid_keycode);
|
||||
void removeKeyFromReport(uint8_t hid_keycode);
|
||||
public:
|
||||
void begin();
|
||||
void end();
|
||||
void setKeysFromADBRegister(uint16_t);
|
||||
void setModifiersFromADBRegister(uint16_t);
|
||||
void sendReport();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
#define private public
|
||||
#pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
|
||||
#include <unity.h>
|
||||
#include "raw_keyboard.h"
|
||||
|
||||
// void setUp(void) {
|
||||
// // set stuff up here
|
||||
// }
|
||||
|
||||
// void tearDown(void) {
|
||||
// // clean stuff up here
|
||||
// }
|
||||
|
||||
void test_keyReport_empty(void) {
|
||||
RawKeyboard k;
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[i]);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.reserved);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.modifiers);
|
||||
}
|
||||
|
||||
void test_addKeyToReport(void) {
|
||||
RawKeyboard k;
|
||||
|
||||
TEST_ASSERT_TRUE(k.addKeyToReport(1));
|
||||
TEST_ASSERT_TRUE(k.addKeyToReport(2));
|
||||
TEST_ASSERT_TRUE(k.addKeyToReport(3));
|
||||
TEST_ASSERT_TRUE(k.addKeyToReport(2));
|
||||
|
||||
TEST_ASSERT_EQUAL(1, k.keyReport.keys[0]);
|
||||
TEST_ASSERT_EQUAL(2, k.keyReport.keys[1]);
|
||||
TEST_ASSERT_EQUAL(3, k.keyReport.keys[2]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[3]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[4]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[5]);
|
||||
}
|
||||
|
||||
void test_removeKeyFromReport(void) {
|
||||
RawKeyboard k;
|
||||
|
||||
uint8_t initial_keys[] = {7, 8, 9, 0, 0, 0};
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
k.keyReport.keys[i] = initial_keys[i];
|
||||
}
|
||||
|
||||
k.removeKeyFromReport(7);
|
||||
k.removeKeyFromReport(9);
|
||||
k.removeKeyFromReport(7);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[0]);
|
||||
TEST_ASSERT_EQUAL(8, k.keyReport.keys[1]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[2]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[3]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[4]);
|
||||
TEST_ASSERT_EQUAL(0, k.keyReport.keys[5]);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_keyReport_empty);
|
||||
RUN_TEST(test_addKeyToReport);
|
||||
RUN_TEST(test_removeKeyFromReport);
|
||||
UNITY_END();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#define private public
|
||||
#pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
|
||||
#include <unity.h>
|
||||
#include "adb_devices.h"
|
||||
#include "hid_keyboard.h"
|
||||
|
||||
// void setUp(void) {
|
||||
// // set stuff up here
|
||||
// }
|
||||
|
||||
// void tearDown(void) {
|
||||
// // clean stuff up here
|
||||
// }
|
||||
|
||||
void test_key_report_empty(void) {
|
||||
hid_key_report k = {0};
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
TEST_ASSERT_EQUAL(0, k.keys[i]);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, k.modifiers);
|
||||
}
|
||||
|
||||
void test_hid_keyboard_add_key_to_report(void) {
|
||||
hid_key_report k = {0};
|
||||
|
||||
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 1));
|
||||
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 2));
|
||||
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 3));
|
||||
TEST_ASSERT_TRUE(hid_keyboard_add_key_to_report(&k, 2));
|
||||
|
||||
TEST_ASSERT_EQUAL(1, k.keys[0]);
|
||||
TEST_ASSERT_EQUAL(2, k.keys[1]);
|
||||
TEST_ASSERT_EQUAL(3, k.keys[2]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[3]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[4]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[5]);
|
||||
}
|
||||
|
||||
void test_hid_keyboard_remove_key_from_report(void) {
|
||||
hid_key_report k = {0};
|
||||
|
||||
uint8_t initial_keys[] = {7, 8, 9, 0, 0, 0};
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
k.keys[i] = initial_keys[i];
|
||||
}
|
||||
|
||||
hid_keyboard_remove_key_from_report(&k, 7);
|
||||
hid_keyboard_remove_key_from_report(&k, 9);
|
||||
hid_keyboard_remove_key_from_report(&k, 7);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, k.keys[0]);
|
||||
TEST_ASSERT_EQUAL(8, k.keys[1]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[2]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[3]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[4]);
|
||||
TEST_ASSERT_EQUAL(0, k.keys[5]);
|
||||
}
|
||||
|
||||
void test_adb_kb_keypress(void) {
|
||||
uint8_t kp_bin[2] = {0b10000001, 0b00001011};
|
||||
|
||||
adb_kb_keypress kp_stru;
|
||||
kp_stru.released0 = true;
|
||||
kp_stru.key0 = 1;
|
||||
kp_stru.released1 = false;
|
||||
kp_stru.key1 = 11;
|
||||
|
||||
uint16_t kp_stru_bin = *((uint16_t*)&kp_stru);
|
||||
|
||||
TEST_ASSERT_EQUAL(kp_bin, kp_stru_bin);
|
||||
}
|
||||
|
||||
void test_adb_kb_modifiers() {
|
||||
uint8_t mod_bin[2] = {0b00110101, 0b11000010};
|
||||
adb_kb_modifiers mod_stru = *((adb_kb_modifiers*)&mod_bin);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.reserved0);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.backspace);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.caps_lock);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.reset);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.control);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.shift);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.option);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.command);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.num_lock);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.scroll_lock);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.reserved1);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.led_scroll);
|
||||
TEST_ASSERT_EQUAL(1, mod_stru.led_caps);
|
||||
TEST_ASSERT_EQUAL(0, mod_stru.led_num);
|
||||
}
|
||||
|
||||
void test_adb_command() {
|
||||
uint8_t cmd_bin = 0b01101001;
|
||||
adb_command cmd_stru = *((adb_command*)&cmd_bin);
|
||||
|
||||
TEST_ASSERT_EQUAL(6, cmd_stru.addr);
|
||||
TEST_ASSERT_EQUAL(2, cmd_stru.cmd);
|
||||
TEST_ASSERT_EQUAL(1, cmd_stru.reg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_key_report_empty);
|
||||
RUN_TEST(test_hid_keyboard_add_key_to_report);
|
||||
RUN_TEST(test_hid_keyboard_remove_key_from_report);
|
||||
|
||||
RUN_TEST(test_adb_kb_keypress);
|
||||
RUN_TEST(test_adb_kb_modifiers);
|
||||
RUN_TEST(test_adb_command);
|
||||
UNITY_END();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user