Skip to content

Haptic Feedback

Haptic feedback rules.mk options

The following options are currently available for haptic feedback in rules.mk:

make
HAPTIC_ENABLE = yes

HAPTIC_DRIVER = drv2605l
# or
HAPTIC_DRIVER = solenoid

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

SettingsDefaultDescription
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

NameDescription
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.

KeyAliasesDescription
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

Solenoids

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.

SettingsDefaultDescription
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

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.

ERM

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.

c
#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
LRA

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.

c
#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
1strong_click43lg_dblclick_med_6085transition_rampup_med_smooth2
2strong_click_6044lg_dblsharp_tick86transition_rampup_short_smooth1
3strong_click_3045lg_dblsharp_tick_8087transition_rampup_short_smooth2
4sharp_click46lg_dblsharp_tick_6088transition_rampup_long_sharp1
5sharp_click_6047buzz89transition_rampup_long_sharp2
6sharp_click_3048buzz_8090transition_rampup_med_sharp1
7soft_bump49buzz_6091transition_rampup_med_sharp2
8soft_bump_6050buzz_4092transition_rampup_short_sharp1
9soft_bump_3051buzz_2093transition_rampup_short_sharp2
10dbl_click52pulsing_strong94transition_rampdown_long_smooth1_50
11dbl_click_6053pulsing_strong_8095transition_rampdown_long_smooth2_50
12trp_click54pulsing_medium96transition_rampdown_med_smooth1_50
13soft_fuzz55pulsing_medium_8097transition_rampdown_med_smooth2_50
14strong_buzz56pulsing_sharp98transition_rampdown_short_smooth1_50
15alert_750ms57pulsing_sharp_8099transition_rampdown_short_smooth2_50
16alert_1000ms58transition_click100transition_rampdown_long_sharp1_50
17strong_click159transition_click_80101transition_rampdown_long_sharp2_50
18strong_click2_8060transition_click_60102transition_rampdown_med_sharp1_50
19strong_click3_6061transition_click_40103transition_rampdown_med_sharp2_50
20strong_click4_3062transition_click_20104transition_rampdown_short_sharp1_50
21medium_click163transition_click_10105transition_rampdown_short_sharp2_50
22medium_click2_8064transition_hum106transition_rampup_long_smooth1_50
23medium_click3_6065transition_hum_80107transition_rampup_long_smooth2_50
24sharp_tick166transition_hum_60108transition_rampup_med_smooth1_50
25sharp_tick2_8067transition_hum_40109transition_rampup_med_smooth2_50
26sharp_tick3_6068transition_hum_20110transition_rampup_short_smooth1_50
27sh_dblclick_str69transition_hum_10111transition_rampup_short_smooth2_50
28sh_dblclick_str_8070transition_rampdown_long_smooth1112transition_rampup_long_sharp1_50
29sh_dblclick_str_6071transition_rampdown_long_smooth2113transition_rampup_long_sharp2_50
30sh_dblclick_str_3072transition_rampdown_med_smooth1114transition_rampup_med_sharp1_50
31sh_dblclick_med73transition_rampdown_med_smooth2115transition_rampup_med_sharp2_50
32sh_dblclick_med_8074transition_rampdown_short_smooth1116transition_rampup_short_sharp1_50
33sh_dblclick_med_6075transition_rampdown_short_smooth2117transition_rampup_short_sharp2_50
34sh_dblsharp_tick76transition_rampdown_long_sharp1118long_buzz_for_programmatic_stopping
35sh_dblsharp_tick_8077transition_rampdown_long_sharp2119smooth_hum1_50
36sh_dblsharp_tick_6078transition_rampdown_med_sharp1120smooth_hum2_40
37lg_dblclick_str79transition_rampdown_med_sharp2121smooth_hum3_30
38lg_dblclick_str_8080transition_rampdown_short_sharp1122smooth_hum4_20
39lg_dblclick_str_6081transition_rampdown_short_sharp2123smooth_hum5_10
40lg_dblclick_str_3082transition_rampup_long_smooth1
41lg_dblclick_med83transition_rampup_long_smooth2
42lg_dblclick_med_8084transition_rampup_med_smooth1

Optional DRV2605L defines

c
#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:

c
#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.

NO_HAPTIC_MOD

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.

NO_HAPTIC_ALPHA

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

NO_HAPTIC_PUNCTUATION

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.

NO_HAPTIC_LOCKKEYS

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.

NO_HAPTIC_NAV

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.

NO_HAPTIC_NUMERIC

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.