From f27d75ea35f025f16368c1ae25cbab8ddcb26692 Mon Sep 17 00:00:00 2001 From: Bruce Barnett Date: Sun, 10 Jul 2022 10:36:49 -0400 Subject: [PATCH] Added support for Control characters and the characters and "<>{}[]^&%=\" --- LINUX.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++ app/Makefile | 6 +++++ app/keyboard.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++--- app/keyboard.h | 26 +++++++++--------- app/usb.c | 19 +++++++++++--- 5 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 LINUX.md create mode 100644 app/Makefile diff --git a/LINUX.md b/LINUX.md new file mode 100644 index 0000000..c99632a --- /dev/null +++ b/LINUX.md @@ -0,0 +1,67 @@ +# I2C Puppet mods for Linux systems + +The original version lacked certain characters, such as , and the characters "<>{}[]^&%=\" +which made it difficult to use on Linux systems + + +This version of the firmware has been modified to support Linux systems. +The following changes have been made + 1) The backspace key works during the GUI login + 2) The Sym key not acts as a Control key, so SYM+C is Control-C + 3) The four top button keys are now used to provide the missing characters. + +The original definiton of the keys were this + + L1 L2 R1 R2 SPKR Mic BS NL SPACE + $ ~ \b \n +Shift +Alt 0 +Sym | TAB + + + +The current definition of the keys are + + L1 L2 R1 R2 SPKR Mic BS NL Spacebar + % = \ $ ~ BS \n +Alt > ] } & ` ~ x +Shift < [ { ^ $ ` BS +Sym x x x x $ ~ BS | + + +#Linux Debug tips + +The keyboard was two "outputs" - one is the USB HID interface, the other is the serial port. +Any printf() command goes to the serial port. + +When the keyboard is plugged into a Linux system, a new TTY interface will appear. I usually use "ls -lt /dev/tty* | head" +to learn the name, as the newest port will appear first. On my system, it's /dev/ttyACM0 + +So on one terminal, I type + +cat -v /ic2_puppet/all/ using my preferred editor. In my case, I use emacs. I have the keystroke combination "Control-C M" bound to compile, using + +(global-set-key "\C-cm" 'compile) + +And when I press these keys, emacs saves all files, and recompiles the +code. I have a small hub with switchable on/off ports, and restart the +keyboard into boot mode, and then do a "make install" to load the new +firmware + + +#TODO + +Currently - the SYM+Button keys are defined as the character "x" to indicate it's not been specified. +I'l like to make these keys to the 4 arrow keys. + +Also - it might be possible to create key combinations by combining the modified keys, like SYM+Alt+key diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..f9d68df --- /dev/null +++ b/app/Makefile @@ -0,0 +1,6 @@ +# Make it useful for Linux +all: keyboard.c keyboard.h usb.c + cd ../build;make +install: ../build/app/i2c_puppet.uf2 + cp ../build/app/i2c_puppet.uf2 /media/${USER}/RPI-RP2 + diff --git a/app/keyboard.c b/app/keyboard.c index 5b624cc..1fc3470 100644 --- a/app/keyboard.c +++ b/app/keyboard.c @@ -2,6 +2,7 @@ #include "fifo.h" #include "keyboard.h" #include "reg.h" +#include // BGB #include @@ -114,12 +115,76 @@ static void transition_to(struct list_item * const p_item, const enum key_state if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) { const bool shift = (self.mods[KEY_MOD_ID_SHL] || self.mods[KEY_MOD_ID_SHR]) | self.capslock; const bool alt = self.mods[KEY_MOD_ID_ALT] | self.numlock; - const bool is_button = (key <= KEY_BTN_RIGHT1) || ((key >= KEY_BTN_LEFT2) && (key <= KEY_BTN_RIGHT2)); +// const bool is_button = (key <= KEY_BTN_RIGHT1) || ((key >= KEY_BTN_LEFT2) && (key <= KEY_BTN_RIGHT2)); + const bool is_button = ((key == KEY_BTN_RIGHT1) + || (key == KEY_BTN_RIGHT2) + || (key == KEY_BTN_LEFT1) + || (key == KEY_BTN_LEFT2)); + const bool control = self.mods[KEY_MOD_ID_SYM]; + - if (alt && !is_button) { + if (is_button) { + switch (key) { + case KEY_BTN_LEFT1: + if (alt) { + key = '>'; + } else if (shift) { + key = '<'; + } else if (control) { + key = 'x'; + } else { + key =0x1B; // ESC + } + break; + case KEY_BTN_LEFT2: + if (alt) { + key = ']'; + } else if (shift) { + key = '['; + } else if (control) { + key ='x'; + } else { + key = '%'; + } + break; + case KEY_BTN_RIGHT1: + if (alt) { + key = '}'; + } else if (shift) { + key = '{'; + } else if (control) { + key = 'x'; + } else { + key = '='; + } + break; + case KEY_BTN_RIGHT2: + if (alt) { + key = '&'; + } else if (shift) { + key = '^'; + } else if (control) { + key = 'x'; // TODO + } else { + key = '\\'; + } + break; + default: + // printf(" ERROR: Illegal key: %d\n", key); + ; + } + } else if (alt) { + printf(" alt \n"); key = p_entry->alt; - } else if (!shift && (key >= 'A' && key <= 'Z')) { + } else if (key >= 'A' && key <= 'Z') { + printf(" letter\n"); + if (control) { // If the SYM key is held down, it's a control key + key = key - 0x40; + } else if (!shift) { // lower case letter key = (key + ' '); + } else { + // it's an uppercase letter - do nothing + } } } diff --git a/app/keyboard.h b/app/keyboard.h index fbe9531..d13e4ca 100644 --- a/app/keyboard.h +++ b/app/keyboard.h @@ -22,24 +22,24 @@ enum key_mod KEY_MOD_ID_LAST, }; -#define KEY_JOY_UP 0x01 -#define KEY_JOY_DOWN 0x02 -#define KEY_JOY_LEFT 0x03 -#define KEY_JOY_RIGHT 0x04 -#define KEY_JOY_CENTER 0x05 -#define KEY_BTN_LEFT1 0x06 -#define KEY_BTN_RIGHT1 0x07 +#define KEY_JOY_UP 0x81 +#define KEY_JOY_DOWN 0x82 +#define KEY_JOY_LEFT 0x83 +#define KEY_JOY_RIGHT 0x84 +#define KEY_JOY_CENTER 0x85 +#define KEY_BTN_LEFT1 0x86 +#define KEY_BTN_RIGHT1 0x87 // 0x08 - BACKSPACE // 0x09 - TAB // 0x0A - NEW LINE // 0x0D - CARRIAGE RETURN -#define KEY_BTN_LEFT2 0x11 -#define KEY_BTN_RIGHT2 0x12 +#define KEY_BTN_LEFT2 0x91 +#define KEY_BTN_RIGHT2 0x92 -#define KEY_MOD_ALT 0x1A -#define KEY_MOD_SHL 0x1B // Left Shift -#define KEY_MOD_SHR 0x1C // Right Shift -#define KEY_MOD_SYM 0x1D +#define KEY_MOD_ALT 0x9A +#define KEY_MOD_SHL 0x9B // Left Shift +#define KEY_MOD_SHR 0x9C // Right Shift +#define KEY_MOD_SYM 0x9D struct key_callback { diff --git a/app/usb.c b/app/usb.c index 25cf769..ff30e2c 100644 --- a/app/usb.c +++ b/app/usb.c @@ -55,8 +55,10 @@ static void key_cb(char key, enum key_state state) return; if (tud_hid_n_ready(USB_ITF_KEYBOARD) && reg_is_bit_set(REG_ID_CF2, CF2_USB_KEYB_ON)) { - uint8_t conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; + // conv_table needs to be 256 entries long because the special keys are in range 128-256 (0x80 - 0xFF) + uint8_t conv_table[256][2] = { HID_ASCII_TO_KEYCODE }; conv_table['\n'][1] = HID_KEY_ENTER; // Fixup: Enter instead of Return + conv_table['\b'][1] = HID_KEY_BACKSPACE; // Fixup: HID backspace (0x2A) instead of \b (0x08) conv_table[KEY_JOY_UP][1] = HID_KEY_ARROW_UP; conv_table[KEY_JOY_DOWN][1] = HID_KEY_ARROW_DOWN; conv_table[KEY_JOY_LEFT][1] = HID_KEY_ARROW_LEFT; @@ -66,10 +68,21 @@ static void key_cb(char key, enum key_state state) uint8_t modifier = 0; if (state == KEY_STATE_PRESSED) { - if (conv_table[(int)key][0]) + printf(" conv_table[%d][0,1]=%d,%d ",key, conv_table[(int)key][0], conv_table[(int)key][1]); // bgb + if (conv_table[(int)key][0]) { modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + } else if (key < 0x20) { // it's a control key + if ((key == '\n') || (key == '\b')) { + // leave alone - this is necessary because the Linux graphical login processes the HID equivalent + // which is done using conv_table[] below + } else { + // convert control key, i.e. [Control-A] converts to [modifier=control, key=A] + modifier=KEYBOARD_MODIFIER_RIGHTCTRL; + key=key + 0x40; + } - keycode[0] = conv_table[(int)key][1]; + } + keycode[0] = conv_table[(int)key][1]; } if (state != KEY_STATE_HOLD)