arduino_hid_keyboard/keymapper.ino
2016-07-07 23:24:45 -04:00

372 lines
9.7 KiB
C++

/* Arduino Keyboard HID driver and USB host shield pass through */
/*
* Copyright (c) 2011 Darran Hunt (darran [at] hunt dot net dot nz)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <SPI.h>
#include <Max3421e.h>
#include <Usb.h>
/* keyboard data taken from configuration descriptor */
#define KBD_ADDR 1
#define KBD_EP 1
#define KBD_IF 0
#define EP_MAXPKTSIZE 8
#define EP_POLL 0x0a
/* Sticky keys */
/*#define CAPSLOCK 0x39*/ // Is going to be considered ESC
#define NUMLOCK 0x53
#define SCROLLLOCK 0x47
/* Sticky keys output report bitmasks */
#define REP_NUMLOCK 0x01
#define REP_CAPSLOCK 0x02
#define REP_SCROLLLOCK 0x04
EP_RECORD ep_record[2]; //endpoint record structure for the keyboard
uint8_t buf[8] = { 0 }; // keyboard buffer
uint8_t old_buf[8] = { 0 }; // last poll
/* Sticky key state */
bool numLock = false;
bool capsLock = false;
bool scrollLock = false;
void setup();
uint8_t dvorak_changer (uint8_t ch, uint8_t mod);
void loop();
bool key_is_new(byte key, byte *report);
MAX3421E Max;
USB Usb;
void setup()
{
Serial.begin(9600);
Max.powerOn();
delay(200);
digitalWrite(13, HIGH);
delay (1000);
digitalWrite (13, LOW);
}
void loop()
{
Max.Task();
Usb.Task();
if (Usb.getUsbTaskState() == USB_STATE_CONFIGURING) {
kbd_init();
Usb.setUsbTaskState( USB_STATE_RUNNING);
}
if (Usb.getUsbTaskState() == USB_STATE_RUNNING) {
kbd_poll();
}
}
/* Initialize keyboard */
void kbd_init( void )
{
byte rcode = 0; //return code
/* Initialize data structures */
ep_record[0] = *(Usb.getDevTableEntry(0,0)); //copy endpoint 0 parameters
ep_record[1].MaxPktSize = EP_MAXPKTSIZE;
ep_record[1].Interval = EP_POLL;
ep_record[1].sndToggle = bmSNDTOG0;
ep_record[1].rcvToggle = bmRCVTOG0;
Usb.setDevTableEntry(1, ep_record); //plug kbd.endpoint parameters to devtable
/* Configure device */
rcode = Usb.setConf(KBD_ADDR, 0, 1);
if (rcode) {
while(1); //stop
}
delay(2000);
}
/* Poll USB keyboard for new key presses, send through to host via
* the Keyboard HID driver in the atmega8u2
*/
void kbd_poll(void)
{
char i;
byte rcode = 0; //return code
uint8_t ledReport;
static uint8_t lastLedReport = 0;
static uint8_t leds = 0;
static uint8_t lastLeds = 0;
/* poll keyboard */
rcode = Usb.inTransfer(KBD_ADDR, KBD_EP, 8, (char *)buf);
if (rcode != 0) {
return;
}
// Serial.print ("Modifier = ");
// Serial.println (buf[0]);
/* Check for change */
for (i=0; i<8; i++) {
if (buf[i] != old_buf[i]) {
for (i = 2; i < 8; ++i) {
buf[i] = dvorak_changer (buf[i], buf[0]);
}
/* Send the new key presses to the host */
Serial.write(buf, 8);
/* Get led report */
ledReport = Serial.read();
break;
}
}
/* Check for status keys and adjust led status */
for (i=2; i<8; i++) {
if (buf[i] == 0) {
/* 0 marks end of keys in the report */
break;
}
/* Check new keys for status change keys */
/*if (key_is_new(buf[i], old_buf)) {*/
/*switch (buf[i]) {*/
/*case CAPSLOCK:*/
/*capsLock =! capsLock;*/
/*leds = capsLock ? leds |= REP_CAPSLOCK : leds &= ~REP_CAPSLOCK;*/
/*break;*/
/*case NUMLOCK:*/
/*numLock =! numLock;*/
/*leds = numLock ? leds |= REP_NUMLOCK : leds &= ~REP_NUMLOCK;*/
/*break;*/
/*case SCROLLLOCK:*/
/*scrollLock =! scrollLock;*/
/*leds = scrollLock ? leds |= REP_SCROLLLOCK : leds &= ~REP_SCROLLLOCK;*/
/*break;*/
/*default:*/
/*break;*/
/*}*/
/*//}*/
}
/* Got a change in LED status? */
if (lastLeds != leds) {
Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, (char *)&leds );
lastLeds = leds;
}
/* update the old buffer */
for (i=0; i<8; i++) {
old_buf[i] = buf[i];
}
}
/*
* Function: key_is_new(key, report)
* Description: see if key is new or is already in report
* Returns: false if found, true if not
*/
bool key_is_new(uint8_t key, uint8_t *report)
{
uint8_t ind;
for (ind=2; ind<8; ind++) {
if (report[ind] == key) {
return false;
}
}
return true;
}
/*
* Qwerty to dvorak hardware changer
* http://www.freebsddiary.org/APC/usb_hid_usages.php
* http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
*
* Modifier keys:
* LEFT:
CTRL = 1
ALT = 4
SHIFT = 2
WINKEY = 8
* RIGHT:
CTRL = 16
ALT = 64
SHIFT = 32
*
*/
uint8_t dvorak_changer (uint8_t ch, uint8_t mod)
{
if (mod != 32) { // RIGHTSHIFT as layer key
switch (ch){
/* begin mid row*/
case 0x39: // CAPSLOCK --> ESC
return 0x29;
/*case 0x04: // A --> A*/
/*return 0x04;*/
case 0x16: // S --> A
return 0x12;
case 0x07: // D --> E
return 0x08;
case 0x09: // F --> U
return 0x18;
case 0x0A: // G --> I
return 0x0C;
case 0x0B: // H --> D
return 0x07;
case 0x0D: // J --> H
return 0x0B;
case 0x0E: // K --> T
return 0x17;
case 0x0F: // L --> N
return 0x11;
case 0x033: // : --> S
return 0x016;
case 0x34: // " --> -
return 0x2D;
/* end of mid row */
/* begin of upper row */
case 0x14: // Q --> '@
if (mod == 2){
return 0x1F; // Upper case Q to @
} else {
return 0x34; // lowercase q to '
}
case 0x1A: // W --> ,<
return 0x36;
case 0x08: // E --> .>
return 0x37;
case 0x15: // R --> P
return 0x13;
case 0x17: // T --> Y
return 0x1C;
case 0x1C: // Y --> F
return 0x09;
case 0x18: // U --> G
return 0x0A;
case 0x0C: // I --> C
return 0x06;
case 0x12: // O --> R
return 0x15;
case 0x13: // P --> L
return 0x0F;
case 0x2F: // [{ --> /?
return 0x38;
case 0x30: // ]} --> =+
return 0x2E;
/* end upper row */
/* begin lower row */
case 0x2E: // += --> ]}
return 0x30;
case 0x2D: // -_ --> [{
return 0x2F;
case 0x1D: // Z --> :;
return 0x33;
case 0x1B: // X --> Q
return 0x14;
case 0x06: // C --> J
return 0x0D;
case 0x19: // V --> K
return 0x0E;
case 0x05: // B --> X
return 0x1B;
case 0x11: // N --> B
return 0x05;
/*case 0x10: // M --> M*/
/*return 0x10;*/
case 0x36: // <, --> W
return 0x1A;
case 0x37: // >. --> V
return 0x19;
case 0x38: // ?/ --> Z
return 0x1D;
/* end lower row */
/* specials */
case 0x1F: // 2@ --> 2"
if (mod == 2) {
return 0x34;
} else {
return 0x1F;
}
case 0x31: // \| --> DEL
return 0x4C;
case 0x29: // ESC --> `¬
return 0x35;
case 0x4C: // DEL --> /
return 0x31;
case 0x49: // INS --> HOME END
buf[0] = 0;
if (mod == 2) {
return 0x4D ;
} else {
return 0x4A;
}
}
} else {
buf[0] = 0;
switch (ch){
case 0x1A: // SHIFTRIGHT + , --> UpArrow
return 0x52;
case 0x16: // SHIFTRIGHT + o --> DownArrow
return 0x51;
case 0x04: // SHIFTRIGHT + a --> LeftArrow
return 0x50;
case 0x07: // SHIFTRIGHT + e --> RightArrow
return 0x4F;
case 0x2E: // += --> ]}
buf[0] = 2;
return 0x32;
case 0x2D: // -_ --> [{
buf[0] = 2;
return 0x2F;
case 0x36: // <, --> W
buf[0] = 2;
return 0x1A;
case 0x37: // >. --> V
buf[0] = 2;
return 0x19;
case 0x38: // ?/ --> Z
buf[0] = 2;
return 0x1D;
}
}
}