// Set NKRO Keyboard Protocol void Output_kbdProtocolNKRO_capability( TriggerMacro *trigger, uint8_t state, uint8_t stateType, uint8_t *args ) { #if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_kbdProtocolNKRO()"); return; } // Only set if necessary if ( USBKeys_Protocol == 1 ) return; // TODO Analog inputs // Only set on key press if ( stateType != 0x01 ) return; // Flush the key buffers Output_flushBuffers(); // Set the keyboard protocol to NKRO Mode USBKeys_Protocol = 1; #endif }
// USB Module Setup inline void Output_setup() { // Initialize the USB // If a USB connection does not exist, just ignore it // All usb related functions will non-fatally fail if called // If the USB initialization is delayed, then functionality will just be delayed usb_init(); // Register USB Output CLI dictionary CLI_registerDictionary( outputCLIDict, outputCLIDictName ); // Flush key buffers Output_flushBuffers(); }
// USB Module Setup inline void Output_setup() { // Initialize the USB, and then wait for the host to set configuration. // This will hang forever if USB does not initialize // If no USB cable is attached, does not try and initialize USB if ( usb_init() ) { while ( !usb_configured() ); } // Register USB Output CLI dictionary CLI_registerDictionary( outputCLIDict, outputCLIDictName ); // Flush key buffers Output_flushBuffers(); }
// USB Module Setup inline void Output_setup() { // Register USB Output CLI dictionary CLI_registerDictionary( outputCLIDict, outputCLIDictName ); // Flush key buffers Output_flushBuffers(); #if enableRawIO_define == 1 // Setup HID-IO HIDIO_setup(); #endif // Latency resource allocation outputPeriodicLatencyResource = Latency_add_resource("USBOutputPeri", LatencyOption_Ticks); outputPollLatencyResource = Latency_add_resource("USBOutputPoll", LatencyOption_Ticks); }
// Toggle Keyboard Protocol void Output_toggleKbdProtocol_capability( TriggerMacro *trigger, uint8_t state, uint8_t stateType, uint8_t *args ) { #if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_toggleKbdProtocol()"); return; } // Only toggle protocol if release state if ( stateType == 0x00 && state == 0x03 ) { // Flush the key buffers Output_flushBuffers(); // Toggle the keyboard protocol Mode USBKeys_Protocol = !USBKeys_Protocol; } #endif }
// Set Boot Keyboard Protocol void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_kbdProtocolBoot()"); return; } // Only set if necessary if ( USBKeys_Protocol == 0 ) return; // TODO Analog inputs // Only set on key press if ( stateType != 0x01 ) return; // Flush the key buffers Output_flushBuffers(); // Set the keyboard protocol to Boot Mode USBKeys_Protocol = 0; }
// Adds a single USB Code to the USB Output buffer // Argument #1: USB Code void Output_usbCodeSend_capability( TriggerMacro *trigger, uint8_t state, uint8_t stateType, uint8_t *args ) { #if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_usbCodeSend(usbCode)"); return; } // Depending on which mode the keyboard is in the USB needs Press/Hold/Release events uint8_t keyPress = 0; // Default to key release // Only send press and release events if ( stateType == 0x00 && state == 0x02 ) // Hold state return; // If press, send bit (NKRO) or byte (6KRO) if ( stateType == 0x00 && state == 0x01 ) // Press state keyPress = 1; // Get the keycode from arguments uint8_t key = args[0]; // Depending on which mode the keyboard is in, USBKeys_Keys array is used differently // Boot mode - Maximum of 6 byte codes // NKRO mode - Each bit of the 26 byte corresponds to a key // Bits 0 - 45 (bytes 0 - 5) correspond to USB Codes 4 - 49 (Main) // Bits 48 - 161 (bytes 6 - 20) correspond to USB Codes 51 - 164 (Secondary) // Bits 168 - 213 (bytes 21 - 26) correspond to USB Codes 176 - 221 (Tertiary) // Bits 214 - 216 unused uint8_t bytePosition = 0; uint8_t byteShift = 0; switch ( USBKeys_Protocol ) { case 0: // Boot Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_primary.modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_primary.modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_primary.changed |= USBKeyChangeState_Modifiers; } // Normal USB Code else { // Determine if key was set uint8_t keyFound = 0; uint8_t old_sent = USBKeys_Sent; for ( uint8_t curkey = 0, newkey = 0; curkey < old_sent; curkey++, newkey++ ) { // On press, key already present, don't re-add if ( keyPress && USBKeys_primary.keys[newkey] == key ) { keyFound = 1; break; } // On release, remove if found if ( !keyPress && USBKeys_primary.keys[newkey] == key ) { // Shift next key onto this one // (Doesn't matter if it overflows, buffer is large enough, and size is used) USBKeys_primary.keys[newkey--] = USBKeys_primary.keys[++curkey]; USBKeys_Sent--; keyFound = 1; USBKeys_primary.changed = USBKeyChangeState_MainKeys; break; } } // USB Key limit reached if ( USBKeys_Sent >= USB_BOOT_MAX_KEYS ) { warn_print("USB Key limit reached"); break; } // Add key if not already found in the buffer if ( keyPress && !keyFound ) { USBKeys_primary.keys[USBKeys_Sent++] = key; USBKeys_primary.changed = USBKeyChangeState_MainKeys; } } break; case 1: // NKRO Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_primary.modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_primary.modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_primary.changed |= USBKeyChangeState_Modifiers; break; } // First 6 bytes else if ( key >= 4 && key <= 49 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 0th position, each byte has 8 bits, starting at 4th bit uint8_t keyPos = key + (0 * 8 - 4); // Starting position in array, Ignoring 4 keys switch ( keyPos ) { byteLookup( 0 ); byteLookup( 1 ); byteLookup( 2 ); byteLookup( 3 ); byteLookup( 4 ); byteLookup( 5 ); } USBKeys_primary.changed |= USBKeyChangeState_MainKeys; } // Next 14 bytes else if ( key >= 51 && key <= 155 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 6th byte position, each byte has 8 bits, starting at 51st bit uint8_t keyPos = key + (6 * 8 - 51); // Starting position in array switch ( keyPos ) { byteLookup( 6 ); byteLookup( 7 ); byteLookup( 8 ); byteLookup( 9 ); byteLookup( 10 ); byteLookup( 11 ); byteLookup( 12 ); byteLookup( 13 ); byteLookup( 14 ); byteLookup( 15 ); byteLookup( 16 ); byteLookup( 17 ); byteLookup( 18 ); byteLookup( 19 ); } USBKeys_primary.changed |= USBKeyChangeState_SecondaryKeys; } // Next byte else if ( key >= 157 && key <= 164 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (20 * 8 - 157); // Starting position in array, Ignoring 6 keys switch ( keyPos ) { byteLookup( 20 ); } USBKeys_primary.changed |= USBKeyChangeState_TertiaryKeys; } // Last 6 bytes else if ( key >= 176 && key <= 221 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (21 * 8 - 176); // Starting position in array switch ( keyPos ) { byteLookup( 21 ); byteLookup( 22 ); byteLookup( 23 ); byteLookup( 24 ); byteLookup( 25 ); byteLookup( 26 ); } USBKeys_primary.changed |= USBKeyChangeState_QuartiaryKeys; } // Received 0x00 // This is a special USB Code that internally indicates a "break" // It is used to send "nothing" in order to break up sequences of USB Codes else if ( key == 0x00 ) { USBKeys_primary.changed |= USBKeyChangeState_MainKeys; // Also flush out buffers just in case Output_flushBuffers(); break; } // Invalid key else { warn_msg("USB Code not within 4-49 (0x4-0x31), 51-155 (0x33-0x9B), 157-164 (0x9D-0xA4), 176-221 (0xB0-0xDD) or 224-231 (0xE0-0xE7) NKRO Mode: "); printHex( key ); print( NL ); break; } // Set/Unset if ( keyPress ) { USBKeys_primary.keys[bytePosition] |= (1 << byteShift); USBKeys_Sent--; } else // Release { USBKeys_primary.keys[bytePosition] &= ~(1 << byteShift); USBKeys_Sent++; } break; } #endif }
// Adds a single USB Code to the USB Output buffer // Argument #1: USB Code void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_usbCodeSend(usbCode)"); return; } // Depending on which mode the keyboard is in the USB needs Press/Hold/Release events uint8_t keyPress = 0; // Default to key release, only used for NKRO switch ( USBKeys_Protocol ) { case 0: // Boot Mode // TODO Analog inputs // Only indicate USB has changed if either a press or release has occured if ( state == 0x01 || state == 0x03 ) USBKeys_Changed = USBKeyChangeState_MainKeys; // Only send keypresses if press or hold state if ( stateType == 0x00 && state == 0x03 ) // Release state return; break; case 1: // NKRO Mode // Only send press and release events if ( stateType == 0x00 && state == 0x02 ) // Hold state return; // Determine if setting or unsetting the bitfield (press == set) if ( stateType == 0x00 && state == 0x01 ) // Press state keyPress = 1; break; } // Get the keycode from arguments uint8_t key = args[0]; // Depending on which mode the keyboard is in, USBKeys_Keys array is used differently // Boot mode - Maximum of 6 byte codes // NKRO mode - Each bit of the 26 byte corresponds to a key // Bits 0 - 45 (bytes 0 - 5) correspond to USB Codes 4 - 49 (Main) // Bits 48 - 161 (bytes 6 - 20) correspond to USB Codes 51 - 164 (Secondary) // Bits 168 - 213 (bytes 21 - 26) correspond to USB Codes 176 - 221 (Tertiary) // Bits 214 - 216 unused uint8_t bytePosition = 0; uint8_t byteShift = 0; switch ( USBKeys_Protocol ) { case 0: // Boot Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } // Normal USB Code else { // USB Key limit reached if ( USBKeys_Sent >= USB_BOOT_MAX_KEYS ) { warn_print("USB Key limit reached"); return; } // Make sure key is within the USB HID range if ( key <= 104 ) { USBKeys_Keys[USBKeys_Sent++] = key; } // Invalid key else { warn_msg("USB Code above 104/0x68 in Boot Mode: "); printHex( key ); print( NL ); } } break; case 1: // NKRO Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_Modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_Changed |= USBKeyChangeState_Modifiers; break; } // First 6 bytes else if ( key >= 4 && key <= 49 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 0th position, each byte has 8 bits, starting at 4th bit uint8_t keyPos = key + (0 * 8 - 4); // Starting position in array, Ignoring 4 keys switch ( keyPos ) { byteLookup( 0 ); byteLookup( 1 ); byteLookup( 2 ); byteLookup( 3 ); byteLookup( 4 ); byteLookup( 5 ); } USBKeys_Changed |= USBKeyChangeState_MainKeys; } // Next 14 bytes else if ( key >= 51 && key <= 155 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 6th byte position, each byte has 8 bits, starting at 51st bit uint8_t keyPos = key + (6 * 8 - 51); // Starting position in array switch ( keyPos ) { byteLookup( 6 ); byteLookup( 7 ); byteLookup( 8 ); byteLookup( 9 ); byteLookup( 10 ); byteLookup( 11 ); byteLookup( 12 ); byteLookup( 13 ); byteLookup( 14 ); byteLookup( 15 ); byteLookup( 16 ); byteLookup( 17 ); byteLookup( 18 ); byteLookup( 19 ); } USBKeys_Changed |= USBKeyChangeState_SecondaryKeys; } // Next byte else if ( key >= 157 && key <= 164 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (20 * 8 - 157); // Starting position in array, Ignoring 6 keys switch ( keyPos ) { byteLookup( 20 ); } USBKeys_Changed |= USBKeyChangeState_TertiaryKeys; } // Last 6 bytes else if ( key >= 176 && key <= 221 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (21 * 8 - 176); // Starting position in array switch ( keyPos ) { byteLookup( 21 ); byteLookup( 22 ); byteLookup( 23 ); byteLookup( 24 ); byteLookup( 25 ); byteLookup( 26 ); } USBKeys_Changed |= USBKeyChangeState_QuartiaryKeys; } // Received 0x00 // This is a special USB Code that internally indicates a "break" // It is used to send "nothing" in order to break up sequences of USB Codes else if ( key == 0x00 ) { USBKeys_Changed |= USBKeyChangeState_MainKeys; // Also flush out buffers just in case Output_flushBuffers(); break; } // Invalid key else { warn_msg("USB Code not within 4-49 (0x4-0x31), 51-155 (0x33-0x9B), 157-164 (0x9D-0xA4), 176-221 (0xB0-0xDD) or 224-231 (0xE0-0xE7) NKRO Mode: "); printHex( key ); print( NL ); break; } // Set/Unset if ( keyPress ) { USBKeys_Keys[bytePosition] |= (1 << byteShift); USBKeys_Sent++; } else // Release { USBKeys_Keys[bytePosition] &= ~(1 << byteShift); USBKeys_Sent++; } break; } }