aboutsummaryrefslogtreecommitdiffstats
path: root/quantum/process_keycode/process_tap_dance.c
blob: 403dca5380dfe14894b6e8eb838f9cdb088ea789 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "quantum.h"
#include "action_tapping.h"

static uint16_t last_td;
static int8_t highest_td = -1;

void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;

  if (state->count == 1) {
    register_code16 (pair->kc1);
  } else if (state->count == 2) {
    register_code16 (pair->kc2);
  }
}

void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;

  if (state->count == 1) {
    unregister_code16 (pair->kc1);
  } else if (state->count == 2) {
    unregister_code16 (pair->kc2);
  }
}

static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
                                                 void *user_data,
                                                 qk_tap_dance_user_fn_t fn)
{
  if (fn) {
    fn(state, user_data);
  }
}

static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t *action)
{
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_each_tap);
}

static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t *action)
{
  if (action->state.finished)
    return;
  action->state.finished = true;
  add_mods(action->state.oneshot_mods);
  send_keyboard_report();
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished);
}

static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action)
{
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset);
  del_mods(action->state.oneshot_mods);
  send_keyboard_report();
}

bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
  uint16_t idx = keycode - QK_TAP_DANCE;
  qk_tap_dance_action_t *action;

  if (last_td && last_td != keycode) {
    (&tap_dance_actions[last_td - QK_TAP_DANCE])->state.interrupted = true;
  }

  switch(keycode) {
  case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
    if ((int16_t)idx > highest_td)
      highest_td = idx;
    action = &tap_dance_actions[idx];

    action->state.pressed = record->event.pressed;
    if (record->event.pressed) {
      action->state.keycode = keycode;
      action->state.count++;
      action->state.timer = timer_read();
      action->state.oneshot_mods = get_oneshot_mods();
      process_tap_dance_action_on_each_tap (action);

      if (last_td && last_td != keycode) {
        qk_tap_dance_action_t *paction = &tap_dance_actions[last_td - QK_TAP_DANCE];
        paction->state.interrupted = true;
        process_tap_dance_action_on_dance_finished (paction);
        reset_tap_dance (&paction->state);
      }

      last_td = keycode;
    }

    break;

  default:
    if (!record->event.pressed)
      return true;

    if (highest_td == -1)
      return true;

    for (int i = 0; i <= highest_td; i++) {
      action = &tap_dance_actions[i];
      if (action->state.count == 0)
        continue;
      action->state.interrupted = true;
      process_tap_dance_action_on_dance_finished (action);
      reset_tap_dance (&action->state);
    }
    break;
  }

  return true;
}

void matrix_scan_tap_dance () {
  if (highest_td == -1)
    return;

for (int i = 0; i <= highest_td; i++) {
    qk_tap_dance_action_t *action = &tap_dance_actions[i];

    if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) {
      process_tap_dance_action_on_dance_finished (action);
      reset_tap_dance (&action->state);
    }
  }
}

void reset_tap_dance (qk_tap_dance_state_t *state) {
  qk_tap_dance_action_t *action;

  if (state->pressed)
    return;

  action = &tap_dance_actions[state->keycode - QK_TAP_DANCE];

  process_tap_dance_action_on_reset (action);

  state->count = 0;
  state->interrupted = false;
  state->finished = false;
  last_td = 0;
}
="c1">// electric arrow - not compliant with obdev's rules but we'll have our own vid-pid soon //#define USB_CFG_VENDOR_NAME 0x2301 //#define USB_CFG_VENDOR_NAME_LEN 1 //#define USB_CFG_VENDOR_NAME 'd','i','g','i','s','t','u','m','p','.','c','o','m' //#define USB_CFG_VENDOR_NAME_LEN 13 /* These two values define the vendor name returned by the USB device. The name * must be given as a list of characters under single quotes. The characters * are interpreted as Unicode (UTF-16) entities. * If you don't want a vendor name string, undefine these macros. * ALWAYS define a vendor name containing your Internet domain name if you use * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for * details. */ //#define USB_CFG_DEVICE_NAME 0x00B5,'B' //#define USB_CFG_DEVICE_NAME_LEN 2 /* Same as above for the device name. If you don't want a device name, undefine * the macros. See the file USB-IDs-for-free.txt before you assign a name if * you use a shared VID/PID. */ /*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ /*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ /* Same as above for the serial number. If you don't want a serial number, * undefine the macros. * It may be useful to provide the serial number through other means than at * compile time. See the section about descriptor properties below for how * to fine tune control over USB descriptors such as the string descriptor * for the serial number. */ #define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ #define USB_CFG_DEVICE_SUBCLASS 0 //#define USB_CFG_DEVICE_CLASS 0xFE /* application specific */ //#define USB_CFG_DEVICE_SUBCLASS 0x01 /* device firmware upgrade */ /* See USB specification if you want to conform to an existing device class. * Class 0xff is "vendor specific". */ #define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ #define USB_CFG_INTERFACE_SUBCLASS 0 #define USB_CFG_INTERFACE_PROTOCOL 0 /* See USB specification if you want to conform to an existing device class or * protocol. The following classes must be set at interface level: * HID class is 3, no subclass and protocol required (but may be useful!) * CDC class is 2, use subclass 2 and protocol 1 for ACM */ /* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */ /* Define this to the length of the HID report descriptor, if you implement * an HID device. Otherwise don't define it or define it to 0. * If you use this define, you must add a PROGMEM character array named * "usbHidReportDescriptor" to your code which contains the report descriptor. * Don't forget to keep the array and this define in sync! */ #define USB_PUBLIC static /* Use the define above if you #include usbdrv.c instead of linking against it. * This technique saves a couple of bytes in flash memory. */ /* ------------------- Fine Control over USB Descriptors ------------------- */ /* If you don't want to use the driver's default USB descriptors, you can * provide our own. These can be provided as (1) fixed length static data in * flash memory, (2) fixed length static data in RAM or (3) dynamically at * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more * information about this function. * Descriptor handling is configured through the descriptor's properties. If * no properties are defined or if they are 0, the default descriptor is used. * Possible properties are: * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if * you want RAM pointers. * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found * in static memory is in RAM, not in flash memory. * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), * the driver must know the descriptor's length. The descriptor itself is * found at the address of a well known identifier (see below). * List of static descriptor names (must be declared PROGMEM if in flash): * char usbDescriptorDevice[]; * char usbDescriptorConfiguration[]; * char usbDescriptorHidReport[]; * char usbDescriptorString0[]; * int usbDescriptorStringVendor[]; * int usbDescriptorStringDevice[]; * int usbDescriptorStringSerialNumber[]; * Other descriptors can't be provided statically, they must be provided * dynamically at runtime. * * Descriptor properties are or-ed or added together, e.g.: * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) * * The following descriptors are defined: * USB_CFG_DESCR_PROPS_DEVICE * USB_CFG_DESCR_PROPS_CONFIGURATION * USB_CFG_DESCR_PROPS_STRINGS * USB_CFG_DESCR_PROPS_STRING_0 * USB_CFG_DESCR_PROPS_STRING_VENDOR * USB_CFG_DESCR_PROPS_STRING_PRODUCT * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER * USB_CFG_DESCR_PROPS_HID * USB_CFG_DESCR_PROPS_HID_REPORT * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) * * Note about string descriptors: String descriptors are not just strings, they * are Unicode strings prefixed with a 2 byte header. Example: * int serialNumberDescriptor[] = { * USB_STRING_DESCRIPTOR_HEADER(6), * 'S', 'e', 'r', 'i', 'a', 'l' * }; */ #define USB_CFG_DESCR_PROPS_DEVICE 0 #define USB_CFG_DESCR_PROPS_CONFIGURATION 0 #define USB_CFG_DESCR_PROPS_STRINGS 0 #define USB_CFG_DESCR_PROPS_STRING_0 0 #define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 #define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 #define USB_CFG_DESCR_PROPS_HID 0 #define USB_CFG_DESCR_PROPS_HID_REPORT 0 #define USB_CFG_DESCR_PROPS_UNKNOWN 0 #endif /* __usbconfig_h_included__ */