Parent directory

send_string.c

11266 bytes
  1/* Copyright 2021
  2 *
  3 * This program is free software: you can redistribute it and/or modify
  4 * it under the terms of the GNU General Public License as published by
  5 * the Free Software Foundation, either version 2 of the License, or
  6 * (at your option) any later version.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 * GNU General Public License for more details.
 12 *
 13 * You should have received a copy of the GNU General Public License
 14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 15 */
 16
 17#include "send_string.h"
 18
 19#include <ctype.h>
 20#include <stdlib.h>
 21
 22#include "quantum_keycodes.h"
 23#include "keycode.h"
 24#include "action.h"
 25#include "wait.h"
 26
 27#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL)
 28#    include "audio.h"
 29#    ifndef BELL_SOUND
 30#        define BELL_SOUND TERMINAL_SOUND
 31#    endif
 32float bell_song[][2] = SONG(BELL_SOUND);
 33#endif
 34
 35// clang-format off
 36
 37/* Bit-Packed look-up table to convert an ASCII character to whether
 38 * [Shift] needs to be sent with the keycode.
 39 */
 40__attribute__((weak)) const uint8_t ascii_to_shift_lut[16] PROGMEM = {
 41    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 42    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 43    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 44    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 45
 46    KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 0),
 47    KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0),
 48    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 49    KCLUT_ENTRY(0, 0, 1, 0, 1, 0, 1, 1),
 50    KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
 51    KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
 52    KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
 53    KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 1, 1),
 54    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 55    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 56    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 57    KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0)
 58};
 59
 60/* Bit-Packed look-up table to convert an ASCII character to whether
 61 * [AltGr] needs to be sent with the keycode.
 62 */
 63__attribute__((weak)) const uint8_t ascii_to_altgr_lut[16] PROGMEM = {
 64    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 65    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 66    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 67    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 68
 69    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 70    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 71    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 72    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 73    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 74    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 75    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 76    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 77    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 78    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 79    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 80    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
 81};
 82
 83/* Bit-Packed look-up table to convert an ASCII character to whether
 84 * [Space] needs to be sent after the keycode
 85 */
 86__attribute__((weak)) const uint8_t ascii_to_dead_lut[16] PROGMEM = {
 87    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 88    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 89    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 90    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 91
 92    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 93    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 94    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 95    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 96    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 97    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 98    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 99    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
100    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
101    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
102    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
103    KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0)
104};
105
106/* Look-up table to convert an ASCII character to a keycode.
107 */
108__attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = {
109    // NUL   SOH      STX      ETX      EOT      ENQ      ACK      BEL
110    XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
111    // BS    TAB      LF       VT       FF       CR       SO       SI
112    KC_BSPC, KC_TAB,  KC_ENT,  XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
113    // DLE   DC1      DC2      DC3      DC4      NAK      SYN      ETB
114    XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
115    // CAN   EM       SUB      ESC      FS       GS       RS       US
116    XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC,  XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
117
118    //       !        "        #        $        %        &        '
119    KC_SPC,  KC_1,    KC_QUOT, KC_3,    KC_4,    KC_5,    KC_7,    KC_QUOT,
120    // (     )        *        +        ,        -        .        /
121    KC_9,    KC_0,    KC_8,    KC_EQL,  KC_COMM, KC_MINS, KC_DOT,  KC_SLSH,
122    // 0     1        2        3        4        5        6        7
123    KC_0,    KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,
124    // 8     9        :        ;        <        =        >        ?
125    KC_8,    KC_9,    KC_SCLN, KC_SCLN, KC_COMM, KC_EQL,  KC_DOT,  KC_SLSH,
126    // @     A        B        C        D        E        F        G
127    KC_2,    KC_A,    KC_B,    KC_C,    KC_D,    KC_E,    KC_F,    KC_G,
128    // H     I        J        K        L        M        N        O
129    KC_H,    KC_I,    KC_J,    KC_K,    KC_L,    KC_M,    KC_N,    KC_O,
130    // P     Q        R        S        T        U        V        W
131    KC_P,    KC_Q,    KC_R,    KC_S,    KC_T,    KC_U,    KC_V,    KC_W,
132    // X     Y        Z        [        \        ]        ^        _
133    KC_X,    KC_Y,    KC_Z,    KC_LBRC, KC_BSLS, KC_RBRC, KC_6,    KC_MINS,
134    // `     a        b        c        d        e        f        g
135    KC_GRV,  KC_A,    KC_B,    KC_C,    KC_D,    KC_E,    KC_F,    KC_G,
136    // h     i        j        k        l        m        n        o
137    KC_H,    KC_I,    KC_J,    KC_K,    KC_L,    KC_M,    KC_N,    KC_O,
138    // p     q        r        s        t        u        v        w
139    KC_P,    KC_Q,    KC_R,    KC_S,    KC_T,    KC_U,    KC_V,    KC_W,
140    // x     y        z        {        |        }        ~        DEL
141    KC_X,    KC_Y,    KC_Z,    KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV,  KC_DEL
142};
143
144// clang-format on
145
146// Note: we bit-pack in "reverse" order to optimize loading
147#define PGM_LOADBIT(mem, pos) ((pgm_read_byte(&((mem)[(pos) / 8])) >> ((pos) % 8)) & 0x01)
148
149void send_string(const char *string) {
150    send_string_with_delay(string, TAP_CODE_DELAY);
151}
152
153void send_string_with_delay(const char *string, uint8_t interval) {
154    while (1) {
155        char ascii_code = *string;
156        if (!ascii_code) break;
157        if (ascii_code == SS_QMK_PREFIX) {
158            ascii_code = *(++string);
159
160            if (ascii_code == SS_TAP_CODE) {
161                // tap
162                uint8_t keycode = *(++string);
163                tap_code(keycode);
164            } else if (ascii_code == SS_DOWN_CODE) {
165                // down
166                uint8_t keycode = *(++string);
167                register_code(keycode);
168            } else if (ascii_code == SS_UP_CODE) {
169                // up
170                uint8_t keycode = *(++string);
171                unregister_code(keycode);
172            } else if (ascii_code == SS_DELAY_CODE) {
173                // delay
174                int     ms      = 0;
175                uint8_t keycode = *(++string);
176
177                while (isdigit(keycode)) {
178                    ms *= 10;
179                    ms += keycode - '0';
180                    keycode = *(++string);
181                }
182
183                wait_ms(ms);
184            }
185
186            wait_ms(interval);
187        } else {
188            send_char_with_delay(ascii_code, interval);
189        }
190
191        ++string;
192    }
193}
194
195void send_char(char ascii_code) {
196    send_char_with_delay(ascii_code, TAP_CODE_DELAY);
197}
198
199void send_char_with_delay(char ascii_code, uint8_t interval) {
200#if defined(AUDIO_ENABLE) && defined(SENDSTRING_BELL)
201    if (ascii_code == '\a') { // BEL
202        PLAY_SONG(bell_song);
203        return;
204    }
205#endif
206
207    uint8_t keycode    = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]);
208    bool    is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code);
209    bool    is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code);
210    bool    is_dead    = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code);
211
212    if (is_shifted) {
213        register_code(KC_LEFT_SHIFT);
214        wait_ms(interval);
215    }
216
217    if (is_altgred) {
218        register_code(KC_RIGHT_ALT);
219        wait_ms(interval);
220    }
221
222    tap_code_delay(keycode, interval);
223    wait_ms(interval);
224
225    if (is_altgred) {
226        unregister_code(KC_RIGHT_ALT);
227        wait_ms(interval);
228    }
229
230    if (is_shifted) {
231        unregister_code(KC_LEFT_SHIFT);
232        wait_ms(interval);
233    }
234
235    if (is_dead) {
236        tap_code(KC_SPACE);
237        wait_ms(interval);
238    }
239}
240
241void send_dword(uint32_t number) {
242    send_word(number >> 16);
243    send_word(number & 0xFFFFUL);
244}
245
246void send_word(uint16_t number) {
247    send_byte(number >> 8);
248    send_byte(number & 0xFF);
249}
250
251void send_byte(uint8_t number) {
252    send_nibble(number >> 4);
253    send_nibble(number & 0xF);
254}
255
256void send_nibble(uint8_t number) {
257    switch (number & 0xF) {
258        case 0 ... 9:
259            send_char(number + '0');
260            break;
261        case 10 ... 15:
262            send_char(number - 10 + 'a');
263            break;
264    }
265}
266
267void tap_random_base64(void) {
268#if defined(__AVR_ATmega32U4__)
269    uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64;
270#else
271    uint8_t key = rand() % 64;
272#endif
273    switch (key) {
274        case 0 ... 25:
275            send_char(key + 'A');
276            break;
277        case 26 ... 51:
278            send_char(key - 26 + 'a');
279            break;
280        case 52:
281            send_char('0');
282            break;
283        case 53 ... 61:
284            send_char(key - 53 + '1');
285            break;
286        case 62:
287            send_char('+');
288            break;
289        case 63:
290            send_char('/');
291            break;
292    }
293}
294
295#if defined(__AVR__)
296void send_string_P(const char *string) {
297    send_string_with_delay_P(string, TAP_CODE_DELAY);
298}
299
300void send_string_with_delay_P(const char *string, uint8_t interval) {
301    while (1) {
302        char ascii_code = pgm_read_byte(string);
303        if (!ascii_code) break;
304        if (ascii_code == SS_QMK_PREFIX) {
305            ascii_code = pgm_read_byte(++string);
306
307            if (ascii_code == SS_TAP_CODE) {
308                // tap
309                uint8_t keycode = pgm_read_byte(++string);
310                tap_code(keycode);
311            } else if (ascii_code == SS_DOWN_CODE) {
312                // down
313                uint8_t keycode = pgm_read_byte(++string);
314                register_code(keycode);
315            } else if (ascii_code == SS_UP_CODE) {
316                // up
317                uint8_t keycode = pgm_read_byte(++string);
318                unregister_code(keycode);
319            } else if (ascii_code == SS_DELAY_CODE) {
320                // delay
321                int     ms      = 0;
322                uint8_t keycode = pgm_read_byte(++string);
323
324                while (isdigit(keycode)) {
325                    ms *= 10;
326                    ms += keycode - '0';
327                    keycode = pgm_read_byte(++string);
328                }
329                wait_ms(ms);
330            }
331        } else {
332            send_char_with_delay(ascii_code, interval);
333        }
334
335        ++string;
336    }
337}
338#endif