summaryrefslogtreecommitdiffstats
path: root/quantum/process_keycode/process_tap_dance.c
blob: 097440405cf9e88e5762a87dcdc2a2f747e4cfe1 (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
#include "quantum.h"

static qk_tap_dance_state_t qk_tap_dance_state;

static void _process_tap_dance_action_pair (qk_tap_dance_state_t *state,
                                            uint16_t kc1, uint16_t kc2) {
  uint16_t kc;

  if (state->count == 0)
    return;

  kc = (state->count == 1) ? kc1 : kc2;

  register_code (kc);
  unregister_code (kc);

  if (state->count >= 2) {
    reset_tap_dance (state);
  }
}

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

void process_tap_dance_action_on_each_tap (uint16_t keycode)
{
  uint16_t idx = keycode - QK_TAP_DANCE;
  qk_tap_dance_action_t action;

  action = tap_dance_actions[idx];

  switch (action.type) {
  case QK_TAP_DANCE_TYPE_FN:
    _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn.on_each_tap);
    break;

  default:
    break;
  }
}

void process_tap_dance_action_on_dance_finished (uint16_t keycode)
{
  uint16_t idx = keycode - QK_TAP_DANCE;
  qk_tap_dance_action_t action;

  action = tap_dance_actions[idx];

  switch (action.type) {
  case QK_TAP_DANCE_TYPE_PAIR:
    _process_tap_dance_action_pair (&qk_tap_dance_state,
                                    action.pair.kc1, action.pair.kc2);
    break;
  case QK_TAP_DANCE_TYPE_FN:
    _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn.on_dance_finished);
    break;

  default:
    break;
  }
}

bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
  bool r = true;

  switch(keycode) {
  case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
    process_tap_dance_action_on_each_tap (qk_tap_dance_state.keycode);
    if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) {
      process_tap_dance_action_on_dance_finished (qk_tap_dance_state.keycode);
    } else if (qk_tap_dance_state.active && qk_tap_dance_state.pressed) {
      reset_tap_dance (&qk_tap_dance_state);
    } else {
      r = false;
    }

    qk_tap_dance_state.active = true;
    qk_tap_dance_state.pressed = record->event.pressed;
    if (record->event.pressed) {
      qk_tap_dance_state.keycode = keycode;
      qk_tap_dance_state.timer = timer_read ();
      qk_tap_dance_state.count++;
    }
    break;

  default:
    if (qk_tap_dance_state.keycode) {
      // if we are here, the tap dance was interrupted by a different key
      process_tap_dance_action_on_each_tap (qk_tap_dance_state.keycode);
      process_tap_dance_action_on_dance_finished (qk_tap_dance_state.keycode);
      reset_tap_dance (&qk_tap_dance_state);
      qk_tap_dance_state.active = false;
    }
    break;
  }

  return r;
}

void matrix_scan_tap_dance () {
  if (qk_tap_dance_state.active && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) {
    // if we are here, the tap dance was timed out
    process_tap_dance_action_on_dance_finished (qk_tap_dance_state.keycode);
    reset_tap_dance (&qk_tap_dance_state);
  }
}

void reset_tap_dance (qk_tap_dance_state_t *state) {
  uint16_t idx = state->keycode - QK_TAP_DANCE;
  qk_tap_dance_action_t action;

  if (state->pressed)
    return;

  action = tap_dance_actions[idx];
  switch (action.type) {
  case QK_TAP_DANCE_TYPE_FN:
    if (action.fn.on_reset) {
      action.fn.on_reset(state);
    }
    break;

  default:
    break;
  }

  state->keycode = 0;
  state->count = 0;
  state->active = false;
}