/* 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 #include #include /* 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; } } }