| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 | //
// Created by robin on 1/8/16.
//
UsbKeyboardDevice UsbKeyboard = UsbKeyboardDevice("us");
/* 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.
 */
PROGMEM const char usbHidReportDescriptor[35] = { /* 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, BUFFER_SIZE-1,           //   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
};
UsbKeyboardDevice::UsbKeyboardDevice(const char* layout)
    : _layout(0)
{
    PORTD = 0; // TODO: Only for USB pins?
    DDRD |= ~USBMASK;
    cli();
    usbDeviceDisconnect();
    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));
    setLayout(layout);
}
bool UsbKeyboardDevice::isUsbReady()
{
    UsbKeyboard.update();
    return usbInterruptIsReady();
}
void UsbKeyboardDevice::setLayout(const char* layout)
{
    delete _layout;
    _layout = new char[strlen(layout)];
    strcpy(_layout, layout);
}
int UsbKeyboardDevice::charModAltGr(char c, int* modifier)
{
    *modifier = MOD_ALT_RIGHT;
    return c;
}
int UsbKeyboardDevice::charModShift(char c, int* modifier)
{
    *modifier = MOD_SHIFT_LEFT;
    return c;
}
#ifdef ARD_USBKBD_AZERTY
int UsbKeyboardDevice::charToKeyAzerty(int c, int* modifier)
{
    *modifier = 0;
    if (c == '0')
        return charModShift(KEY_0, modifier);
    if (c >= '1' && c <= '9')
        return charModShift(KEY_1 + c - '1', modifier);
    if (c == '\n')
        return KEY_ENTER;
    if (c == ' ')
        return KEY_SPACE;
    if (c >= 'a' && c <= 'z')
    {
        if (c == 'a')
            c = 'q';
        else if (c == 'm')
            return KEY_SEMICOLON;
        else if (c == 'q')
            c = 'a';
        else if (c == 'w')
            c = 'z';
        else if (c == 'z')
            c = 'w';
        return KEY_A + c - 'a';
    }
    if (c >= 'A' && c <= 'Z')
    {
        if (c == 'A')
            c = 'Q';
        else if (c == 'M')
            return charModShift(KEY_SEMICOLON, modifier);
        else if (c == 'Q')
            c = 'A';
        else if (c == 'W')
            c = 'Z';
        else if (c == 'Z')
            c = 'W';
        return charModShift(KEY_A + c - 'A', modifier);
    }
    if (c == '~')
        return charModAltGr(KEY_2, modifier);
    if (c == '#')
        return charModAltGr(KEY_3, modifier);
    if (c == '{')
        return charModAltGr(KEY_4, modifier);
    if (c == '[')
        return charModAltGr(KEY_5, modifier);
    if (c == '|')
        return charModAltGr(KEY_6, modifier);
    if (c == '`')
        return charModAltGr(KEY_7, modifier);
    if (c == '\\')
        return charModAltGr(KEY_8, modifier);
    if (c == '^')
        return charModAltGr(KEY_9, modifier);
    if (c == '@')
        return charModAltGr(KEY_0, modifier);
    if (c == ']')
        return charModAltGr(KEY_HYPHEN, modifier);
    if (c == '}')
        return charModAltGr(KEY_EQUAL, modifier);
    if (c == -75)//µ
        return charModShift(KEY_BSLASH, modifier);
    if (c == '*')
        return KEY_BSLASH;
    if (c == '&')
        return KEY_1;
    if (c == -23)//é
        return KEY_2;
    if (c == '\"')
        return KEY_3;
    if (c == '\'')
        return KEY_4;
    if (c == '(')
        return KEY_5;
    if (c == '-')
        return KEY_6;
    if (c == -24)//è
        return KEY_7;
    if (c == '_')
        return KEY_8;
    if (c == -25)//ç
        return KEY_9;
    if (c == -32)//à
        return KEY_0;
    if (c == ')')
        return KEY_HYPHEN;
    if (c == '=')
        return KEY_EQUAL;
    if (c == '+')
        return charModShift(KEY_EQUAL, modifier);
    if (c == ',')
        return KEY_M;
    if (c == ';')
        return KEY_COMMA;
    if (c == ':')
        return KEY_DOT;
    if (c == '!')
        return KEY_SLASH;
    if (c == -7)//ù
        return KEY_QUOTE;
    if (c == '<')
        return KEYP_NUS_BSLASH;
    if (c == '?')
        return charModShift(KEY_M, modifier);
    if (c == '.')
        return charModShift(KEY_COMMA, modifier);
    if (c == '/')
        return charModShift(KEY_DOT, modifier);
    if (c == -89)//§
        return charModShift(KEY_SLASH, modifier);
    if (c == '%')
        return charModShift(KEY_QUOTE, modifier);
    if (c == '>')
        return charModShift(KEYP_NUS_BSLASH, modifier);
    return 0;
}
#endif
#ifdef ARD_USBKBD_QWERTY
int UsbKeyboardDevice::charToKeyQwerty(int c, int* modifier)
{
    *modifier = 0;
    if (c == '0')
        return KEY_0;
    if (c >= '1' && c <= '9')
        return KEY_1 + c - '1';
    if (c >= 'a' && c <= 'z')
        return KEY_A + c - 'a';
    if (c >= 'A' && c <= 'Z')
        return charModShift(KEY_A + c - 'A', modifier);
    if (c == '\n')
        return KEY_ENTER;
    if (c == ' ')
        return KEY_SPACE;
    if (c == '.')
        return KEY_DOT;
    if (c == ',')
        return KEY_COMMA;
    if (c == '/')
        return KEY_SLASH;
    if (c == ';')
        return KEY_SEMICOLON;
    if (c == '`')
        return KEY_TILDE;
    if (c == '-')
        return KEY_HYPHEN;
    if (c == '=')
        return KEY_EQUAL;
    if (c == '\'')
        return KEY_QUOTE;
    if (c == '~')
        return charModShift(KEY_TILDE, modifier);
    if (c == '<')
        return charModShift(KEY_COMMA, modifier);
    if (c == '>')
        return charModShift(KEY_DOT, modifier);
    if (c == '?')
        return charModShift(KEY_SLASH, modifier);
    if (c == ':')
        return charModShift(KEY_SEMICOLON, modifier);
    if (c == '!')
        return charModShift(KEY_1, modifier);
    if (c == '@')
        return charModShift(KEY_2, modifier);
    if (c == '#')
        return charModShift(KEY_3, modifier);
    if (c == '$')
        return charModShift(KEY_4, modifier);
    if (c == '%')
        return charModShift(KEY_5, modifier);
    if (c == '^')
        return charModShift(KEY_6, modifier);
    if (c == '&')
        return charModShift(KEY_7, modifier);
    if (c == '*')
        return charModShift(KEY_8, modifier);
    if (c == '(')
        return charModShift(KEY_9, modifier);
    if (c == ')')
        return charModShift(KEY_0, modifier);
    if (c == '_')
        return charModShift(KEY_HYPHEN, modifier);
    if (c == '+')
        return charModShift(KEY_EQUAL, modifier);
    if (c == '"')
        return charModShift(KEY_QUOTE, modifier);
    if (c == '{')
        return charModShift(KEY_LBRACKET, modifier);
    if (c == '}')
        return charModShift(KEY_RBRACKET, modifier);
    if (c == '|')
        return charModShift(KEY_BSLASH, modifier);
    if (c == '[')
        return KEY_LBRACKET;
    if (c == ']')
        return KEY_RBRACKET;
    if (c == '\\')
        return KEY_BSLASH;
    return 0;
}
#endif
void UsbKeyboardDevice::sendKeyStrokes(const char* str)
{
    int (*charToKey)(int,int*) = 0;
#ifdef ARD_USBKBD_AZERTY
    if (!strcmp(_layout, "fr"))
    {
        charToKey = charToKeyAzerty;
    }
#endif
#ifdef ARD_USBKBD_QWERTY
    if (!strcmp(_layout, "us"))
    {
        charToKey = charToKeyQwerty;
    }
#endif
    if (!charToKey)
    {
        return;
    }
    while (*str)
    {
        int modifier = 0;
        int k = charToKey(*str, &modifier);
        /*if (!k)
        {
          k = KEY_SPACE;
          char buf[12];
          itoa((unsigned)*str, buf, 10);
          sendKeyStrokes(buf);
        }*/
        if (k)
        {
            UsbKeyboard.sendKeyStroke(k, modifier);
        }
        ++str;
    }
}
void UsbKeyboardDevice::sendKeyStroke(byte keyStroke, byte modifiers)
{
    while (!usbInterruptIsReady()) {
        // Note: We wait until we can send keystroke
        //       so we know the previous keystroke was
        //       sent.
    }
    memset(reportBuffer, 0, sizeof(reportBuffer));
    reportBuffer[0] = modifiers;
    reportBuffer[1] = keyStroke;
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
    while (!usbInterruptIsReady()) {
        // Note: We wait until we can send keystroke
        //       so we know the previous keystroke was
        //       sent.
    }
    // This stops endlessly repeating keystrokes:
    memset(reportBuffer, 0, sizeof(reportBuffer));
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
uchar usbFunctionSetup(uchar data[8])
{
    usbRequest_t    *rq = (usbRequest_t *)((void *)data);
    usbMsgPtr = UsbKeyboard.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;
}
 |