Skip to content

Instantly share code, notes, and snippets.

@bryanjhv
Created July 30, 2019 23:52
Show Gist options
  • Save bryanjhv/2a9a5936fe82b2bdd4090b86ce52cbb6 to your computer and use it in GitHub Desktop.
Save bryanjhv/2a9a5936fe82b2bdd4090b86ce52cbb6 to your computer and use it in GitHub Desktop.
/*
* Based on Obdev's AVRUSB code and under the same license.
*
* TODO: Make a proper file header. :-)
* Modified for Digispark by Digistump
*/
#ifndef __DigiKeyboard_h__
#define __DigiKeyboard_h__
#include <Arduino.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <string.h>
#include "usbdrv.h"
// TODO: Work around Arduino 12 issues better.
//#include <WConstants.h>
//#undef int()
typedef uint8_t byte;
#define BUFFER_SIZE 2 // Minimum of 2: 1 for modifiers + 1 for keystroke
static uchar idleRate; // in 4 ms units
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and but we do allow
* simultaneous key presses.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
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)
0x95, 0x01, // REPORT_COUNT (simultaneous keystrokes)
0x75, 0x08, // REPORT_SIZE (8)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
* 10 Keyboard/Keypad Page for more codes.
*/
#define MOD_CONTROL_LEFT (1<<0)
#define MOD_SHIFT_LEFT (1<<1)
#define MOD_ALT_LEFT (1<<2)
#define MOD_GUI_LEFT (1<<3)
#define MOD_CONTROL_RIGHT (1<<4)
#define MOD_SHIFT_RIGHT (1<<5)
#define MOD_ALT_RIGHT (1<<6)
#define MOD_GUI_RIGHT (1<<7)
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_ENTER 40
#define KEY_SPACE 44
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
#define KEY_ARROW_LEFT 0x50
#include "scancode-ascii-table2.h"
class DigiKeyboardDevice : public Print {
public:
DigiKeyboardDevice () {
cli();
usbDeviceDisconnect();
_delay_ms(250);
usbDeviceConnect();
usbInit();
sei();
// TODO: Remove the next two lines once we fix
// missing first keystroke bug properly.
memset(reportBuffer, 0, sizeof(reportBuffer));
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
void update() {
usbPoll();
}
// delay while updating until we are finished delaying
void delay(long milli) {
unsigned long last = millis();
while (milli > 0) {
unsigned long now = millis();
milli -= now - last;
last = now;
update();
}
}
//sendKeyStroke: sends a key press AND release
void sendKeyStroke(byte keyStroke) {
sendKeyStroke(keyStroke, 0);
}
//sendKeyStroke: sends a key press AND release with modifiers
void sendKeyStroke(byte keyStroke, byte modifiers) {
sendKeyPress(keyStroke, modifiers);
// This stops endlessly repeating keystrokes:
sendKeyPress(0,0);
}
//sendKeyPress: sends a key press only - no release
//to release the key, send again with keyPress=0
void sendKeyPress(byte keyPress) {
sendKeyPress(keyPress, 0);
}
//sendKeyPress: sends a key press only, with modifiers - no release
//to release the key, send again with keyPress=0
void sendKeyPress(byte keyPress, byte modifiers) {
while (!usbInterruptIsReady()) {
// Note: We wait until we can send keyPress
// so we know the previous keyPress was
// sent.
usbPoll();
_delay_ms(5);
}
memset(reportBuffer, 0, sizeof(reportBuffer));
reportBuffer[0] = modifiers;
reportBuffer[1] = keyPress;
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
size_t write(uint8_t chr) {
if (chr == '<') {
sendKeyStroke(0x64);
} else if (chr == '>') {
sendKeyStroke(0x64, MOD_SHIFT_RIGHT);
} else {
uint8_t data = pgm_read_byte_near(ascii_to_scan_code_table + (chr - 8));
sendKeyStroke(data & 0b00111111, data >> 7 ? MOD_SHIFT_RIGHT : 0 | (data << 1) >> 7 ? MOD_ALT_RIGHT : 0);
if (chr == '^' || chr == '`') {
sendKeyStroke(0x2c);
}
}
return 1;
}
//private: TODO: Make friend?
uchar reportBuffer[2]; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
using Print::write;
};
DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();
#ifdef __cplusplus
extern "C"{
#endif
// USB_PUBLIC uchar usbFunctionSetup
uchar usbFunctionSetup(uchar data[8]) {
usbRequest_t *rq = (usbRequest_t *)((void *)data);
usbMsgPtr = DigiKeyboard.reportBuffer; //
if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
/* class request type */
if (rq->bRequest == USBRQ_HID_GET_REPORT) {
/* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* we only have one report type, so don't look at wValue */
// TODO: Ensure it's okay not to return anything here?
return 0;
} else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
//usbMsgPtr = &idleRate;
//return 1;
return 0;
} else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
idleRate = rq->wValue.bytes[1];
}
} else {
/* no vendor specific requests implemented */
}
return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __DigiKeyboard_h__
#include <avr/pgmspace.h>
// Lookup table to convert ascii characters in to keyboard scan codes
// Format: most signifficant bit indicates if scan code should be sent with shift modifier
// remaining 7 bits are to be used as scan code number.
#define SHIFT 0x80
#define ALTGR 0x40
const unsigned char ascii_to_scan_code_table[] PROGMEM = {
0x2a, // BS (backspace)
0x2b, // TAB (horizontal tab)
KEY_ENTER, // LF (NL line feed, new line)
0x00, // VT (vertical tab)
0x00, // FF (NP form feed, new page)
0x00, // CR (carriage return)
0x00, // SO (shift out)
0x00, // SI (shift in)
0x00, // DLE (data link escape)
0x00, // DC1 (device control 1)
0x00, // DC2 (device control 2)
0x00, // DC3 (device control 3)
0x00, // DC4 (device control 4)
0x00, // NAK (negative acknowledge)
0x00, // SYN (synchronous idle)
0x00, // ETB (end of trans. block)
0x00, // CAN (cancel)
0x00, // EM (end of medium)
0x00, // SUB (substitute)
0x29, // ESC (escape)
0x00, // FS (file separator)
0x00, // GS (group separator)
0x00, // RS (record separator)
0x00, // US (unit separator)
#ifdef kbd_en_us
KEY_SPACE, // Space
KEY_1|SHIFT, // !
0x34|SHIFT, // "
KEY_3|SHIFT, // #
KEY_4|SHIFT, // $
KEY_5|SHIFT, // %
KEY_7|SHIFT, // &
0x34, // '
KEY_9|SHIFT, // (
KEY_0|SHIFT, // )
KEY_8|SHIFT, // *
0x2e|SHIFT, // +
0x36, // ,
0x2d, // -
0x37, // .
0x38, // /
KEY_0, // 0
KEY_1, // 1
KEY_2, // 2
KEY_3, // 3
KEY_4, // 4
KEY_5, // 5
KEY_6, // 6
KEY_7, // 7
KEY_8, // 8
KEY_9, // 9
0x33|SHIFT, // :
0x33, // ;
0x36|SHIFT, // <
0x2e, // =
0x37|SHIFT, // >
0x38|SHIFT, // ?
KEY_2|SHIFT, // @
KEY_A|SHIFT, // A
KEY_B|SHIFT, // B
KEY_C|SHIFT, // C
KEY_D|SHIFT, // D
KEY_E|SHIFT, // E
KEY_F|SHIFT, // F
KEY_G|SHIFT, // G
KEY_H|SHIFT, // H
KEY_I|SHIFT, // I
KEY_J|SHIFT, // J
KEY_K|SHIFT, // K
KEY_L|SHIFT, // L
KEY_M|SHIFT, // M
KEY_N|SHIFT, // N
KEY_O|SHIFT, // O
KEY_P|SHIFT, // P
KEY_Q|SHIFT, // Q
KEY_R|SHIFT, // R
KEY_S|SHIFT, // S
KEY_T|SHIFT, // T
KEY_U|SHIFT, // U
KEY_V|SHIFT, // V
KEY_W|SHIFT, // W
KEY_X|SHIFT, // X
KEY_Y|SHIFT, // Y
KEY_Z|SHIFT, // Z
0x2f, // [
0x31, // Backslash
0x30, // ]
KEY_6|SHIFT, // ^
0x2d|SHIFT, // _
0x35, // `
KEY_A, // a
KEY_B, // b
KEY_C, // c
KEY_D, // d
KEY_E, // e
KEY_F, // f
KEY_G, // g
KEY_H, // h
KEY_I, // i
KEY_J, // j
KEY_K, // k
KEY_L, // l
KEY_M, // m
KEY_N, // n
KEY_O, // o
KEY_P, // p
KEY_Q, // q
KEY_R, // r
KEY_S, // s
KEY_T, // t
KEY_U, // u
KEY_V, // v
KEY_W, // w
KEY_X, // x
KEY_Y, // y
KEY_Z, // z
0x2f|SHIFT, // {
0x31|SHIFT, // |
0x30|SHIFT, // }
0x35|SHIFT, // ~
#endif
#ifdef kbd_es_es
KEY_SPACE, // Space
KEY_1|SHIFT, // !
KEY_2|SHIFT, // "
KEY_3|ALTGR, // #
KEY_4|SHIFT, // $
KEY_5|SHIFT, // %
KEY_6|SHIFT, // &
0x2d, // '
KEY_8|SHIFT, // (
KEY_9|SHIFT, // )
0x30|SHIFT, // *
0x30, // +
0x36, // ,
0x38, // -
0x37, // .
KEY_7|SHIFT, // /
KEY_0, // 0
KEY_1, // 1
KEY_2, // 2
KEY_3, // 3
KEY_4, // 4
KEY_5, // 5
KEY_6, // 6
KEY_7, // 7
KEY_8, // 8
KEY_9, // 9
0x37|SHIFT, // :
0x36|SHIFT, // ;
0x03, // < KEY100
KEY_0|SHIFT, // =
0x03|SHIFT, // > KEY100|SHIFT
0x2d|SHIFT, // ?
KEY_2|ALTGR, // @
KEY_A|SHIFT, // A
KEY_B|SHIFT, // B
KEY_C|SHIFT, // C
KEY_D|SHIFT, // D
KEY_E|SHIFT, // E
KEY_F|SHIFT, // F
KEY_G|SHIFT, // G
KEY_H|SHIFT, // H
KEY_I|SHIFT, // I
KEY_J|SHIFT, // J
KEY_K|SHIFT, // K
KEY_L|SHIFT, // L
KEY_M|SHIFT, // M
KEY_N|SHIFT, // N
KEY_O|SHIFT, // O
KEY_P|SHIFT, // P
KEY_Q|SHIFT, // Q
KEY_R|SHIFT, // R
KEY_S|SHIFT, // S
KEY_T|SHIFT, // T
KEY_U|SHIFT, // U
KEY_V|SHIFT, // V
KEY_W|SHIFT, // W
KEY_X|SHIFT, // X
KEY_Y|SHIFT, // Y
KEY_Z|SHIFT, // Z
0x2f|ALTGR, // [
0x35|ALTGR, // Backslash
0x30|ALTGR, // ]
0x2f|SHIFT, // ^ KEY+SPACE
0x38|SHIFT, // _
0x2f, // ` KEY+SPACE
KEY_A, // a
KEY_B, // b
KEY_C, // c
KEY_D, // d
KEY_E, // e
KEY_F, // f
KEY_G, // g
KEY_H, // h
KEY_I, // i
KEY_J, // j
KEY_K, // k
KEY_L, // l
KEY_M, // m
KEY_N, // n
KEY_O, // o
KEY_P, // p
KEY_Q, // q
KEY_R, // r
KEY_S, // s
KEY_T, // t
KEY_U, // u
KEY_V, // v
KEY_W, // w
KEY_X, // x
KEY_Y, // y
KEY_Z, // z
0x34|ALTGR, // {
KEY_1|ALTGR, // |
0x32|ALTGR, // }
KEY_4|ALTGR, // ~
#endif
};
@korenevskiy
Copy link

korenevskiy commented May 30, 2023

Please Add support hotkey BIOS https://github.com/bkgarry/DigikeyboardBIOS

@korenevskiy
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment