Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ab0c2eb72 | ||
|
|
2e73bb9ea1 | ||
|
|
e5ac605b4c | ||
|
|
fb220038b7 | ||
|
|
464c56f599 | ||
|
|
a59b43b433 | ||
|
|
ceb2f3de00 | ||
|
|
5cd4030a93 | ||
|
|
21ae72dd9e | ||
|
|
dba61c6a42 | ||
|
|
f61acc483b | ||
|
|
fb38e4099b | ||
|
|
5fe19abe06 | ||
|
|
06e34fdcbc | ||
|
|
cc6666b96d | ||
|
|
a22dfdd917 | ||
|
|
8b69a25dda | ||
|
|
6f2b45c27c | ||
|
|
98f7d512de | ||
|
|
c5cf738fd0 | ||
|
|
af31ae210a | ||
|
|
44799995b9 | ||
|
|
3f5f83a19b | ||
|
|
bc4f35e578 | ||
|
|
e9309aab16 | ||
|
|
f004b84399 | ||
|
|
58f8120611 | ||
|
|
5b71fb7aaa | ||
|
|
9d0f41bf5e | ||
|
|
47a3a8ad80 | ||
|
|
b4908bf2ac | ||
|
|
846342e851 | ||
|
|
3196abe574 | ||
|
|
5f0bae1840 | ||
|
|
c3a38c8b59 | ||
|
|
1f9d31cad4 | ||
|
|
b89de6655e | ||
|
|
4a1b747197 | ||
|
|
eca87d2f62 | ||
|
|
2e2b9d08a9 |
42
CHANGELOG.md
42
CHANGELOG.md
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to the [UHK Versioning](VERSIONING.md) conventions.
|
and this project adheres to the [UHK Versioning](VERSIONING.md) conventions.
|
||||||
|
|
||||||
|
## [8.5.4] - 2018-01-05
|
||||||
|
|
||||||
|
Device Protocol: 4.5.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Make the modifiers of shortcut keys stick only as long as the layer switcher key of a shortcut key is being held.
|
||||||
|
|
||||||
|
## [8.5.3] - 2018-10-20
|
||||||
|
|
||||||
|
Device Protocol: 4.5.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Re-enable the I2C watchdog of the left keyboard half which was accidentally disabled starting from firmware 8.4.3. This should fix the freezes of the left keyboard half.
|
||||||
|
|
||||||
|
## [8.5.2] - 2018-10-06
|
||||||
|
|
||||||
|
Device Protocol: 4.5.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Don't suppress keys upon keymap change.
|
||||||
|
|
||||||
|
## [8.5.1] - 2018-10-04
|
||||||
|
|
||||||
|
Device Protocol: 4.5.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Reset UsbReportUpdateSemaphore if it gets stuck for 100ms. This should fix occasional freezes.
|
||||||
|
|
||||||
|
## [8.5.0] - 2018-10-04
|
||||||
|
|
||||||
|
Device Protocol: 4.**5.0** | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Send primary role modifiers consistently.
|
||||||
|
- Only allow layer switcher keys to deactivate toggled layers.
|
||||||
|
- Deactivate secondary roles when switching keymaps.
|
||||||
|
- Use the correct scancode so that commas are outputted for macros.
|
||||||
|
- Move the pointer not by 1 but by 5 pixels when testing the USB stack to make the pointer easier to see.
|
||||||
|
- Expose UsbReportUpdateSemaphore via UsbCommand_{Get,Set}Variable() `DEVICEPROTOCOL:MINOR`
|
||||||
|
- Extract CurrentTime and remove Timer_{Get,Set}CurrentTime()
|
||||||
|
|
||||||
|
## [8.4.5] - 2018-08-21
|
||||||
|
|
||||||
|
Device Protocol: 4.4.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Suppress pressed keys when the layer or keymap changes.
|
||||||
|
|
||||||
## [8.4.4] - 2018-08-14
|
## [8.4.4] - 2018-08-14
|
||||||
|
|
||||||
Device Protocol: 4.4.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
Device Protocol: 4.4.0 | Module Protocol: 4.0.0 | User Config: 4.1.0 | Hardware Config: 1.0.0
|
||||||
|
|||||||
8
ISSUE_TEMPLATE
Normal file
8
ISSUE_TEMPLATE
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Before submitting a new issue, make sure to do the following:
|
||||||
|
|
||||||
|
1. If you're using Karabiner Elements on your Mac, close it!
|
||||||
|
2. Install the latest Agent:
|
||||||
|
https://github.com/UltimateHackingKeyboard/agent/releases/latest
|
||||||
|
3. Use Agent to update to the latest firmware:
|
||||||
|
https://github.com/UltimateHackingKeyboard/firmware/releases/latest
|
||||||
|
4. Try to reproduce the issue, and only report it if it still persists.
|
||||||
19
README.md
19
README.md
@@ -12,20 +12,23 @@ If you're one of the brave few who wants to hack the firmware then read on.
|
|||||||
|
|
||||||
`git clone --recursive git@github.com:UltimateHackingKeyboard/firmware.git`
|
`git clone --recursive git@github.com:UltimateHackingKeyboard/firmware.git`
|
||||||
|
|
||||||
2. Download and install MCUXpresso IDE for [Linux](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/mcuxpressoide-10.1.1_606.x86_64.deb.bin), [Mac](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/MCUXpressoIDE_10.1.1_606.pkg), or [Windows](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/MCUXpressoIDE_10.1.1_606.exe).
|
2. Download and install MCUXpresso IDE for [Linux](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/mcuxpressoide-10.2.1_795.x86_64.deb.bin), [Mac](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/MCUXpressoIDE_10.2.1_795.pkg), or [Windows](https://storage.googleapis.com/ugl-static/mcuxpresso-ide/MCUXpressoIDE_10.2.1_795.exe).
|
||||||
|
|
||||||
3. In the IDE, import the project by invoking *File -> Import -> General -> Existing Projects into Workspace*, select the *left* or *right* directory depending on the desired firmware, then click on the *Finish* button.
|
3. In the IDE, import the project by invoking *File -> Import -> General -> Existing Projects into Workspace*, select the *left* or *right* directory depending on the desired firmware, then click on the *Finish* button.
|
||||||
|
|
||||||
## Building and flashing the firmware
|
4. In order to be able to flash the firmware via USB from the IDE, you must build [Agent](https://github.com/UltimateHackingKeyboard/agent) which is Git submodule of the this repo and located in the `lib/agent` directory.
|
||||||
|
|
||||||
For the left keyboard half, make sure to power it via the right keyboard half (which must be powered via USB). Also connect the left keyboard half to your SEGGER J-Link USB debug probe (which must also be connected via USB). Then in KDS, click on *Run -> Run Configurations*, select *GDB SEGGER J-Link Debugging -> uhk60-left_release_jlink*, and click on the *Debug* button.
|
5. Finally, in the IDE, click on *Run -> External Tools -> External Tools Configurations*, then select a release firmware to be flashed such as *uhk60-right_release_kboot*, and click on the *Run* button.
|
||||||
|
|
||||||
For the right keyboard half, flash [the bootloader](https://github.com/UltimateHackingKeyboard/bootloader) first.
|
Going forward, it's easier to flash the firmware of your choice by using the downwards toolbar icon which is located rightwards of the *green play + toolbox icon*.
|
||||||
|
|
||||||
At this point, you can flash the right firmware via USB from KDS. To achieve this, you must build [Agent](https://github.com/UltimateHackingKeyboard/agent) that is Git submodule of the this repo and located in the `lib/agent` directory. Then in KDS, click on *Run -> Run Configurations*, select *C/C++ Application -> uhk60-right_release_kboot*, and click on the *Run* button.
|
|
||||||
|
|
||||||
From this point on, you can upgrade the firmwares of both halves via USB by using the uhk60-left_release_kboot and uhk60-right_release_kboot run configurations. Alternatively, you can use your SEGGER J-Link probe.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Want to contribute? Let us show you [how](/CONTRIBUTING.md).
|
Want to contribute? Let us show you [how](/CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## Custom Firmwares
|
||||||
|
|
||||||
|
The following list contains unofficial forks of the firmware. These forks provide functionality unavailable in the official firmware, but come without guarantees of any kind:
|
||||||
|
|
||||||
|
- [https://github.com/kareltucek/firmware](https://github.com/kareltucek/firmware) - firmware featuring macro engine extended by a set of custom commands, allowing more advanced configurations including custom layer switching logic, doubletap bindings, alternative secondary roles etc.
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,7 @@
|
|||||||
void KEY_SCANNER_HANDLER(void)
|
void KEY_SCANNER_HANDLER(void)
|
||||||
{
|
{
|
||||||
KeyMatrix_ScanRow(&keyMatrix);
|
KeyMatrix_ScanRow(&keyMatrix);
|
||||||
#ifdef I2C_WATCHDOG
|
|
||||||
RunWatchdog();
|
RunWatchdog();
|
||||||
#endif
|
|
||||||
LPTMR_ClearStatusFlags(KEY_SCANNER_LPTMR_BASEADDR, kLPTMR_TimerCompareFlag);
|
LPTMR_ClearStatusFlags(KEY_SCANNER_LPTMR_BASEADDR, kLPTMR_TimerCompareFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Submodule lib/agent updated: 80e8c014ec...1eb8720305
@@ -13,7 +13,6 @@
|
|||||||
uint8_t timestamp;
|
uint8_t timestamp;
|
||||||
bool previous : 1;
|
bool previous : 1;
|
||||||
bool current : 1;
|
bool current : 1;
|
||||||
bool suppressed : 1;
|
|
||||||
bool debouncing : 1;
|
bool debouncing : 1;
|
||||||
} key_state_t;
|
} key_state_t;
|
||||||
|
|
||||||
|
|||||||
@@ -70,3 +70,14 @@ layer_id_t GetActiveLayer()
|
|||||||
|
|
||||||
return heldLayer;
|
return heldLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsLayerHeld(void)
|
||||||
|
{
|
||||||
|
for (layer_id_t layerId = LayerId_Mod; layerId <= LayerId_Mouse; layerId++) {
|
||||||
|
if (heldLayers[layerId]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
// Functions:
|
// Functions:
|
||||||
|
|
||||||
layer_id_t GetActiveLayer();
|
layer_id_t GetActiveLayer(void);
|
||||||
|
bool IsLayerHeld(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ uint8_t characterToScancode(char character)
|
|||||||
return HID_KEYBOARD_SC_DOT_AND_GREATER_THAN_SIGN;
|
return HID_KEYBOARD_SC_DOT_AND_GREATER_THAN_SIGN;
|
||||||
case ',':
|
case ',':
|
||||||
case '<':
|
case '<':
|
||||||
return HID_KEYBOARD_SC_KEYPAD_LESS_THAN_SIGN;
|
return HID_KEYBOARD_SC_COMMA_AND_LESS_THAN_SIGN;
|
||||||
case '/':
|
case '/':
|
||||||
case '\?':
|
case '\?':
|
||||||
return HID_KEYBOARD_SC_SLASH_AND_QUESTION_MARK;
|
return HID_KEYBOARD_SC_SLASH_AND_QUESTION_MARK;
|
||||||
@@ -286,7 +286,7 @@ bool processDelayAction(void)
|
|||||||
inDelay = false;
|
inDelay = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timer_SetCurrentTime(&delayStart);
|
delayStart = CurrentTime;
|
||||||
inDelay = true;
|
inDelay = true;
|
||||||
}
|
}
|
||||||
return inDelay;
|
return inDelay;
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "peripherals/test_led.h"
|
#include "peripherals/test_led.h"
|
||||||
|
|
||||||
|
volatile uint32_t CurrentTime;
|
||||||
static uint32_t timerClockFrequency;
|
static uint32_t timerClockFrequency;
|
||||||
static volatile uint32_t currentTime, delayLength;
|
static volatile uint32_t delayLength;
|
||||||
|
|
||||||
void PIT_TIMER_HANDLER(void)
|
void PIT_TIMER_HANDLER(void)
|
||||||
{
|
{
|
||||||
currentTime++;
|
CurrentTime++;
|
||||||
if (delayLength) {
|
if (delayLength) {
|
||||||
--delayLength;
|
--delayLength;
|
||||||
}
|
}
|
||||||
@@ -28,15 +29,11 @@ void Timer_Init(void)
|
|||||||
PIT_StartTimer(PIT, PIT_TIMER_CHANNEL);
|
PIT_StartTimer(PIT, PIT_TIMER_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Timer_GetCurrentTime() {
|
|
||||||
return currentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Timer_GetCurrentTimeMicros() {
|
uint32_t Timer_GetCurrentTimeMicros() {
|
||||||
uint32_t primask, count, ms;
|
uint32_t primask, count, ms;
|
||||||
primask = DisableGlobalIRQ(); // Make sure the read is atomic
|
primask = DisableGlobalIRQ(); // Make sure the read is atomic
|
||||||
count = PIT_GetCurrentTimerCount(PIT, PIT_TIMER_CHANNEL); // Read the current timer count
|
count = PIT_GetCurrentTimerCount(PIT, PIT_TIMER_CHANNEL); // Read the current timer count
|
||||||
ms = currentTime; // Read the overflow counter
|
ms = CurrentTime; // Read the overflow counter
|
||||||
EnableGlobalIRQ(primask); // Enable interrupts again if they where enabled before - this should make it interrupt safe
|
EnableGlobalIRQ(primask); // Enable interrupts again if they where enabled before - this should make it interrupt safe
|
||||||
|
|
||||||
// Calculate the counter value in microseconds - note that the PIT timer is counting downward, so we need to subtract the count from the period value
|
// Calculate the counter value in microseconds - note that the PIT timer is counting downward, so we need to subtract the count from the period value
|
||||||
@@ -44,11 +41,6 @@ uint32_t Timer_GetCurrentTimeMicros() {
|
|||||||
return ms * 1000U * TIMER_INTERVAL_MSEC + us;
|
return ms * 1000U * TIMER_INTERVAL_MSEC + us;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer_SetCurrentTime(uint32_t *time)
|
|
||||||
{
|
|
||||||
*time = Timer_GetCurrentTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer_SetCurrentTimeMicros(uint32_t *time)
|
void Timer_SetCurrentTimeMicros(uint32_t *time)
|
||||||
{
|
{
|
||||||
*time = Timer_GetCurrentTimeMicros();
|
*time = Timer_GetCurrentTimeMicros();
|
||||||
@@ -56,20 +48,18 @@ void Timer_SetCurrentTimeMicros(uint32_t *time)
|
|||||||
|
|
||||||
uint32_t Timer_GetElapsedTime(uint32_t *time)
|
uint32_t Timer_GetElapsedTime(uint32_t *time)
|
||||||
{
|
{
|
||||||
uint32_t elapsedTime = Timer_GetCurrentTime() - *time;
|
return CurrentTime - *time;
|
||||||
return elapsedTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Timer_GetElapsedTimeMicros(uint32_t *time)
|
uint32_t Timer_GetElapsedTimeMicros(uint32_t *time)
|
||||||
{
|
{
|
||||||
uint32_t elapsedTime = Timer_GetCurrentTimeMicros() - *time;
|
return Timer_GetCurrentTimeMicros() - *time;
|
||||||
return elapsedTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Timer_GetElapsedTimeAndSetCurrent(uint32_t *time)
|
uint32_t Timer_GetElapsedTimeAndSetCurrent(uint32_t *time)
|
||||||
{
|
{
|
||||||
uint32_t elapsedTime = Timer_GetElapsedTime(time);
|
uint32_t elapsedTime = Timer_GetElapsedTime(time);
|
||||||
*time = Timer_GetCurrentTime();
|
*time = CurrentTime;
|
||||||
return elapsedTime;
|
return elapsedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,14 @@
|
|||||||
|
|
||||||
#define TIMER_INTERVAL_MSEC 1
|
#define TIMER_INTERVAL_MSEC 1
|
||||||
|
|
||||||
|
// Variables:
|
||||||
|
|
||||||
|
extern volatile uint32_t CurrentTime;
|
||||||
|
|
||||||
// Functions:
|
// Functions:
|
||||||
|
|
||||||
void Timer_Init(void);
|
void Timer_Init(void);
|
||||||
uint32_t Timer_GetCurrentTime();
|
|
||||||
uint32_t Timer_GetCurrentTimeMicros();
|
uint32_t Timer_GetCurrentTimeMicros();
|
||||||
void Timer_SetCurrentTime(uint32_t *time);
|
|
||||||
void Timer_SetCurrentTimeMicros(uint32_t *time);
|
void Timer_SetCurrentTimeMicros(uint32_t *time);
|
||||||
uint32_t Timer_GetElapsedTime(uint32_t *time);
|
uint32_t Timer_GetElapsedTime(uint32_t *time);
|
||||||
uint32_t Timer_GetElapsedTimeMicros(uint32_t *time);
|
uint32_t Timer_GetElapsedTimeMicros(uint32_t *time);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void UsbCommand_GetDebugBuffer(void)
|
|||||||
SetDebugBufferUint32(13, I2cWatchdog_RecoveryCounter);
|
SetDebugBufferUint32(13, I2cWatchdog_RecoveryCounter);
|
||||||
SetDebugBufferUint32(17, MatrixScanCounter);
|
SetDebugBufferUint32(17, MatrixScanCounter);
|
||||||
SetDebugBufferUint32(21, UsbReportUpdateCounter);
|
SetDebugBufferUint32(21, UsbReportUpdateCounter);
|
||||||
SetDebugBufferUint32(25, Timer_GetCurrentTime());
|
SetDebugBufferUint32(25, CurrentTime);
|
||||||
SetDebugBufferUint32(29, UsbGenericHidActionCounter);
|
SetDebugBufferUint32(29, UsbGenericHidActionCounter);
|
||||||
SetDebugBufferUint32(33, UsbBasicKeyboardActionCounter);
|
SetDebugBufferUint32(33, UsbBasicKeyboardActionCounter);
|
||||||
SetDebugBufferUint32(37, UsbMediaKeyboardActionCounter);
|
SetDebugBufferUint32(37, UsbMediaKeyboardActionCounter);
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ void UsbCommand_GetDeviceProperty(void)
|
|||||||
SetUsbTxBufferUint32(6, I2cMainBusActualBaudRateBps);
|
SetUsbTxBufferUint32(6, I2cMainBusActualBaudRateBps);
|
||||||
break;
|
break;
|
||||||
case DevicePropertyId_Uptime:
|
case DevicePropertyId_Uptime:
|
||||||
SetUsbTxBufferUint32(1, Timer_GetCurrentTime());
|
SetUsbTxBufferUint32(1, CurrentTime);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SetUsbTxBufferUint8(0, UsbStatusCode_GetDeviceProperty_InvalidProperty);
|
SetUsbTxBufferUint8(0, UsbStatusCode_GetDeviceProperty_InvalidProperty);
|
||||||
|
|||||||
@@ -21,5 +21,8 @@ void UsbCommand_GetVariable(void)
|
|||||||
case UsbVariable_DebounceTimeRelease:
|
case UsbVariable_DebounceTimeRelease:
|
||||||
SetUsbTxBufferUint8(1, DebounceTimeRelease);
|
SetUsbTxBufferUint8(1, DebounceTimeRelease);
|
||||||
break;
|
break;
|
||||||
|
case UsbVariable_UsbReportSemaphore:
|
||||||
|
SetUsbTxBufferUint8(1, UsbReportUpdateSemaphore);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,8 @@ void UsbCommand_SetVariable(void)
|
|||||||
case UsbVariable_DebounceTimeRelease:
|
case UsbVariable_DebounceTimeRelease:
|
||||||
DebounceTimeRelease = GetUsbRxBufferUint8(2);
|
DebounceTimeRelease = GetUsbRxBufferUint8(2);
|
||||||
break;
|
break;
|
||||||
|
case UsbVariable_UsbReportSemaphore:
|
||||||
|
UsbReportUpdateSemaphore = GetUsbRxBufferUint8(2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,8 @@
|
|||||||
UsbVariable_TestSwitches,
|
UsbVariable_TestSwitches,
|
||||||
UsbVariable_TestUsbStack,
|
UsbVariable_TestUsbStack,
|
||||||
UsbVariable_DebounceTimePress,
|
UsbVariable_DebounceTimePress,
|
||||||
UsbVariable_DebounceTimeRelease
|
UsbVariable_DebounceTimeRelease,
|
||||||
|
UsbVariable_UsbReportSemaphore,
|
||||||
} usb_variable_id_t;
|
} usb_variable_id_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ static uint16_t DoubleTapSwitchLayerReleaseTimeout = 200;
|
|||||||
|
|
||||||
static bool activeMouseStates[ACTIVE_MOUSE_STATES_COUNT];
|
static bool activeMouseStates[ACTIVE_MOUSE_STATES_COUNT];
|
||||||
bool TestUsbStack = false;
|
bool TestUsbStack = false;
|
||||||
|
static key_action_t actionCache[SLOT_COUNT][MAX_KEY_COUNT_PER_MODULE];
|
||||||
|
|
||||||
volatile uint8_t UsbReportUpdateSemaphore = 0;
|
volatile uint8_t UsbReportUpdateSemaphore = 0;
|
||||||
|
|
||||||
@@ -206,15 +207,15 @@ static void handleSwitchLayerAction(key_state_t *keyState, key_action_t *action)
|
|||||||
doubleTapSwitchLayerKey = NULL;
|
doubleTapSwitchLayerKey = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action->type != KeyActionType_SwitchLayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!keyState->previous && isLayerDoubleTapToggled && ToggledLayer == action->switchLayer.layer) {
|
if (!keyState->previous && isLayerDoubleTapToggled && ToggledLayer == action->switchLayer.layer) {
|
||||||
ToggledLayer = LayerId_Base;
|
ToggledLayer = LayerId_Base;
|
||||||
isLayerDoubleTapToggled = false;
|
isLayerDoubleTapToggled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action->type != KeyActionType_SwitchLayer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyState->previous && doubleTapSwitchLayerKey == keyState &&
|
if (keyState->previous && doubleTapSwitchLayerKey == keyState &&
|
||||||
Timer_GetElapsedTime(&doubleTapSwitchLayerTriggerTime) > DoubleTapSwitchLayerReleaseTimeout)
|
Timer_GetElapsedTime(&doubleTapSwitchLayerTriggerTime) > DoubleTapSwitchLayerReleaseTimeout)
|
||||||
{
|
{
|
||||||
@@ -225,86 +226,98 @@ static void handleSwitchLayerAction(key_state_t *keyState, key_action_t *action)
|
|||||||
if (doubleTapSwitchLayerKey && Timer_GetElapsedTimeAndSetCurrent(&doubleTapSwitchLayerStartTime) < DoubleTapSwitchLayerTimeout) {
|
if (doubleTapSwitchLayerKey && Timer_GetElapsedTimeAndSetCurrent(&doubleTapSwitchLayerStartTime) < DoubleTapSwitchLayerTimeout) {
|
||||||
ToggledLayer = action->switchLayer.layer;
|
ToggledLayer = action->switchLayer.layer;
|
||||||
isLayerDoubleTapToggled = true;
|
isLayerDoubleTapToggled = true;
|
||||||
doubleTapSwitchLayerTriggerTime = Timer_GetCurrentTime();
|
doubleTapSwitchLayerTriggerTime = CurrentTime;
|
||||||
} else {
|
} else {
|
||||||
doubleTapSwitchLayerKey = keyState;
|
doubleTapSwitchLayerKey = keyState;
|
||||||
}
|
}
|
||||||
doubleTapSwitchLayerStartTime = Timer_GetCurrentTime();
|
doubleTapSwitchLayerStartTime = CurrentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t basicScancodeIndex = 0;
|
static uint8_t basicScancodeIndex = 0;
|
||||||
static uint8_t mediaScancodeIndex = 0;
|
static uint8_t mediaScancodeIndex = 0;
|
||||||
static uint8_t systemScancodeIndex = 0;
|
static uint8_t systemScancodeIndex = 0;
|
||||||
static uint8_t stickyModifiers;
|
static uint8_t stickyModifiers, stickySlotId, stickyKeyId;
|
||||||
|
|
||||||
static void applyKeyAction(key_state_t *keyState, key_action_t *action)
|
|
||||||
{
|
|
||||||
if (keyState->suppressed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSwitchLayerAction(keyState, action);
|
|
||||||
|
|
||||||
switch (action->type) {
|
|
||||||
case KeyActionType_Keystroke:
|
|
||||||
if (action->keystroke.scancode) {
|
|
||||||
if (!keyState->previous) {
|
|
||||||
stickyModifiers = action->keystroke.modifiers;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ActiveUsbBasicKeyboardReport->modifiers |= action->keystroke.modifiers;
|
|
||||||
}
|
|
||||||
switch (action->keystroke.keystrokeType) {
|
|
||||||
case KeystrokeType_Basic:
|
|
||||||
if (basicScancodeIndex >= USB_BASIC_KEYBOARD_MAX_KEYS || action->keystroke.scancode == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ActiveUsbBasicKeyboardReport->scancodes[basicScancodeIndex++] = action->keystroke.scancode;
|
|
||||||
break;
|
|
||||||
case KeystrokeType_Media:
|
|
||||||
if (mediaScancodeIndex >= USB_MEDIA_KEYBOARD_MAX_KEYS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ActiveUsbMediaKeyboardReport->scancodes[mediaScancodeIndex++] = action->keystroke.scancode;
|
|
||||||
break;
|
|
||||||
case KeystrokeType_System:
|
|
||||||
if (systemScancodeIndex >= USB_SYSTEM_KEYBOARD_MAX_KEYS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ActiveUsbSystemKeyboardReport->scancodes[systemScancodeIndex++] = action->keystroke.scancode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KeyActionType_Mouse:
|
|
||||||
if (!keyState->previous) {
|
|
||||||
stickyModifiers = 0;
|
|
||||||
}
|
|
||||||
activeMouseStates[action->mouseAction] = true;
|
|
||||||
break;
|
|
||||||
case KeyActionType_SwitchLayer:
|
|
||||||
// Handled by handleSwitchLayerAction()
|
|
||||||
break;
|
|
||||||
case KeyActionType_SwitchKeymap:
|
|
||||||
if (!keyState->previous) {
|
|
||||||
stickyModifiers = 0;
|
|
||||||
SwitchKeymapById(action->switchKeymap.keymapId);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KeyActionType_PlayMacro:
|
|
||||||
if (!keyState->previous) {
|
|
||||||
stickyModifiers = 0;
|
|
||||||
Macros_StartMacro(action->playMacro.macroId);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t secondaryRoleState = SecondaryRoleState_Released;
|
static uint8_t secondaryRoleState = SecondaryRoleState_Released;
|
||||||
static uint8_t secondaryRoleSlotId;
|
static uint8_t secondaryRoleSlotId;
|
||||||
static uint8_t secondaryRoleKeyId;
|
static uint8_t secondaryRoleKeyId;
|
||||||
static secondary_role_t secondaryRole;
|
static secondary_role_t secondaryRole;
|
||||||
|
|
||||||
|
static void applyKeyAction(key_state_t *keyState, key_action_t *action, uint8_t slotId, uint8_t keyId)
|
||||||
|
{
|
||||||
|
if (keyState->current) {
|
||||||
|
handleSwitchLayerAction(keyState, action);
|
||||||
|
|
||||||
|
switch (action->type) {
|
||||||
|
case KeyActionType_Keystroke:
|
||||||
|
if (action->keystroke.scancode) {
|
||||||
|
if (!keyState->previous) {
|
||||||
|
stickyModifiers = action->keystroke.modifiers;
|
||||||
|
stickySlotId = slotId;
|
||||||
|
stickyKeyId = keyId;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ActiveUsbBasicKeyboardReport->modifiers |= action->keystroke.modifiers;
|
||||||
|
}
|
||||||
|
switch (action->keystroke.keystrokeType) {
|
||||||
|
case KeystrokeType_Basic:
|
||||||
|
if (basicScancodeIndex >= USB_BASIC_KEYBOARD_MAX_KEYS || action->keystroke.scancode == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ActiveUsbBasicKeyboardReport->scancodes[basicScancodeIndex++] = action->keystroke.scancode;
|
||||||
|
break;
|
||||||
|
case KeystrokeType_Media:
|
||||||
|
if (mediaScancodeIndex >= USB_MEDIA_KEYBOARD_MAX_KEYS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ActiveUsbMediaKeyboardReport->scancodes[mediaScancodeIndex++] = action->keystroke.scancode;
|
||||||
|
break;
|
||||||
|
case KeystrokeType_System:
|
||||||
|
if (systemScancodeIndex >= USB_SYSTEM_KEYBOARD_MAX_KEYS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ActiveUsbSystemKeyboardReport->scancodes[systemScancodeIndex++] = action->keystroke.scancode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyActionType_Mouse:
|
||||||
|
if (!keyState->previous) {
|
||||||
|
stickyModifiers = 0;
|
||||||
|
}
|
||||||
|
activeMouseStates[action->mouseAction] = true;
|
||||||
|
break;
|
||||||
|
case KeyActionType_SwitchLayer:
|
||||||
|
// Handled by handleSwitchLayerAction()
|
||||||
|
break;
|
||||||
|
case KeyActionType_SwitchKeymap:
|
||||||
|
if (!keyState->previous) {
|
||||||
|
stickyModifiers = 0;
|
||||||
|
secondaryRoleState = SecondaryRoleState_Released;
|
||||||
|
SwitchKeymapById(action->switchKeymap.keymapId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyActionType_PlayMacro:
|
||||||
|
if (!keyState->previous) {
|
||||||
|
stickyModifiers = 0;
|
||||||
|
Macros_StartMacro(action->playMacro.macroId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (action->type) {
|
||||||
|
case KeyActionType_Keystroke:
|
||||||
|
if (keyState->previous) {
|
||||||
|
if (slotId == stickySlotId && keyId == stickyKeyId) {
|
||||||
|
if (!IsLayerHeld() && !(secondaryRoleState == SecondaryRoleState_Triggered && IS_SECONDARY_ROLE_LAYER_SWITCHER(secondaryRole))) {
|
||||||
|
stickyModifiers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void updateActiveUsbReports(void)
|
static void updateActiveUsbReports(void)
|
||||||
{
|
{
|
||||||
if (MacroPlaying) {
|
if (MacroPlaying) {
|
||||||
@@ -333,7 +346,6 @@ static void updateActiveUsbReports(void)
|
|||||||
if (layerChanged) {
|
if (layerChanged) {
|
||||||
stickyModifiers = 0;
|
stickyModifiers = 0;
|
||||||
}
|
}
|
||||||
bool layerGotReleased = layerChanged && activeLayer == LayerId_Base;
|
|
||||||
LedDisplay_SetLayer(activeLayer);
|
LedDisplay_SetLayer(activeLayer);
|
||||||
|
|
||||||
if (TestUsbStack) {
|
if (TestUsbStack) {
|
||||||
@@ -351,63 +363,65 @@ static void updateActiveUsbReports(void)
|
|||||||
isEvenMedia = !isEvenMedia;
|
isEvenMedia = !isEvenMedia;
|
||||||
ActiveUsbMediaKeyboardReport->scancodes[mediaScancodeIndex++] = isEvenMedia ? MEDIA_VOLUME_DOWN : MEDIA_VOLUME_UP;
|
ActiveUsbMediaKeyboardReport->scancodes[mediaScancodeIndex++] = isEvenMedia ? MEDIA_VOLUME_DOWN : MEDIA_VOLUME_UP;
|
||||||
}
|
}
|
||||||
MouseMoveState.xOut = isEven ? -1 : 1;
|
MouseMoveState.xOut = isEven ? -5 : 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t slotId=0; slotId<SLOT_COUNT; slotId++) {
|
for (uint8_t slotId=0; slotId<SLOT_COUNT; slotId++) {
|
||||||
for (uint8_t keyId=0; keyId<MAX_KEY_COUNT_PER_MODULE; keyId++) {
|
for (uint8_t keyId=0; keyId<MAX_KEY_COUNT_PER_MODULE; keyId++) {
|
||||||
key_state_t *keyState = &KeyStates[slotId][keyId];
|
key_state_t *keyState = &KeyStates[slotId][keyId];
|
||||||
key_action_t *action = &CurrentKeymap[activeLayer][slotId][keyId];
|
key_action_t *action;
|
||||||
|
|
||||||
if (keyState->debouncing) {
|
if (keyState->debouncing) {
|
||||||
if ((uint8_t)(Timer_GetCurrentTime() - keyState->timestamp) > (keyState->previous ? DebounceTimePress : DebounceTimeRelease)) {
|
if ((uint8_t)(CurrentTime - keyState->timestamp) > (keyState->previous ? DebounceTimePress : DebounceTimeRelease)) {
|
||||||
keyState->debouncing = false;
|
keyState->debouncing = false;
|
||||||
} else {
|
} else {
|
||||||
keyState->current = keyState->previous;
|
keyState->current = keyState->previous;
|
||||||
}
|
}
|
||||||
} else if (keyState->previous != keyState->current) {
|
} else if (keyState->previous != keyState->current) {
|
||||||
keyState->timestamp = Timer_GetCurrentTime();
|
keyState->timestamp = CurrentTime;
|
||||||
keyState->debouncing = true;
|
keyState->debouncing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyState->current) {
|
if (keyState->current && !keyState->previous) {
|
||||||
if (SleepModeActive && !keyState->previous) {
|
if (SleepModeActive) {
|
||||||
WakeUpHost();
|
WakeUpHost();
|
||||||
}
|
}
|
||||||
key_action_t *baseAction = &CurrentKeymap[LayerId_Base][slotId][keyId];
|
if (secondaryRoleState == SecondaryRoleState_Pressed) {
|
||||||
if (layerGotReleased && !(baseAction->type == KeyActionType_Keystroke && baseAction->keystroke.scancode == 0 && baseAction->keystroke.modifiers)) {
|
// Trigger secondary role.
|
||||||
keyState->suppressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger secondary role.
|
|
||||||
if (!keyState->previous && secondaryRoleState == SecondaryRoleState_Pressed) {
|
|
||||||
secondaryRoleState = SecondaryRoleState_Triggered;
|
secondaryRoleState = SecondaryRoleState_Triggered;
|
||||||
keyState->current = false;
|
keyState->current = false;
|
||||||
} else if (action->type == KeyActionType_Keystroke && action->keystroke.secondaryRole) {
|
} else {
|
||||||
|
actionCache[slotId][keyId] = CurrentKeymap[activeLayer][slotId][keyId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action = &actionCache[slotId][keyId];
|
||||||
|
|
||||||
|
if (keyState->current) {
|
||||||
|
if (action->type == KeyActionType_Keystroke && action->keystroke.secondaryRole) {
|
||||||
// Press released secondary role key.
|
// Press released secondary role key.
|
||||||
if (!keyState->previous && secondaryRoleState == SecondaryRoleState_Released) {
|
if (!keyState->previous && secondaryRoleState == SecondaryRoleState_Released) {
|
||||||
secondaryRoleState = SecondaryRoleState_Pressed;
|
secondaryRoleState = SecondaryRoleState_Pressed;
|
||||||
secondaryRoleSlotId = slotId;
|
secondaryRoleSlotId = slotId;
|
||||||
secondaryRoleKeyId = keyId;
|
secondaryRoleKeyId = keyId;
|
||||||
secondaryRole = action->keystroke.secondaryRole;
|
secondaryRole = action->keystroke.secondaryRole;
|
||||||
keyState->suppressed = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
applyKeyAction(keyState, action);
|
applyKeyAction(keyState, action, slotId, keyId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (keyState->suppressed) {
|
|
||||||
keyState->suppressed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release secondary role key.
|
// Release secondary role key.
|
||||||
if (keyState->previous && secondaryRoleSlotId == slotId && secondaryRoleKeyId == keyId) {
|
if (keyState->previous && secondaryRoleSlotId == slotId && secondaryRoleKeyId == keyId && secondaryRoleState != SecondaryRoleState_Released) {
|
||||||
// Trigger primary role.
|
// Trigger primary role.
|
||||||
if (secondaryRoleState == SecondaryRoleState_Pressed) {
|
if (secondaryRoleState == SecondaryRoleState_Pressed) {
|
||||||
applyKeyAction(keyState, action);
|
keyState->previous = false;
|
||||||
|
keyState->current = true;
|
||||||
|
applyKeyAction(keyState, action, slotId, keyId);
|
||||||
}
|
}
|
||||||
secondaryRoleState = SecondaryRoleState_Released;
|
secondaryRoleState = SecondaryRoleState_Released;
|
||||||
|
} else {
|
||||||
|
applyKeyAction(keyState, action, slotId, keyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,14 +447,21 @@ uint32_t UsbReportUpdateCounter;
|
|||||||
|
|
||||||
void UpdateUsbReports(void)
|
void UpdateUsbReports(void)
|
||||||
{
|
{
|
||||||
|
static uint32_t lastUpdateTime;
|
||||||
|
|
||||||
for (uint8_t keyId = 0; keyId < RIGHT_KEY_MATRIX_KEY_COUNT; keyId++) {
|
for (uint8_t keyId = 0; keyId < RIGHT_KEY_MATRIX_KEY_COUNT; keyId++) {
|
||||||
KeyStates[SlotId_RightKeyboardHalf][keyId].current = RightKeyMatrix.keyStates[keyId];
|
KeyStates[SlotId_RightKeyboardHalf][keyId].current = RightKeyMatrix.keyStates[keyId];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UsbReportUpdateSemaphore && !SleepModeActive) {
|
if (UsbReportUpdateSemaphore && !SleepModeActive) {
|
||||||
return;
|
if (Timer_GetElapsedTime(&lastUpdateTime) < USB_SEMAPHORE_TIMEOUT) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
UsbReportUpdateSemaphore = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastUpdateTime = CurrentTime;
|
||||||
UsbReportUpdateCounter++;
|
UsbReportUpdateCounter++;
|
||||||
|
|
||||||
ResetActiveUsbBasicKeyboardReport();
|
ResetActiveUsbBasicKeyboardReport();
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#define SECONDARY_ROLE_MODIFIER_TO_HID_MODIFIER(secondaryRoleModifier) (1 << ((secondaryRoleModifier) - 1))
|
#define SECONDARY_ROLE_MODIFIER_TO_HID_MODIFIER(secondaryRoleModifier) (1 << ((secondaryRoleModifier) - 1))
|
||||||
#define SECONDARY_ROLE_LAYER_TO_LAYER_ID(secondaryRoleLayer) ((secondaryRoleLayer) - SecondaryRole_RightSuper)
|
#define SECONDARY_ROLE_LAYER_TO_LAYER_ID(secondaryRoleLayer) ((secondaryRoleLayer) - SecondaryRole_RightSuper)
|
||||||
|
|
||||||
|
#define USB_SEMAPHORE_TIMEOUT 100 // ms
|
||||||
|
|
||||||
// Typedefs:
|
// Typedefs:
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
"commander": "^2.11.0",
|
"commander": "^2.11.0",
|
||||||
"shelljs": "^0.7.8"
|
"shelljs": "^0.7.8"
|
||||||
},
|
},
|
||||||
"firmwareVersion": "8.4.4",
|
"firmwareVersion": "8.5.4",
|
||||||
"deviceProtocolVersion": "4.4.0",
|
"deviceProtocolVersion": "4.5.0",
|
||||||
"moduleProtocolVersion": "4.0.0",
|
"moduleProtocolVersion": "4.0.0",
|
||||||
"userConfigVersion": "4.1.0",
|
"userConfigVersion": "4.1.0",
|
||||||
"hardwareConfigVersion": "1.0.0",
|
"hardwareConfigVersion": "1.0.0",
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
// Variables:
|
// Variables:
|
||||||
|
|
||||||
#define FIRMWARE_MAJOR_VERSION 8
|
#define FIRMWARE_MAJOR_VERSION 8
|
||||||
#define FIRMWARE_MINOR_VERSION 4
|
#define FIRMWARE_MINOR_VERSION 5
|
||||||
#define FIRMWARE_PATCH_VERSION 4
|
#define FIRMWARE_PATCH_VERSION 4
|
||||||
|
|
||||||
#define DEVICE_PROTOCOL_MAJOR_VERSION 4
|
#define DEVICE_PROTOCOL_MAJOR_VERSION 4
|
||||||
#define DEVICE_PROTOCOL_MINOR_VERSION 4
|
#define DEVICE_PROTOCOL_MINOR_VERSION 5
|
||||||
#define DEVICE_PROTOCOL_PATCH_VERSION 0
|
#define DEVICE_PROTOCOL_PATCH_VERSION 0
|
||||||
|
|
||||||
#define MODULE_PROTOCOL_MAJOR_VERSION 4
|
#define MODULE_PROTOCOL_MAJOR_VERSION 4
|
||||||
|
|||||||
Reference in New Issue
Block a user