Skip to content

Haptic Feedback

Haptic feedback options

The following options are currently available for haptic feedback in


HAPTIC_DRIVER = drv2605l
# or
HAPTIC_DRIVER = solenoid

The following config.h settings are available for all types of haptic feedback:

HAPTIC_ENABLE_PINNot definedConfigures a pin to enable a boost converter for some haptic solution, often used with solenoid drivers.
HAPTIC_ENABLE_PIN_ACTIVE_LOWNot definedIf defined then the haptic enable pin is active-low.
HAPTIC_ENABLE_STATUS_LEDNot definedConfigures a pin to reflect the current enabled/disabled status of haptic feedback.
HAPTIC_ENABLE_STATUS_LED_ACTIVE_LOWNot definedIf defined then the haptic status led will be active-low.
HAPTIC_OFF_IN_LOW_POWER0If set to 1, haptic feedback is disabled before the device is configured, and while the device is suspended.

Known Supported Hardware

LV061228B-L65-Az-axis 2v LRA
Mini Motor Discsmall 2-5v ERM

Haptic Keycodes

Not all keycodes below will work depending on which haptic mechanism you have chosen.

QK_HAPTIC_ONHF_ONTurn haptic feedback on
QK_HAPTIC_OFFHF_OFFTurn haptic feedback off
QK_HAPTIC_TOGGLEHF_TOGGToggle haptic feedback on/off
QK_HAPTIC_RESETHF_RSTReset haptic feedback config to default
QK_HAPTIC_FEEDBACK_TOGGLEHF_FDBKToggle feedback to occur on keypress, release or both
QK_HAPTIC_BUZZ_TOGGLEHF_BUZZToggle solenoid buzz on/off
QK_HAPTIC_MODE_NEXTHF_NEXTGo to next DRV2605L waveform
QK_HAPTIC_MODE_PREVIOUSHF_PREVGo to previous DRV2605L waveform
QK_HAPTIC_CONTINUOUS_TOGGLEHF_CONTToggle continuous haptic mode on/off
QK_HAPTIC_CONTINUOUS_UPHF_CONUIncrease DRV2605L continous haptic strength
QK_HAPTIC_CONTINUOUS_DOWNHF_CONDDecrease DRV2605L continous haptic strength
QK_HAPTIC_DWELL_UPHF_DWLUIncrease Solenoid dwell time
QK_HAPTIC_DWELL_DOWNHF_DWLDDecrease Solenoid dwell time


The solenoid code supports relay switches, and similar hardware, as well as solenoids.

For a regular solenoid, you will need a build a circuit to drive the solenoid through a mosfet as most MCU will not be able to provide the current needed to drive the coil in the solenoid.

Wiring diagram provided by Adafruit

For relay switches, the hardware may already contain all of that ciruitry, and just require VCC, GND and a data pin.

SOLENOID_PINNot definedConfigures the pin that the switch is connected to.
SOLENOID_PIN_ACTIVE_LOWNot definedIf defined then the switch trigger pin is active low.
SOLENOID_PINSNot definedConfigures an array of pins to be used for switch activation.
SOLENOID_PINS_ACTIVE_LOWNot definedAllows you to specify how each pin is pulled for activation.
SOLENOID_RANDOM_FIRENot definedWhen there are multiple solenoids, will select a random one to fire.
SOLENOID_DEFAULT_DWELL12 msConfigures the default dwell time for the switch.
SOLENOID_MIN_DWELL4 msSets the lower limit for the dwell.
SOLENOID_MAX_DWELL100 msSets the upper limit for the dwell.
SOLENOID_DWELL_STEP_SIZE1 msThe step size to use when HF_DWL* keycodes are sent.
SOLENOID_DEFAULT_BUZZ0 (disabled)On HF_RST buzz is set "on" if this is "1"
SOLENOID_BUZZ_ACTUATEDSOLENOID_MIN_DWELLActuated-time when the switch is in buzz mode.
SOLENOID_BUZZ_NONACTUATEDSOLENOID_MIN_DWELLNon-Actuated-time when the switch is in buzz mode.
  • If solenoid buzz is off, then dwell time is how long the "plunger" stays activated. The dwell time changes how the solenoid sounds.
  • If solenoid buzz is on, then dwell time sets the length of the buzz, while SOLENOID_BUZZ_ACTUATED and SOLENOID_BUZZ_NONACTUATED set the (non-)actuation times withing the buzz period.
  • With the current implementation, for any of the above time settings, the precision of these settings may be affected by how fast the keyboard is able to scan the matrix. Therefore, if the keyboards scanning routine is slow, it may be preferable to set SOLENOID_DWELL_STEP_SIZE to a value slightly smaller than the time it takes to scan the keyboard.

Beware that some pins may be powered during bootloader (ie. A13 on the STM32F303 chip) and will result in the solenoid kept in the on state through the whole flashing process. This may overheat and damage the solenoid. If you find that the pin the solenoid is connected to is triggering the solenoid during bootloader/DFU, select another pin.


DRV2605L is controlled over i2c protocol, and has to be connected to the SDA and SCL pins, these varies depending on the MCU in use.

Feedback motor setup

This driver supports 2 different feedback motors. Set the following in your config.h based on which motor you have selected.


Eccentric Rotating Mass vibration motors (ERM) is motor with a off-set weight attached so when drive signal is attached, the off-set weight spins and causes a sinusoidal wave that translate into vibrations.

#define DRV2605L_FB_ERM_LRA 0
#define DRV2605L_FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
#define DRV2605L_FB_LOOPGAIN 1 /* For  Low:0, Medium:1, High:2, Very High:3 */

/* Please refer to your datasheet for the optimal setting for your specific motor. */
#define DRV2605L_RATED_VOLTAGE 3
#define DRV2605L_V_PEAK 5

Linear resonant actuators (LRA, also know as a linear vibrator) works different from a ERM. A LRA has a weight and magnet suspended by springs and a voice coil. When the drive signal is applied, the weight would be vibrate on a single axis (side to side or up and down). Since the weight is attached to a spring, there is a resonance effect at a specific frequency. This frequency is where the LRA will operate the most efficiently. Refer to the motor's datasheet for the recommanded range for this frequency.

#define DRV2605L_FB_ERM_LRA 1
#define DRV2605L_FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
#define DRV2605L_FB_LOOPGAIN 1 /* For  Low:0, Medium:1, High:2, Very High:3 */

/* Please refer to your datasheet for the optimal setting for your specific motor. */
#define DRV2605L_RATED_VOLTAGE 2
#define DRV2605L_V_PEAK 2.8
#define DRV2605L_V_RMS 2.0 
#define DRV2605L_V_PEAK 2.1
#define DRV2605L_F_LRA 205 /* resonance freq */

DRV2605L waveform library

DRV2605L comes with preloaded library of various waveform sequences that can be called and played. If writing a macro, these waveforms can be played using DRV_pulse(*sequence name or number*)

List of waveform sequences from the datasheet:

seq#Sequence nameseq#Sequence nameseq#Sequence name

Optional DRV2605L defines

#define DRV2605L_GREETING *sequence name or number*

If haptic feedback is enabled, the keyboard will vibrate to a specific sequence during startup. That can be selected using the following define:

#define DRV2605L_DEFAULT_MODE *sequence name or number*

This will set what sequence HF_RST will set as the active mode. If not defined, mode will be set to 1 when HF_RST is pressed.

DRV2605L Continuous Haptic Mode

This mode sets continuous haptic feedback with the option to increase or decrease strength.

Haptic Key Exclusion

The Haptic Exclusion is implemented as __attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record) in haptic.c. This allows a re-definition at the required level with the specific requirement / exclusion.


With the entry of #define NO_HAPTIC_MOD in config.h, the following keys will not trigger feedback:

  • Usual modifier keys such as Control/Shift/Alt/Gui (For example KC_LCTL)
  • MO() momentary keys. See also Layers.
  • LM() momentary keys with mod active.
  • LT() layer tap keys, when held to activate a layer. However when tapped, and the key is quickly released, and sends a keycode, haptic feedback is still triggered.
  • TT() layer tap toggle keys, when held to activate a layer. However when tapped TAPPING_TOGGLE times to permanently toggle the layer, on the last tap haptic feedback is still triggered.
  • MT() mod tap keys, when held to keep a usual modifier key pressed. However when tapped, and the key is quickly released, and sends a keycode, haptic feedback is still triggered. See also Mod-Tap.


With the entry of #define NO_HAPTIC_ALPHA in config.h, none of the alpha keys (A ... Z) will trigger a feedback.


With the entry of #define NO_HAPTIC_PUNCTUATION in config.h, none of the following keys will trigger a feedback: Enter, ESC, Backspace, Space, Minus, Equal, Left Bracket, Right Bracket, Backslash, Non-US Hash, Semicolon, Quote, Grave, Comma, Slash, Dot, Non-US Backslash.


With the entry of #define NO_HAPTIC_LOCKKEYS in config.h, none of the following keys will trigger a feedback: Caps Lock, Scroll Lock, Num Lock.


With the entry of #define NO_HAPTIC_NAV in config.h, none of the following keys will trigger a feedback: Print Screen, Pause, Insert, Delete, Page Down, Page Up, Left Arrow, Up Arrow, Right Arrow, Down Arrow, End, Home.


With the entry of #define NO_HAPTIC_NUMERIC in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback.