#include #include "key_action.h" #include "led_display.h" #include "layer.h" #include "usb_interfaces/usb_interface_mouse.h" #include "keymap.h" #include "peripherals/test_led.h" #include "slave_drivers/is31fl3731_driver.h" #include "slave_drivers/uhk_module_driver.h" #include "macros.h" #include "key_states.h" #include "right_key_matrix.h" #include "layer.h" #include "usb_report_updater.h" #include "timer.h" #include "key_debouncer.h" #include "config_parser/parse_keymap.h" #include "usb_commands/usb_command_get_debug_buffer.h" uint32_t UsbReportUpdateTime = 0; static uint32_t elapsedTime; uint16_t DoubleTapSwitchLayerTimeout = 250; static bool activeMouseStates[ACTIVE_MOUSE_STATES_COUNT]; mouse_kinetic_state_t MouseMoveState = { .isScroll = false, .upState = SerializedMouseAction_MoveUp, .downState = SerializedMouseAction_MoveDown, .leftState = SerializedMouseAction_MoveLeft, .rightState = SerializedMouseAction_MoveRight, .intMultiplier = 25, .initialSpeed = 5, .acceleration = 35, .deceleratedSpeed = 10, .baseSpeed = 40, .acceleratedSpeed = 80, }; mouse_kinetic_state_t MouseScrollState = { .isScroll = true, .upState = SerializedMouseAction_ScrollDown, .downState = SerializedMouseAction_ScrollUp, .leftState = SerializedMouseAction_ScrollLeft, .rightState = SerializedMouseAction_ScrollRight, .intMultiplier = 1, .initialSpeed = 20, .acceleration = 20, .deceleratedSpeed = 10, .baseSpeed = 20, .acceleratedSpeed = 50, }; void processMouseKineticState(mouse_kinetic_state_t *kineticState) { float initialSpeed = kineticState->intMultiplier * kineticState->initialSpeed; float acceleration = kineticState->intMultiplier * kineticState->acceleration; float deceleratedSpeed = kineticState->intMultiplier * kineticState->deceleratedSpeed; float baseSpeed = kineticState->intMultiplier * kineticState->baseSpeed; float acceleratedSpeed = kineticState->intMultiplier * kineticState->acceleratedSpeed; if (!kineticState->wasMoveAction && !activeMouseStates[SerializedMouseAction_Decelerate]) { kineticState->currentSpeed = initialSpeed; } bool isMoveAction = activeMouseStates[kineticState->upState] || activeMouseStates[kineticState->downState] || activeMouseStates[kineticState->leftState] || activeMouseStates[kineticState->rightState]; mouse_speed_t mouseSpeed = MouseSpeed_Normal; if (activeMouseStates[SerializedMouseAction_Accelerate]) { kineticState->targetSpeed = acceleratedSpeed; mouseSpeed = MouseSpeed_Accelerated; } else if (activeMouseStates[SerializedMouseAction_Decelerate]) { kineticState->targetSpeed = deceleratedSpeed; mouseSpeed = MouseSpeed_Decelerated; } else if (isMoveAction) { kineticState->targetSpeed = baseSpeed; } if (mouseSpeed == MouseSpeed_Accelerated || (kineticState->wasMoveAction && isMoveAction && (kineticState->prevMouseSpeed != mouseSpeed))) { kineticState->currentSpeed = kineticState->targetSpeed; } if (isMoveAction) { if (kineticState->currentSpeed < kineticState->targetSpeed) { kineticState->currentSpeed += acceleration * elapsedTime / 1000; if (kineticState->currentSpeed > kineticState->targetSpeed) { kineticState->currentSpeed = kineticState->targetSpeed; } } else { kineticState->currentSpeed -= acceleration * elapsedTime / 1000; if (kineticState->currentSpeed < kineticState->targetSpeed) { kineticState->currentSpeed = kineticState->targetSpeed; } } float distance = kineticState->currentSpeed * elapsedTime / 1000; if (kineticState->isScroll && !kineticState->wasMoveAction) { kineticState->xSum = 0; kineticState->ySum = 0; } // Update horizontal state bool horizontalMovement = true; if (activeMouseStates[kineticState->leftState]) { kineticState->xSum -= distance; } else if (activeMouseStates[kineticState->rightState]) { kineticState->xSum += distance; } else { horizontalMovement = false; } float xSumInt; float xSumFrac = modff(kineticState->xSum, &xSumInt); kineticState->xSum = xSumFrac; kineticState->xOut = xSumInt; if (kineticState->isScroll && !kineticState->wasMoveAction && kineticState->xOut == 0 && horizontalMovement) { kineticState->xOut = kineticState->xSum > 0 ? 1 : -1; kineticState->xSum = 0; } // Update vertical state bool verticalMovement = true; if (activeMouseStates[kineticState->upState]) { kineticState->ySum -= distance; } else if (activeMouseStates[kineticState->downState]) { kineticState->ySum += distance; } else { verticalMovement = false; } float ySumInt; float ySumFrac = modff(kineticState->ySum, &ySumInt); kineticState->ySum = ySumFrac; kineticState->yOut = ySumInt; if (kineticState->isScroll && !kineticState->wasMoveAction && kineticState->yOut == 0 && verticalMovement) { kineticState->yOut = kineticState->ySum > 0 ? 1 : -1; kineticState->ySum = 0; } } else { kineticState->currentSpeed = 0; } kineticState->prevMouseSpeed = mouseSpeed; kineticState->wasMoveAction = isMoveAction; } void processMouseActions() { processMouseKineticState(&MouseMoveState); ActiveUsbMouseReport->x = MouseMoveState.xOut; ActiveUsbMouseReport->y = MouseMoveState.yOut; MouseMoveState.xOut = 0; MouseMoveState.yOut = 0; processMouseKineticState(&MouseScrollState); ActiveUsbMouseReport->wheelX = MouseScrollState.xOut; ActiveUsbMouseReport->wheelY = MouseScrollState.yOut; MouseScrollState.xOut = 0; MouseScrollState.yOut = 0; // The following line makes the firmware crash for some reason: // SetDebugBufferFloat(60, mouseScrollState.currentSpeed); // TODO: Figure out why. // Oddly, the following line (which is the inlined version of the above) works: // *(float*)(DebugBuffer + 60) = mouseScrollState.currentSpeed; // The value parameter of SetDebugBufferFloat() seems to be the culprit because // if it's not used within the function it doesn't crash anymore. if (activeMouseStates[SerializedMouseAction_LeftClick]) { ActiveUsbMouseReport->buttons |= MouseButton_Left; } if (activeMouseStates[SerializedMouseAction_MiddleClick]) { ActiveUsbMouseReport->buttons |= MouseButton_Middle; } if (activeMouseStates[SerializedMouseAction_RightClick]) { ActiveUsbMouseReport->buttons |= MouseButton_Right; } } static layer_id_t previousLayer = LayerId_Base; static uint8_t basicScancodeIndex = 0; static uint8_t mediaScancodeIndex = 0; static uint8_t systemScancodeIndex = 0; void applyKeyAction(key_state_t *keyState, key_action_t *action) { static key_state_t *doubleTapSwitchLayerKey; static uint32_t doubleTapSwitchLayerStartTime; if (keyState->suppressed) { return; } if (doubleTapSwitchLayerKey && doubleTapSwitchLayerKey != keyState && !keyState->previous) { doubleTapSwitchLayerKey = NULL; } switch (action->type) { case KeyActionType_Keystroke: 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: activeMouseStates[action->mouseAction] = true; break; case KeyActionType_SwitchLayer: if (!keyState->previous && previousLayer == LayerId_Base && action->switchLayer.mode == SwitchLayerMode_HoldAndDoubleTapToggle) { if (doubleTapSwitchLayerKey && Timer_GetElapsedTimeAndSetCurrent(&doubleTapSwitchLayerStartTime) < DoubleTapSwitchLayerTimeout) { ToggledLayer = action->switchLayer.layer; } else { doubleTapSwitchLayerKey = keyState; } doubleTapSwitchLayerStartTime = CurrentTime; } break; case KeyActionType_SwitchKeymap: if (!keyState->previous) { SwitchKeymap(action->switchKeymap.keymapId); } break; } } static uint8_t secondaryRoleState = SecondaryRoleState_Released; static uint8_t secondaryRoleSlotId; static uint8_t secondaryRoleKeyId; static secondary_role_t secondaryRole; #define pos 35 void updateActiveUsbReports(void) { SetDebugBufferUint32(pos, 1); memset(activeMouseStates, 0, ACTIVE_MOUSE_STATES_COUNT); static uint8_t previousModifiers = 0; elapsedTime = Timer_GetElapsedTimeAndSetCurrent(&UsbReportUpdateTime); basicScancodeIndex = 0; mediaScancodeIndex = 0; systemScancodeIndex = 0; for (uint8_t keyId=0; keyId < RIGHT_KEY_MATRIX_KEY_COUNT; keyId++) { KeyStates[SlotId_RightKeyboardHalf][keyId].current = RightKeyMatrix.keyStates[keyId]; } layer_id_t activeLayer = LayerId_Base; if (secondaryRoleState == SecondaryRoleState_Triggered && IS_SECONDARY_ROLE_LAYER_SWITCHER(secondaryRole)) { activeLayer = SECONDARY_ROLE_LAYER_TO_LAYER_ID(secondaryRole); } if (activeLayer == LayerId_Base) { activeLayer = GetActiveLayer(); } bool suppressKeys = previousLayer != LayerId_Base && activeLayer == LayerId_Base; LedDisplay_SetLayer(activeLayer); if (MacroPlaying) { Macros_ContinueMacro(); memcpy(&ActiveUsbMouseReport, &MacroMouseReport, sizeof MacroMouseReport); memcpy(&ActiveUsbBasicKeyboardReport, &MacroBasicKeyboardReport, sizeof MacroBasicKeyboardReport); memcpy(&ActiveUsbMediaKeyboardReport, &MacroMediaKeyboardReport, sizeof MacroMediaKeyboardReport); memcpy(&ActiveUsbSystemKeyboardReport, &MacroSystemKeyboardReport, sizeof MacroSystemKeyboardReport); return; } SetDebugBufferUint32(pos, 2); for (uint8_t slotId=0; slotIddebounceCounter < KEY_DEBOUNCER_TIMEOUT_MSEC) { keyState->current = keyState->previous; } else if (!keyState->previous && keyState->current) { keyState->debounceCounter = 0; } if (keyState->current) { if (suppressKeys) { keyState->suppressed = true; } if (action->type == KeyActionType_Keystroke && action->keystroke.secondaryRole) { // Press released secondary role key. if (!keyState->previous && action->type == KeyActionType_Keystroke && action->keystroke.secondaryRole && secondaryRoleState == SecondaryRoleState_Released) { secondaryRoleState = SecondaryRoleState_Pressed; secondaryRoleSlotId = slotId; secondaryRoleKeyId = keyId; secondaryRole = action->keystroke.secondaryRole; keyState->suppressed = true; } } else { // Trigger secondary role. if (!keyState->previous && secondaryRoleState == SecondaryRoleState_Pressed) { secondaryRoleState = SecondaryRoleState_Triggered; } else { applyKeyAction(keyState, action); } } } else { if (keyState->suppressed) { keyState->suppressed = false; } // Release secondary role key. if (keyState->previous && secondaryRoleSlotId == slotId && secondaryRoleKeyId == keyId) { // Trigger primary role. if (secondaryRoleState == SecondaryRoleState_Pressed) { applyKeyAction(keyState, action); } secondaryRoleState = SecondaryRoleState_Released; } } keyState->previous = keyState->current; } } SetDebugBufferUint32(pos, 4); processMouseActions(); SetDebugBufferUint32(pos, 5); // When a layer switcher key gets pressed along with another key that produces some modifiers // and the accomanying key gets released then keep the related modifiers active a long as the // layer switcher key stays pressed. Useful for Alt+Tab keymappings and the like. if (activeLayer != LayerId_Base && activeLayer == PreviousHeldLayer && basicScancodeIndex == 0) { ActiveUsbBasicKeyboardReport->modifiers |= previousModifiers; } if (secondaryRoleState == SecondaryRoleState_Triggered && IS_SECONDARY_ROLE_MODIFIER(secondaryRole)) { ActiveUsbBasicKeyboardReport->modifiers |= SECONDARY_ROLE_MODIFIER_TO_HID_MODIFIER(secondaryRole); } previousModifiers = ActiveUsbBasicKeyboardReport->modifiers; previousLayer = activeLayer; SetDebugBufferUint32(pos, 7); } bool UsbBasicKeyboardReportEverSent = false; bool UsbMediaKeyboardReportEverSent = false; bool UsbSystemKeyboardReportEverSent = false; bool UsbMouseReportEverSentEverSent = false; uint32_t UsbReportUpdateCounter; static uint32_t lastUsbUpdateTime; void UpdateUsbReports(void) { UsbReportUpdateCounter++; if (Timer_GetElapsedTime(&lastUsbUpdateTime) > 100) { UsbBasicKeyboardReportEverSent = false; UsbMediaKeyboardReportEverSent = false; UsbSystemKeyboardReportEverSent = false; UsbMouseReportEverSentEverSent = false; } if (IsUsbBasicKeyboardReportSent) { UsbBasicKeyboardReportEverSent = true; } if (IsUsbMediaKeyboardReportSent) { UsbMediaKeyboardReportEverSent = true; } if (IsUsbSystemKeyboardReportSent) { UsbSystemKeyboardReportEverSent = true; } if (IsUsbMouseReportSent) { UsbMouseReportEverSentEverSent = true; } bool areUsbReportsSent = true; if (UsbBasicKeyboardReportEverSent) { areUsbReportsSent &= IsUsbBasicKeyboardReportSent; } if (UsbMediaKeyboardReportEverSent) { areUsbReportsSent &= IsUsbMediaKeyboardReportSent; } if (UsbSystemKeyboardReportEverSent) { areUsbReportsSent &= IsUsbSystemKeyboardReportSent; } if (UsbMouseReportEverSentEverSent) { areUsbReportsSent &= IsUsbMouseReportSent; } if (!areUsbReportsSent) { return; } ResetActiveUsbBasicKeyboardReport(); ResetActiveUsbMediaKeyboardReport(); ResetActiveUsbSystemKeyboardReport(); ResetActiveUsbMouseReport(); updateActiveUsbReports(); SwitchActiveUsbBasicKeyboardReport(); SwitchActiveUsbMediaKeyboardReport(); SwitchActiveUsbSystemKeyboardReport(); SwitchActiveUsbMouseReport(); IsUsbBasicKeyboardReportSent = false; IsUsbMediaKeyboardReportSent = false; IsUsbSystemKeyboardReportSent = false; IsUsbMouseReportSent = false; Timer_SetCurrentTime(&lastUsbUpdateTime); }