From 8a9945b183d845af3e5a6d63a7b6cf082d379ae7 Mon Sep 17 00:00:00 2001 From: Jacob Alexander Date: Sat, 6 Aug 2016 20:51:10 -0700 Subject: [PATCH] Adding keyBlock capability to support Programmmer's Dvorak - Useful for partial redefinitions of keys Such as redefining Shift, which, as per the USB spec is handled by the OS This means we have to careful select which USB Codes to send to the OS to simulate Shift not being pressed (while it is) - KLL capabilities only work with numerical arguments (KLL 0.3d) - Each key must be explicitly block for each combination (e.g. LShift and RShift are handled separately) - Adding example configuration for the Infinity 60% - Requires kll.git 1a078b2b940709bc3c429c952d2f0d842927394f or higher --- Keyboards/infinity_programmers_dvorak.bash | 71 ++++++++++++++++++++++ Macro/PartialMap/capabilities.kll | 21 ++++++- Macro/PartialMap/macro.c | 60 ++++++++++++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100755 Keyboards/infinity_programmers_dvorak.bash diff --git a/Keyboards/infinity_programmers_dvorak.bash b/Keyboards/infinity_programmers_dvorak.bash new file mode 100755 index 000000000..e9062ccd5 --- /dev/null +++ b/Keyboards/infinity_programmers_dvorak.bash @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# This script shows how to use a complex multi-file layout such as Programmer's Dvorak +# Jacob Alexander 2016 + + + +################# +# Configuration # +################# + +# Feel free to change the variables in this section to configure your keyboard + +BuildPath="IC60" + +## KLL Configuration ## + +# Generally shouldn't be changed, this will affect every layer +BaseMap="scancode_map" + +# This is the default layer of the keyboard +# NOTE: To combine kll files into a single layout, separate them by spaces +# e.g. DefaultMap="mylayout mylayoutmod" +DefaultMap="programmers_dvorak_default stdFuncMap" + +# This is where you set the additional layers +# NOTE: Indexing starts at 1 +# NOTE: Each new layer is another array entry +# e.g. PartialMaps[1]="layer1 layer1mod" +# PartialMaps[2]="layer2" +# PartialMaps[3]="layer3" +PartialMaps[1]="programmers_dvorak_shift" + + + +########################## +# Advanced Configuration # +########################## + +# Don't change the variables in this section unless you know what you're doing +# These are useful for completely custom keyboards +# NOTE: Changing any of these variables will require a force build to compile correctly + +# Keyboard Module Configuration +ScanModule="Infinity_60%" +MacroModule="PartialMap" +OutputModule="pjrcUSB" +DebugModule="full" + +# Microcontroller +Chip="mk20dx128vlf5" + +# Compiler Selection +Compiler="gcc" + + + +######################## +# Bash Library Include # +######################## + +# Shouldn't need to touch this section + +# Check if the library can be found +if [ ! -f cmake.bash ]; then + echo "ERROR: Cannot find 'cmake.bash'" + exit 1 +fi + +# Load the library +source cmake.bash + diff --git a/Macro/PartialMap/capabilities.kll b/Macro/PartialMap/capabilities.kll index 5261754b1..5e182c0a4 100644 --- a/Macro/PartialMap/capabilities.kll +++ b/Macro/PartialMap/capabilities.kll @@ -1,10 +1,10 @@ Name = PartialMapCapabilities; -Version = 0.3; +Version = 0.4; Author = "HaaTa (Jacob Alexander) 2014-2016"; KLL = 0.3d; # Modified Date -Date = 2016-04-08; +Date = 2016-08-06; # Capabilties available to the PartialMap module @@ -25,3 +25,20 @@ stateWordSize = 8; # Default for now, increase to 16 or 32 for higher limits indexWordSize => IndexWordSize_define; indexWordSize = 16; # Default for now, increase to 32 for higher limits (8 for less resource usage) +# Block Key Capability +# Add this capability as a combo to any key you want to explicitly block another +# For example: +# To turn Shift+1 into q +# U"Shift" + U"1" : U"Q" + blockKey( 0xE1 ) + blockKey( 0x1E ); +# +# 0xE1 - Left Shift (0xE5 is Right Shift) +# 0x1E - 1 +# +# NOTE: KLL is limited to using numbers for key blocking instead of the symbolic names +# A future version of KLL will address this +blockKey => Macro_blockUSBKey_capability( usbCode : 1 ); + +# This defines the maximum number of keys that can be blocked in a single processing loop +maxBlockCount => Macro_maxBlockCount_define; +maxBlockCount = 4; + diff --git a/Macro/PartialMap/macro.c b/Macro/PartialMap/macro.c index 68eb42ac6..6ec480fdc 100644 --- a/Macro/PartialMap/macro.c +++ b/Macro/PartialMap/macro.c @@ -131,6 +131,10 @@ TriggerGuide macroInterconnectCache[ MaxScanCode ]; uint8_t macroInterconnectCacheSize = 0; #endif +// Key blocking buffer +uint8_t macroHidBlockList[ Macro_maxBlockCount_define ]; +uint8_t macroHidBlockListSize; + // ----- Capabilities ----- @@ -370,6 +374,39 @@ void Macro_layerRotate_capability( uint8_t state, uint8_t stateType, uint8_t *ar } +// Block USB Key +// During the next processing cycle, queue up a key to be ignored +// e.g. If Shift is assigned to both Shift and Layer 1 +// Then if the 1 key on Layer 1 is assigned 2 +// Block the Shift key so a USB 2 can be sent via the Output channel +// This works by having a queue of keys to "unset" if they are triggered during the next processing loop +void Macro_blockUSBKey_capability( uint8_t state, uint8_t stateType, uint8_t *args ) +{ + // Display capability name + if ( stateType == 0xFF && state == 0xFF ) + { + print("Macro_blockUSBKey(usbCode)"); + return; + } + + // Get usb key from arguments + // Access argument directly as it's already uint8_t + uint8_t usbCode = args[0]; + + // Add to the hid block list + if ( macroHidBlockListSize < Macro_maxBlockCount_define ) + { + macroHidBlockList[ macroHidBlockListSize++ ] = usbCode; + } + else + { + warn_print("USB Key Block buffer is full!: "); + printHex( usbCode ); + print( NL ); + } +} + + // ----- Functions ----- @@ -681,6 +718,26 @@ void Macro_appendResultMacroToPendingList( const TriggerMacro *triggerMacro ) } +// Block any of the keys that may be in the buffer +// These keys may not be pressed during the processing loop, but block them anyways +// See Macro_blockUSBKey_capability for more details on usage +inline void Macro_processKeyBlocking() +{ + // Iterate over list of USB keys + for ( uint8_t key = 0; key < Macro_maxBlockCount_define; key++ ) + { + // This capability will always unset (doesn't toggle) + + // First we need to generate the argument + uint8_t args[] = { macroHidBlockList[ key ] }; + + // XXX Only handles normal keys (no analog, yet) + // 0x03 is release, which always unsets a key from the USB buffer, even if it's not there + Output_usbCodeSend_capability( 0x03, 0x00, args ); + } +} + + // Macro Procesing Loop // Called once per USB buffer send inline void Macro_process() @@ -758,6 +815,9 @@ inline void Macro_process() // Process result macros Result_process(); + // Process Key Blocking + Macro_processKeyBlocking(); + // Signal buffer that we've used it Scan_finishedWithMacro( macroTriggerListBufferSize );