]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
Updates send_string functionality, adds terminal feature (#1657)
authorJack Humbert <jack.humb@gmail.com>
Tue, 12 Sep 2017 04:43:10 +0000 (00:43 -0400)
committerGitHub <noreply@github.com>
Tue, 12 Sep 2017 04:43:10 +0000 (00:43 -0400)
* implement basic terminal stuff

* modify send_string to read normal strings too

* add files bc yeah. working pgm detected

* pgm detection apparently not working

* adds send string keycodes, additional keycode support in send string

* implement arguments

* [terminal] add help command

* [terminal] adds keycode and keymap functions

* [terminal] adds nop.h, documentation

* update macro docs

14 files changed:
common_features.mk
docs/_summary.md
docs/feature_terminal.md [new file with mode: 0644]
docs/macros.md
keyboards/planck/keymaps/default/keymap.c
keyboards/planck/rules.mk
quantum/audio/song_list.h
quantum/process_keycode/process_terminal.c [new file with mode: 0644]
quantum/process_keycode/process_terminal.h [new file with mode: 0644]
quantum/process_keycode/process_terminal_nop.h [new file with mode: 0644]
quantum/quantum.c
quantum/quantum.h
quantum/quantum_keycodes.h
quantum/send_string_keycodes.h [new file with mode: 0644]

index f405d5c07b92bb767aa0c171a20d9e818c44e8cb..d499d1f0b7093610deb3d8aa54d5b021fc03f7b7 100644 (file)
@@ -153,6 +153,11 @@ ifeq ($(strip $(LED_TABLES)), yes)
     SRC += $(QUANTUM_DIR)/led_tables.c
 endif
 
+ifeq ($(strip $(TERMINAL_ENABLE)), yes)
+    SRC += $(QUANTUM_DIR)/process_keycode/process_terminal.c
+    OPT_DEFS += -DTERMINAL_ENABLE
+endif
+
 QUANTUM_SRC:= \
     $(QUANTUM_DIR)/quantum.c \
     $(QUANTUM_DIR)/keymap_common.c \
index 77d208fc3cd0ae611c12472e22aef704f53c0730..ce02220fbf2c2c0fed982ac87ce6f1ff83d58c29 100644 (file)
@@ -28,6 +28,7 @@
   * [Thermal Printer](feature_thermal_printer.md)
   * [Stenography](stenography.md)
   * [Unicode](unicode.md)
+  * [Terminal](feature_terminal.md)
 
 * Reference
   * [Glossary](glossary.md)
diff --git a/docs/feature_terminal.md b/docs/feature_terminal.md
new file mode 100644 (file)
index 0000000..2c5f2c4
--- /dev/null
@@ -0,0 +1,80 @@
+# Terminal
+
+> This feature is currently *huge* at 4400 bytes, and should probably only be put on boards with a lot of memory, or for fun.
+
+The terminal feature is a command-line-like interface designed to communicate through a text editor with keystrokes. It's beneficial to turn off auto-indent features in your editor.
+
+To enable, stick this in your `rules.mk` or `Makefile`:
+
+    TERMINAL_ENABLE = yes
+
+And use the `TERM_ON` and `TERM_OFF` keycodes to turn it on or off.
+
+When enabled, a `> ` prompt will appear, where you'll be able to type, backspace (a bell will ding if you reach the beginning and audio is enabled), and hit enter to send the command. Arrow keys are currently disabled so it doesn't get confused. Moving your cursor around with the mouse is discouraged.
+
+`#define TERMINAL_HELP` enables some other output helpers that aren't really needed with this page.
+
+## Future ideas
+
+* Keyboard/user-extendable commands
+* Smaller footprint
+* Arrow key support
+* Command history
+* SD card support
+* LCD support for buffer display
+* Keycode -> name string LUT
+* Layer status
+* *Analog/digital port read/write*
+* RGB mode stuff
+* Macro definitions
+* EEPROM read/write
+* Audio control
+
+## Current commands
+
+### `about`
+
+Prints out the current version of QMK with a build date:
+
+```
+> about
+QMK Firmware
+  v0.5.115-7-g80ed73-dirty
+  Built: 2017-08-29-20:24:44
+```
+
+### `help`
+
+Prints out the available commands:
+
+```
+> help
+commands available:
+  about help keycode keymap exit
+```
+
+### `keycode <layer> <row> <col>`
+
+Prints out the keycode value of a certain layer, row, and column:
+
+```
+> keycode 0 1 0
+0x29 (41)
+```
+
+### `keymap <layer>`
+
+Prints out the entire keymap for a certain layer
+
+```
+> keymap 0
+0x002b, 0x0014, 0x001a, 0x0008, 0x0015, 0x0017, 0x001c, 0x0018, 0x000c, 0x0012, 0x0013, 0x002a, 
+0x0029, 0x0004, 0x0016, 0x0007, 0x0009, 0x000a, 0x000b, 0x000d, 0x000e, 0x000f, 0x0033, 0x0034, 
+0x00e1, 0x001d, 0x001b, 0x0006, 0x0019, 0x0005, 0x0011, 0x0010, 0x0036, 0x0037, 0x0038, 0x0028, 
+0x5cd6, 0x00e0, 0x00e2, 0x00e3, 0x5cd4, 0x002c, 0x002c, 0x5cd5, 0x0050, 0x0051, 0x0052, 0x004f,
+> 
+```
+
+### `exit`
+
+Exits the terminal - same as `TERM_OFF`.
\ No newline at end of file
index c7a9b2e7a6f2e9f86e4fd66344ba6cda515efe7b..66d2bc090a84002f717c0f07e44ca37e41a69623 100644 (file)
 # Macros
 
-Macros allow you to send multiple keystrokes when pressing just one key. QMK has a number of ways to define and use macros. These can do anything you want- type common phrases for you, copypasta, repetitive game movements, or even help you code. 
+Macros allow you to send multiple keystrokes when pressing just one key. QMK has a number of ways to define and use macros. These can do anything you want: type common phrases for you, copypasta, repetitive game movements, or even help you code. 
 
 {% hint style='danger' %}
 **Security Note**: While it is possible to use macros to send passwords, credit card numbers, and other sensitive information it is a supremely bad idea to do so. Anyone who gets ahold of your keyboard will be able to access that information by opening a text editor.
 {% endhint %}
 
-# Macro Definitions
+## The new way: `SEND_STRING()` & `process_record_user`
 
-By default QMK assumes you don't have any macros. To define your macros you create an `action_get_macro()` function. For example:
+Sometimes you just want a key to type out words or phrases. For the most common situations we've provided `SEND_STRING()`, which will type out your string for you. All ascii that is easily translated to a keycode is supported (eg `\n\t`).
+
+For example:
 
 ```c
-const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
+enum custom_keycodes {
+       PRINT_TRUTH = SAFE_RANGE
+};
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
        if (record->event.pressed) {
-               switch(id) {
-                       case 0:
-                               return MACRO(D(LSFT), T(H), U(LSFT), T(I), D(LSFT), T(1), U(LSFT), END);
-                       case 1:
-                               return MACRO(D(LSFT), T(B), U(LSFT), T(Y), T(E), D(LSFT), T(1), U(LSFT), END);
+               switch(keycode) {
+                       case PRINT_TRUTH:
+                               SEND_STRING("QMK is the best thing ever!");
+                               return false; break;
                }
        }
-       return MACRO_NONE;
+       return true;
 };
 ```
 
-This defines two macros which will be run when the key they are assigned to is pressed. If instead you'd like them to run when the key is released you can change the if statement:
+### Tap/down/up
+
+You can send arbitary keycodes by wrapping them in:
+
+* `SS_TAP()`
+* `SS_DOWN()`
+* `SS_UP()`
+
+For example:
+
+    SEND_STRING(SS_TAP(X_HOME));
+
+Would tap `KC_HOME` - note how the prefix is now `X_`, and not `KC_`. You can also combine this with other strings, like this:
+
+    SEND_STRING("VE"SS_TAP(X_HOME)"LO");
+
+Which would send "VE" followed by a `KC_HOME` tap, and "LO" (spelling "LOVE" if on a newline).
+
+There's also a couple of mod shortcuts you can use:
+
+* `SS_LCTRL(string)`
+* `SS_LGUI(string)`
+* `SS_LALT(string)`
+
+That can be used like this:
+
+    SEND_STRING(SS_LCTRL("a"));
+
+Which would send LCTRL+a (LTRL down, a, LTRL up) - notice that they take strings (eg `"k"`), and not the `X_K` keycodes.
+
+### Alternative keymaps
+
+By default, it assumes a US keymap with a QWERTY layout; if you want to change that (e.g. if your OS uses software Colemak), include this somewhere in your keymap:
+
+    #include <sendstring_colemak.h>
+
+### Strings in memory
+
+If for some reason you're manipulating strings and need to print out something you just generated (instead of being a literal, constant string), you can use `send_string()`, like this:
 
 ```c
-       if (!record->event.pressed) {
+char my_str[4] = "ok.";
+send_string(my_str);
 ```
 
-## Macro Commands
-
-A macro can include the following commands:
+The shortcuts defined above won't work with `send_string()`, but you can separate things out to different lines if needed:
 
-* I() change interval of stroke in milliseconds.
-* D() press key.
-* U() release key.
-* T() type key(press and release).
-* W() wait (milliseconds).
-* END end mark.
+```c
+char my_str[4] = "ok.";
+SEND_STRING("I said: ");
+send_string(my_str);
+SEND_STRING(".."SS_TAP(X_END));
+```
 
-## Sending strings
+## The old way: `MACRO()` & `action_get_macro`
 
-Sometimes you just want a key to type out words or phrases. For the most common situations we've provided `SEND_STRING()`, which will type out your string for you instead of having to build a `MACRO()`.
+{% hint style='info' %}
+This is inherited from TMK, and hasn't been updated - it's recommend that you use `SEND_STRING` and `process_record_user` instead.
+{% endhint %}
 
-For example:
+By default QMK assumes you don't have any macros. To define your macros you create an `action_get_macro()` function. For example:
 
 ```c
 const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
        if (record->event.pressed) {
                switch(id) {
                        case 0:
-                               SEND_STRING("QMK is the best thing ever!");
-                               return false;
+                               return MACRO(D(LSFT), T(H), U(LSFT), T(I), D(LSFT), T(1), U(LSFT), END);
+                       case 1:
+                               return MACRO(D(LSFT), T(B), U(LSFT), T(Y), T(E), D(LSFT), T(1), U(LSFT), END);
                }
        }
        return MACRO_NONE;
 };
 ```
 
-By default, it assumes a US keymap with a QWERTY layout; if you want to change that (e.g. if your OS uses software Colemak), include this somewhere in your keymap:
+This defines two macros which will be run when the key they are assigned to is pressed. If instead you'd like them to run when the key is released you can change the if statement:
 
-```
-#include <sendstring_colemak.h>
-```
+       if (!record->event.pressed) {
+
+### Macro Commands
+
+A macro can include the following commands:
+
+* I() change interval of stroke in milliseconds.
+* D() press key.
+* U() release key.
+* T() type key(press and release).
+* W() wait (milliseconds).
+* END end mark.
 
-## Mapping a Macro to a key
+### Mapping a Macro to a key
 
 Use the `M()` function within your `KEYMAP()` to call a macro. For example, here is the keymap for a 2-key keyboard:
 
@@ -92,7 +146,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
 
 When you press the key on the left it will type "Hi!" and when you press the key on the right it will type "Bye!".
 
-## Naming your macros
+### Naming your macros
 
 If you have a bunch of macros you want to refer to from your keymap while keeping the keymap easily readable you can name them using `#define` at the top of your file.
 
@@ -107,11 +161,11 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 };
 ```
 
-# Advanced macro functions
+## Advanced macro functions
 
-While working within the `action_get_macro()` function block there are some functions you may find useful. Keep in mind that while you can write some fairly advanced code within a macro if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
+There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
 
-#### `record->event.pressed`
+### `record->event.pressed`
 
 This is a boolean value that can be tested to see if the switch is being pressed or released. An example of this is
 
@@ -123,27 +177,27 @@ This is a boolean value that can be tested to see if the switch is being pressed
        }
 ```
 
-#### `register_code(<kc>);`
+### `register_code(<kc>);`
 
 This sends the `<kc>` keydown event to the computer. Some examples would be `KC_ESC`, `KC_C`, `KC_4`, and even modifiers such as `KC_LSFT` and `KC_LGUI`.
 
-#### `unregister_code(<kc>);`
+### `unregister_code(<kc>);`
 
 Parallel to `register_code` function, this sends the `<kc>` keyup event to the computer. If you don't use this, the key will be held down until it's sent.
 
-#### `clear_keyboard();`
+### `clear_keyboard();`
 
 This will clear all mods and keys currently pressed.
 
-#### `clear_mods();`
+### `clear_mods();`
 
 This will clear all mods currently pressed.
 
-#### `clear_keyboard_but_mods();`
+### `clear_keyboard_but_mods();`
 
 This will clear all keys besides the mods currently pressed.
 
-# Advanced Example: Single-key copy/paste
+## Advanced Example: Single-key copy/paste
 
 This example defines a macro which sends `Ctrl-C` when pressed down, and `Ctrl-V` when released. 
 
index 5449517801288719bc461fbe0f00fc36a0dbe35a..48b02de38e304f4ec96297cf8d01298500711ceb 100644 (file)
@@ -163,7 +163,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  * `-----------------------------------------------------------------------------------'
  */
 [_ADJUST] = {
-  {_______, RESET,   DEBUG,   _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL },
+  {_______, RESET,   DEBUG,   _______, _______, _______, _______, TERM_ON, TERM_OFF,_______, _______, KC_DEL },
   {_______, _______, MU_MOD,  AU_ON,   AU_OFF,  AG_NORM, AG_SWAP, QWERTY,  COLEMAK, DVORAK,  PLOVER,  _______},
   {_______, MUV_DE,  MUV_IN,  MU_ON,   MU_OFF,  MI_ON,   MI_OFF,  _______, _______, _______, _______, _______},
   {_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______}
index 32a9a26c75d1d8e5da7c8cd4ce06b051cd8f5856..c4091f01179c9a770dfe59c7e8c74187c4ea7675 100644 (file)
@@ -57,7 +57,7 @@ CONSOLE_ENABLE = yes         # Console for debug(+400)
 COMMAND_ENABLE = no        # Commands for debug and configuration
 NKRO_ENABLE = no            # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
 BACKLIGHT_ENABLE = no      # Enable keyboard backlight functionality
-MIDI_ENABLE = yes            # MIDI controls
+MIDI_ENABLE = no            # MIDI controls
 AUDIO_ENABLE = yes           # Audio output on port C6
 UNICODE_ENABLE = no         # Unicode
 BLUETOOTH_ENABLE = no       # Enable Bluetooth with the Adafruit EZ-Key HID
index 5ad543ca769866da41a9934e6f249ec3f2eb24dd..25e66e67c19e88278fc04f2bf4b583d9b821e171 100644 (file)
     Q__NOTE(_GS5),     \
     HD_NOTE(_C6),
 
+#define TERMINAL_SOUND \
+    E__NOTE(_C5 )
+
 #endif
diff --git a/quantum/process_keycode/process_terminal.c b/quantum/process_keycode/process_terminal.c
new file mode 100644 (file)
index 0000000..deb1543
--- /dev/null
@@ -0,0 +1,252 @@
+/* Copyright 2017 Jack Humbert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "process_terminal.h"
+#include <string.h>
+#include "version.h"
+#include <stdio.h>
+#include <math.h>
+
+bool terminal_enabled = false;
+char buffer[80] = "";
+char newline[2] = "\n";
+char arguments[6][20];
+
+__attribute__ ((weak))
+const char terminal_prompt[8] = "> ";
+
+#ifdef AUDIO_ENABLE
+    #ifndef TERMINAL_SONG
+        #define TERMINAL_SONG SONG(TERMINAL_SOUND)
+    #endif
+    float terminal_song[][2] = TERMINAL_SONG;
+    #define TERMINAL_BELL() PLAY_SONG(terminal_song)
+#else 
+    #define TERMINAL_BELL()  
+#endif
+
+__attribute__ ((weak))
+const char keycode_to_ascii_lut[58] = {
+    0, 0, 0, 0,
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
+    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, '\t',
+    ' ', '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', '.', '/'
+}; 
+
+__attribute__ ((weak))
+const char shifted_keycode_to_ascii_lut[58] = {
+    0, 0, 0, 0,
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
+    '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', 0, 0, 0, '\t',
+    ' ', '_', '+', '{', '}', '|', 0, ':', '\'', '~', '<', '>', '?'
+}; 
+
+struct stringcase { 
+    char* string; 
+    void (*func)(void); 
+} typedef stringcase;
+
+void enable_terminal(void) {
+    terminal_enabled = true;
+    strcpy(buffer, "");
+    for (int i = 0; i < 6; i++)
+        strcpy(arguments[i], "");
+    // select all text to start over
+    // SEND_STRING(SS_LCTRL("a"));
+    send_string(terminal_prompt);
+}
+
+void disable_terminal(void) {
+    terminal_enabled = false;
+}
+
+void terminal_about(void) {
+    SEND_STRING("QMK Firmware\n");
+    SEND_STRING("  v");
+    SEND_STRING(QMK_VERSION);
+    SEND_STRING("\n"SS_TAP(X_HOME)"  Built: ");
+    SEND_STRING(QMK_BUILDDATE);
+    send_string(newline);
+    #ifdef TERMINAL_HELP
+        if (strlen(arguments[1]) != 0) {
+            SEND_STRING("You entered: ");
+            send_string(arguments[1]);
+            send_string(newline);
+        }
+    #endif
+}
+
+void terminal_help(void);
+
+extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
+
+void terminal_keycode(void) {
+    if (strlen(arguments[1]) != 0 && strlen(arguments[2]) != 0 && strlen(arguments[3]) != 0) {
+        char keycode_dec[5];
+        char keycode_hex[5];
+        uint16_t layer = strtol(arguments[1], (char **)NULL, 10);
+        uint16_t row = strtol(arguments[2], (char **)NULL, 10);
+        uint16_t col = strtol(arguments[3], (char **)NULL, 10);
+        uint16_t keycode = pgm_read_word(&keymaps[layer][row][col]);
+        itoa(keycode, keycode_dec, 10);
+        itoa(keycode, keycode_hex, 16);
+        SEND_STRING("0x");
+        send_string(keycode_hex);
+        SEND_STRING(" (");
+        send_string(keycode_dec);
+        SEND_STRING(")\n");
+    } else {
+        #ifdef TERMINAL_HELP
+            SEND_STRING("usage: keycode <layer> <row> <col>\n");
+        #endif
+    }
+}
+
+void terminal_keymap(void) {
+    if (strlen(arguments[1]) != 0) {
+        uint16_t layer = strtol(arguments[1], (char **)NULL, 10);
+        for (int r = 0; r < MATRIX_ROWS; r++) {
+            for (int c = 0; c < MATRIX_COLS; c++) {
+                uint16_t keycode = pgm_read_word(&keymaps[layer][r][c]);
+                char keycode_s[8];
+                sprintf(keycode_s, "0x%04x, ", keycode);
+                send_string(keycode_s);
+            }
+            send_string(newline);
+        }
+    } else {
+        #ifdef TERMINAL_HELP
+            SEND_STRING("usage: keymap <layer>\n");
+        #endif
+    }
+}
+
+stringcase terminal_cases[] = { 
+    { "about", terminal_about },
+    { "help", terminal_help },
+    { "keycode", terminal_keycode },
+    { "keymap", terminal_keymap },
+    { "exit", disable_terminal }
+};
+
+void terminal_help(void) {
+    SEND_STRING("commands available:\n  ");
+    for( stringcase* case_p = terminal_cases; case_p != terminal_cases + sizeof( terminal_cases ) / sizeof( terminal_cases[0] ); case_p++ ) {
+        send_string(case_p->string);
+        SEND_STRING(" ");
+    }
+    send_string(newline);
+}
+
+void command_not_found(void) {
+    SEND_STRING("command \"");
+    send_string(buffer);
+    SEND_STRING("\" not found\n");
+}
+
+void process_terminal_command(void) {
+    // we capture return bc of the order of events, so we need to manually send a newline
+    send_string(newline);
+
+    char * pch;
+    uint8_t i = 0;
+    pch = strtok(buffer, " ");
+    while (pch != NULL) {
+        strcpy(arguments[i], pch);
+        pch = strtok(NULL, " ");
+        i++;
+    }
+  
+    bool command_found = false;
+    for( stringcase* case_p = terminal_cases; case_p != terminal_cases + sizeof( terminal_cases ) / sizeof( terminal_cases[0] ); case_p++ ) {
+        if( 0 == strcmp( case_p->string, buffer ) ) {
+            command_found = true;
+            (*case_p->func)();
+            break;
+        }
+    }
+
+    if (!command_found)
+        command_not_found();
+
+    if (terminal_enabled) {
+        strcpy(buffer, "");
+        for (int i = 0; i < 6; i++)
+            strcpy(arguments[i], "");
+        SEND_STRING(SS_TAP(X_HOME));
+        send_string(terminal_prompt);
+    }
+}
+
+bool process_terminal(uint16_t keycode, keyrecord_t *record) {
+
+    if (keycode == TERM_ON && record->event.pressed) {
+        enable_terminal();
+        return false;
+    }
+
+    if (terminal_enabled && record->event.pressed) {
+        if (keycode == TERM_OFF && record->event.pressed) {
+            disable_terminal();
+            return false;
+        }
+        if (keycode < 256) {
+            uint8_t str_len;
+            char char_to_add;
+            switch (keycode) {
+                case KC_ENTER:
+                    process_terminal_command();
+                    return false; break;
+                case KC_ESC:
+                    SEND_STRING("\n");
+                    enable_terminal();
+                    return false; break;
+                case KC_BSPC:
+                    str_len = strlen(buffer);
+                    if (str_len > 0) {
+                        buffer[str_len-1] = 0;
+                        return true;
+                    } else {
+                        TERMINAL_BELL();
+                        return false;
+                    } break;
+                case KC_LEFT:
+                case KC_RIGHT:
+                case KC_UP:
+                case KC_DOWN:
+                    return false; break;
+                default:
+                    if (keycode <= 58) {
+                        char_to_add = 0;
+                        if (get_mods() & (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) {
+                            char_to_add = shifted_keycode_to_ascii_lut[keycode];
+                        } else if (get_mods() == 0) {
+                            char_to_add = keycode_to_ascii_lut[keycode];
+                        }
+                        if (char_to_add != 0) {
+                            strncat(buffer, &char_to_add, 1);
+                        } 
+                    } break;
+            }
+
+
+
+        }
+    }
+    return true;
+}
\ No newline at end of file
diff --git a/quantum/process_keycode/process_terminal.h b/quantum/process_keycode/process_terminal.h
new file mode 100644 (file)
index 0000000..d945949
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright 2017 Jack Humbert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROCESS_TERMINAL_H
+#define PROCESS_TERMINAL_H
+
+#include "quantum.h"
+
+extern const char keycode_to_ascii_lut[58];
+extern const char shifted_keycode_to_ascii_lut[58];
+extern const char terminal_prompt[8];
+bool process_terminal(uint16_t keycode, keyrecord_t *record);
+
+#endif
\ No newline at end of file
diff --git a/quantum/process_keycode/process_terminal_nop.h b/quantum/process_keycode/process_terminal_nop.h
new file mode 100644 (file)
index 0000000..56895b3
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright 2017 Jack Humbert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROCESS_TERMINAL_H
+#define PROCESS_TERMINAL_H
+
+#include "quantum.h"
+
+#define TERM_ON KC_NO
+#define TERM_OFF KC_NO
+
+#endif
\ No newline at end of file
index 285e1e81ee37bab17bffc71e918db46e44bca876..1fccaa7d5a027a125c654399f8dd90720799aeef 100644 (file)
@@ -237,6 +237,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #endif
   #ifdef UNICODEMAP_ENABLE
     process_unicode_map(keycode, record) &&
+  #endif
+  #ifdef TERMINAL_ENABLE
+    process_terminal(keycode, record) &&
   #endif
       true)) {
     return false;
@@ -600,21 +603,55 @@ void send_string(const char *str) {
   send_string_with_delay(str, 0);
 }
 
+void send_string_P(const char *str) {
+  send_string_with_delay_P(str, 0);
+}
+
 void send_string_with_delay(const char *str, uint8_t interval) {
     while (1) {
-        uint8_t keycode;
-        uint8_t ascii_code = pgm_read_byte(str);
+        char ascii_code = *str;
         if (!ascii_code) break;
-        keycode = pgm_read_byte(&ascii_to_keycode_lut[ascii_code]);
-        if (pgm_read_byte(&ascii_to_shift_lut[ascii_code])) {
-            register_code(KC_LSFT);
-            register_code(keycode);
-            unregister_code(keycode);
-            unregister_code(KC_LSFT);
+        if (ascii_code == 1) {
+          // tap
+          uint8_t keycode = *(++str);
+          register_code(keycode);
+          unregister_code(keycode);
+        } else if (ascii_code == 2) {
+          // down
+          uint8_t keycode = *(++str);
+          register_code(keycode);
+        } else if (ascii_code == 3) {
+          // up
+          uint8_t keycode = *(++str);
+          unregister_code(keycode);
+        } else {
+          send_char(ascii_code);
         }
-        else {
-            register_code(keycode);
-            unregister_code(keycode);
+        ++str;
+        // interval
+        { uint8_t ms = interval; while (ms--) wait_ms(1); }
+    }
+}
+
+void send_string_with_delay_P(const char *str, uint8_t interval) {
+    while (1) {
+        char ascii_code = pgm_read_byte(str);
+        if (!ascii_code) break;
+        if (ascii_code == 1) {
+          // tap
+          uint8_t keycode = pgm_read_byte(++str);
+          register_code(keycode);
+          unregister_code(keycode);
+        } else if (ascii_code == 2) {
+          // down
+          uint8_t keycode = pgm_read_byte(++str);
+          register_code(keycode);
+        } else if (ascii_code == 3) {
+          // up
+          uint8_t keycode = pgm_read_byte(++str);
+          unregister_code(keycode);
+        } else {
+          send_char(ascii_code);
         }
         ++str;
         // interval
@@ -622,6 +659,20 @@ void send_string_with_delay(const char *str, uint8_t interval) {
     }
 }
 
+void send_char(char ascii_code) {
+  uint8_t keycode;
+  keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]);
+  if (pgm_read_byte(&ascii_to_shift_lut[(uint8_t)ascii_code])) {
+      register_code(KC_LSFT);
+      register_code(keycode);
+      unregister_code(keycode);
+      unregister_code(KC_LSFT);
+  } else {
+      register_code(keycode);
+      unregister_code(keycode);
+  }
+}
+
 void set_single_persistent_default_layer(uint8_t default_layer) {
   #if defined(AUDIO_ENABLE) && defined(DEFAULT_LAYER_SONGS)
     PLAY_SONG(default_layer_songs[default_layer]);
index 9a6d691a15564a0b4adb03e6fcfa9e89cde21d0d..f3333a002af30f2a3f140699947e1be0549e96fe 100644 (file)
@@ -40,7 +40,7 @@
 #include "action_util.h"
 #include <stdlib.h>
 #include "print.h"
-
+#include "send_string_keycodes.h"
 
 extern uint32_t default_layer_state;
 
@@ -103,11 +103,32 @@ extern uint32_t default_layer_state;
        #include "process_key_lock.h"
 #endif
 
-#define SEND_STRING(str) send_string(PSTR(str))
+#ifdef TERMINAL_ENABLE
+       #include "process_terminal.h"
+#else
+       #include "process_terminal_nop.h"
+#endif
+
+#define STRINGIZE(z) #z
+#define ADD_SLASH_X(y) STRINGIZE(\x ## y)
+#define SYMBOL_STR(x) ADD_SLASH_X(x)
+
+#define SS_TAP(keycode) "\1" SYMBOL_STR(keycode)
+#define SS_DOWN(keycode) "\2" SYMBOL_STR(keycode)
+#define SS_UP(keycode) "\3" SYMBOL_STR(keycode)
+
+#define SS_LCTRL(string) SS_DOWN(X_LCTRL) string SS_UP(X_LCTRL)
+#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI)
+#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT)
+
+#define SEND_STRING(str) send_string_P(PSTR(str))
 extern const bool ascii_to_shift_lut[0x80];
 extern const uint8_t ascii_to_keycode_lut[0x80];
 void send_string(const char *str);
 void send_string_with_delay(const char *str, uint8_t interval);
+void send_string_P(const char *str);
+void send_string_with_delay_P(const char *str, uint8_t interval);
+void send_char(char ascii_code);
 
 // For tri-layer
 void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
index ccd4565f5304d52f93d95565ddc5e165ac0cf291..26c3c41a73b0f6125d61bfa36d4a7d83756dc5e8 100644 (file)
@@ -431,6 +431,11 @@ enum quantum_keycodes {
     KC_LOCK,
 #endif
 
+#ifdef TERMINAL_ENABLE
+    TERM_ON,
+    TERM_OFF,
+#endif
+
     // always leave at the end
     SAFE_RANGE
 };
diff --git a/quantum/send_string_keycodes.h b/quantum/send_string_keycodes.h
new file mode 100644 (file)
index 0000000..0e308be
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef SEND_STRING_KEYCODES
+#define SEND_STRING_KEYCODES
+
+#define X_NO              00
+#define X_ROLL_OVER       01
+#define X_POST_FAIL       02
+#define X_UNDEFINED       03
+#define X_A               04
+#define X_B               05
+#define X_C               06
+#define X_D               07
+#define X_E               08
+#define X_F               09
+#define X_G               0A
+#define X_H               0B
+#define X_I               0C
+#define X_J               0D
+#define X_K               0E
+#define X_L               0F
+#define X_M               10
+#define X_N               11
+#define X_O               12
+#define X_P               13
+#define X_Q               14
+#define X_R               15
+#define X_S               16                          
+#define X_T               17                        
+#define X_U               18                        
+#define X_V               19                        
+#define X_W               1A                        
+#define X_X               1B                        
+#define X_Y               1C                        
+#define X_Z               1D                          
+#define X_1               1E                          
+#define X_2               1F                          
+#define X_3               20
+#define X_4               21                        
+#define X_5               22                        
+#define X_6               23                        
+#define X_7               24                        
+#define X_8               25                        
+#define X_9               26                        
+#define X_0               27                        
+#define X_ENTER           28                            
+#define X_ESCAPE          29                             
+#define X_BSPACE          2A                             
+#define X_TAB             2B                          
+#define X_SPACE           2C                            
+#define X_MINUS           2D                            
+#define X_EQUAL           2E                            
+#define X_LBRACKET        2F                               
+#define X_RBRACKET        30
+#define X_BSLASH          31                                     
+#define X_NONUS_HASH      32                                      
+#define X_SCOLON          33                                     
+#define X_QUOTE           34                                      
+#define X_GRAVE           35                                      
+#define X_COMMA           36                                     
+#define X_DOT             37                                
+#define X_SLASH           38                                     
+#define X_CAPSLOCK        39                               
+#define X_F1              3A                         
+#define X_F2              3B                         
+#define X_F3              3C                         
+#define X_F4              3D                         
+#define X_F5              3E                         
+#define X_F6              3F                         
+#define X_F7              40                                       
+#define X_F8              41                          
+#define X_F9              42                         
+#define X_F10             43                          
+#define X_F11             44                          
+#define X_F12             45                          
+#define X_PSCREEN         46                              
+#define X_SCROLLLOCK      47                                 
+#define X_PAUSE           48                            
+#define X_INSERT          49                             
+#define X_HOME            4A                           
+#define X_PGUP            4B                           
+#define X_DELETE          4C                             
+#define X_END             4D                          
+#define X_PGDOWN          4E                             
+#define X_RIGHT           4F                            
+#define X_LEFT            50                                      
+#define X_DOWN            51                           
+#define X_UP              52                         
+#define X_NUMLOCK         53                              
+#define X_KP_SLASH        54                               
+#define X_KP_ASTERISK     55                                  
+#define X_KP_MINUS        56                               
+#define X_KP_PLUS         57                              
+#define X_KP_ENTER        58                               
+#define X_KP_1            59                           
+#define X_KP_2            5A                           
+#define X_KP_3            5B                           
+#define X_KP_4            5C                           
+#define X_KP_5            5D                           
+#define X_KP_6            5E                           
+#define X_KP_7            5F                           
+#define X_KP_8            60                                      
+#define X_KP_9            61                           
+#define X_KP_0            62                           
+#define X_KP_DOT          63                             
+#define X_NONUS_BSLASH    64                                      
+#define X_APPLICATION     65                                  
+#define X_POWER           66                            
+#define X_KP_EQUAL        67                               
+#define X_F13             68                          
+#define X_F14             69                          
+#define X_F15             6A                          
+#define X_F16             6B                          
+#define X_F17             6C                          
+#define X_F18             6D                          
+#define X_F19             6E                          
+#define X_F20             6F                          
+#define X_F21             70                                      
+#define X_F22             71                          
+#define X_F23             72                          
+#define X_F24             73                          
+#define X_EXECUTE         74                              
+#define X_HELP            75                           
+#define X_MENU            76                           
+#define X_SELECT          77                             
+#define X_STOP            78                           
+#define X_AGAIN           79                            
+#define X_UNDO            7A                           
+#define X_CUT             7B                          
+#define X_COPY            7C                           
+#define X_PASTE           7D                            
+#define X_FIND            7E                           
+#define X__MUTE           7F                            
+#define X__VOLUP          80                                       
+#define X__VOLDOWN        81                               
+#define X_LOCKING_CAPS    82                                     
+#define X_LOCKING_NUM     83                                      
+#define X_LOCKING_SCROLL  84                                     
+#define X_KP_COMMA        85                               
+#define X_KP_EQUAL_AS400  86                                       
+#define X_INT1            87                           
+#define X_INT2            88                           
+#define X_INT3            89                           
+#define X_INT4            8A                           
+#define X_INT5            8B                           
+#define X_INT6            8C                           
+#define X_INT7            8D                           
+#define X_INT8            8E                           
+#define X_INT9            8F                           
+#define X_LANG1           90                                    
+#define X_LANG2           91                            
+#define X_LANG3           92                            
+#define X_LANG4           93                            
+#define X_LANG5           94                            
+#define X_LANG6           95                            
+#define X_LANG7           96                            
+#define X_LANG8           97                            
+#define X_LANG9           98                            
+
+/* Modifiers */
+#define X_LCTRL           e0
+#define X_LSHIFT          e1                              
+#define X_LALT            e2                           
+#define X_LGUI            e3                           
+#define X_RCTRL           e4                            
+#define X_RSHIFT          e5                             
+#define X_RALT            e6                           
+#define X_RGUI            e7                           
+
+#endif
\ No newline at end of file