From dd378601608849679ead6e2cccb74f7f29c131dc Mon Sep 17 00:00:00 2001
From: Joe Wasson <jwasson+github@gmail.com>
Date: Wed, 27 Jul 2016 08:43:02 -0700
Subject: [PATCH 1/4] Add one-hand support.

This adds an action, `ACTION_SWAP_HANDS`, that swaps the the keys on the keyboard across a keymap-defined hemisphere in order to support one-hand typing without requiring a separate one-handed layer. See updated `doc/keymap.md` for more information.
---
 doc/keymap.md                 | 18 ++++++++++++++++++
 tmk_core/common.mk            |  4 ++++
 tmk_core/common/action.c      | 33 +++++++++++++++++++++++++++++++++
 tmk_core/common/action.h      | 18 ++++++++++++++++++
 tmk_core/common/action_code.h |  8 +++++++-
 5 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/doc/keymap.md b/doc/keymap.md
index d1985e567c..1285ad6cd1 100644
--- a/doc/keymap.md
+++ b/doc/keymap.md
@@ -455,6 +455,24 @@ Turn the backlight on and off without changing level.
 
 
 
+### 2.6 Swap-Hands Action
+The swap-hands action allows support for one-handed keyboards without requiring a separate layer. Set `ONEHAND_ENABLE` in the Makefile and define a `hand_swap_config` entry in your keymap. Now whenever the `ACTION_SWAP_HANDS` command is executed the keyboard is mirrored. For instance, to type "Hello, World" on QWERTY you would type `^Ge^s^s^w^c W^wr^sd`
+
+The configuration table is a simple 2-dimensional array to map from column/row to new column/row. Example `hand_swap_config` for Planck:
+
+```
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+  {{11, 0}, {10, 0}, {9, 0}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},
+  {{11, 1}, {10, 1}, {9, 1}, {8, 1}, {7, 1}, {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}},
+  {{11, 2}, {10, 2}, {9, 2}, {8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}},
+  {{11, 3}, {10, 3}, {9, 3}, {8, 3}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}},
+};
+```
+
+Note that the array indices are reversed same as the matrix and the values are of type `keypos_t` which is `{col, row}` and all values are zero-based. In the example above, `hand_swap_config[2][4]` (third row, fifth column) would return {7, 2} (third row, eighth column).
+
+
+
 ## 3. Layer switching Example
 There are some ways to switch layer with 'Layer' actions.
 
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index aa05b9491d..429c571435 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -85,6 +85,10 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
     OPT_DEFS += -DBLUETOOTH_ENABLE
 endif
 
+ifeq ($(strip $(ONEHAND_ENABLE)), yes)
+    OPT_DEFS += -DONEHAND_ENABLE
+endif
+
 ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes)
     OPT_DEFS += -DKEYMAP_SECTION_ENABLE
 
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c
index be6dea2b79..0413b1a997 100644
--- a/tmk_core/common/action.c
+++ b/tmk_core/common/action.c
@@ -41,6 +41,12 @@ void action_exec(keyevent_t event)
         dprint("EVENT: "); debug_event(event); dprintln();
     }
 
+#ifdef ONEHAND_ENABLE
+    if (!IS_NOEVENT(event)) {
+        process_hand_swap(&event);
+    }
+#endif
+
     keyrecord_t record = { .event = event };
 
 #ifndef NO_ACTION_TAPPING
@@ -53,6 +59,26 @@ void action_exec(keyevent_t event)
 #endif
 }
 
+#ifdef ONEHAND_ENABLE
+bool swap_hands = false;
+
+void process_hand_swap(keyevent_t *event) {
+    static swap_state_row_t swap_state[MATRIX_ROWS];
+
+    keypos_t pos = event->key;
+    swap_state_row_t col_bit = (swap_state_row_t)1<<pos.col;
+    bool do_swap = event->pressed ? swap_hands :
+                                    swap_state[pos.row] & (col_bit);
+
+    if (do_swap) {
+        event->key = hand_swap_config[pos.row][pos.col];
+        swap_state[pos.row] |= col_bit;
+    } else {
+        swap_state[pos.row] &= ~(col_bit);
+    }
+}
+#endif
+
 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
 bool disable_action_cache = false;
 
@@ -439,6 +465,13 @@ void process_action(keyrecord_t *record, action_t action)
             break;
 #endif
         case ACT_COMMAND:
+            switch (action.command.id) {
+#ifdef ONEHAND_ENABLE
+                case CMD_SWAP_HANDS:
+                    swap_hands = event.pressed;
+                    break;
+#endif
+            }
             break;
 #ifndef NO_ACTION_FUNCTION
         case ACT_FUNCTION:
diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h
index e8aa12a7cb..b9bdfe642c 100644
--- a/tmk_core/common/action.h
+++ b/tmk_core/common/action.h
@@ -65,6 +65,24 @@ bool process_record_quantum(keyrecord_t *record);
 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
 extern bool disable_action_cache;
 #endif
+
+/* Code for handling one-handed key modifiers. */
+#ifdef ONEHAND_ENABLE
+extern bool swap_hands;
+extern const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS];
+#if (MATRIX_COLS <= 8)
+typedef  uint8_t    swap_state_row_t;
+#elif (MATRIX_COLS <= 16)
+typedef  uint16_t   swap_state_row_t;
+#elif (MATRIX_COLS <= 32)
+typedef  uint32_t   swap_state_row_t;
+#else
+#error "MATRIX_COLS: invalid value"
+#endif
+
+void process_hand_swap(keyevent_t *record);
+#endif
+
 void process_record_nocache(keyrecord_t *record);
 void process_record(keyrecord_t *record);
 void process_action(keyrecord_t *record, action_t action);
diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h
index ca729aaece..95d2cbf3e4 100644
--- a/tmk_core/common/action_code.h
+++ b/tmk_core/common/action_code.h
@@ -295,6 +295,10 @@ enum backlight_opt {
     BACKLIGHT_STEP     = 3,
     BACKLIGHT_LEVEL    = 4,
 };
+
+enum command_id {
+    CMD_SWAP_HANDS = 0x14,
+};
 /* Macro */
 #define ACTION_MACRO(id)                ACTION(ACT_MACRO, (id))
 #define ACTION_MACRO_TAP(id)            ACTION(ACT_MACRO, FUNC_TAP<<8 | (id))
@@ -306,7 +310,7 @@ enum backlight_opt {
 #define ACTION_BACKLIGHT_STEP()         ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP << 8)
 #define ACTION_BACKLIGHT_LEVEL(level)   ACTION(ACT_BACKLIGHT, BACKLIGHT_LEVEL << 8 | (level))
 /* Command */
-#define ACTION_COMMAND(id, opt)         ACTION(ACT_COMMAND,  (opt)<<8 | (addr))
+#define ACTION_COMMAND(id, opt)         ACTION(ACT_COMMAND,  (opt)<<8 | (id))
 /* Function */
 enum function_opts {
     FUNC_TAP = 0x8,     /* indciates function is tappable */
@@ -314,5 +318,7 @@ enum function_opts {
 #define ACTION_FUNCTION(id)             ACTION(ACT_FUNCTION, (id))
 #define ACTION_FUNCTION_TAP(id)         ACTION(ACT_FUNCTION, FUNC_TAP<<8 | (id))
 #define ACTION_FUNCTION_OPT(id, opt)    ACTION(ACT_FUNCTION, (opt)<<8 | (id))
+/* OneHand Support */
+#define ACTION_SWAP_HANDS()             ACTION_COMMAND(CMD_SWAP_HANDS, 0)
 
 #endif /* ACTION_CODE_H */

From 8090f6b499fd87ddeb7a191f7bc3dace9d03be23 Mon Sep 17 00:00:00 2001
From: Joe Wasson <jwasson+github@gmail.com>
Date: Thu, 28 Jul 2016 01:24:06 -0700
Subject: [PATCH 2/4] Improve one-hand support by adding more actions and tap
 keys.

---
 doc/keymap.md                 | 13 +++++++-
 tmk_core/common/action.c      | 57 ++++++++++++++++++++++++++++++++---
 tmk_core/common/action_code.h | 28 ++++++++++++++---
 3 files changed, 89 insertions(+), 9 deletions(-)

diff --git a/doc/keymap.md b/doc/keymap.md
index 1285ad6cd1..6f2a663fc8 100644
--- a/doc/keymap.md
+++ b/doc/keymap.md
@@ -456,8 +456,9 @@ Turn the backlight on and off without changing level.
 
 
 ### 2.6 Swap-Hands Action
-The swap-hands action allows support for one-handed keyboards without requiring a separate layer. Set `ONEHAND_ENABLE` in the Makefile and define a `hand_swap_config` entry in your keymap. Now whenever the `ACTION_SWAP_HANDS` command is executed the keyboard is mirrored. For instance, to type "Hello, World" on QWERTY you would type `^Ge^s^s^w^c W^wr^sd`
+The swap-hands action allows support for one-handed keyboards without requiring a separate layer. Set `ONEHAND_ENABLE` in the Makefile and define a `hand_swap_config` entry in your keymap. Now whenever the `ACTION_SWAP_HANDS` command key is pressed the keyboard is mirrored. For instance, to type "Hello, World" on QWERTY you would type `^Ge^s^s^w^c W^wr^sd`
 
+### 2.6.1 Configuration
 The configuration table is a simple 2-dimensional array to map from column/row to new column/row. Example `hand_swap_config` for Planck:
 
 ```
@@ -471,6 +472,16 @@ const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
 
 Note that the array indices are reversed same as the matrix and the values are of type `keypos_t` which is `{col, row}` and all values are zero-based. In the example above, `hand_swap_config[2][4]` (third row, fifth column) would return {7, 2} (third row, eighth column).
 
+### 2.6.2 Advanced Swap Commands
+- **`ACTION_SWAP_HANDS()`** Swaps hands when pressed, returns to normal when released (momentary).
+- **`ACTION_SWAP_HANDS_TOGGLE()`** Toggles swap on and off with every keypress.
+- **`ACTION_SWAP_HANDS_TAP_TOGGLE()`** Toggles with a tap; momentary when held.
+- **`ACTION_SWAP_HANDS_TAP_KEY(key)`** Sends `key` with a tap; momentary swap when held.
+- **`ACTION_SWAP_HANDS_ON_OFF()`** Alias for `ACTION_SWAP_HANDS()`
+- **`ACTION_SWAP_HANDS_OFF_ON()`** Momentarily turns off swap.
+- **`ACTION_SWAP_HANDS_ON()`** Turns on swapping and leaves it on.
+- **`ACTION_SWAP_HANDS_OFF()`** Turn off swapping and leaves it off. Good for returning to a known state.
+
 
 
 ## 3. Layer switching Example
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c
index 0413b1a997..08ef22eb97 100644
--- a/tmk_core/common/action.c
+++ b/tmk_core/common/action.c
@@ -465,14 +465,55 @@ void process_action(keyrecord_t *record, action_t action)
             break;
 #endif
         case ACT_COMMAND:
-            switch (action.command.id) {
+            break;
 #ifdef ONEHAND_ENABLE
-                case CMD_SWAP_HANDS:
+        case ACT_SWAP_HANDS:
+            switch (action.swap.code) {
+                case OP_SH_TOGGLE:
+                    if (event.pressed) {
+                        swap_hands = !swap_hands;
+                    }
+                    break;
+                case OP_SH_ON_OFF:
                     swap_hands = event.pressed;
                     break;
-#endif
+                case OP_SH_OFF_ON:
+                    swap_hands = !event.pressed;
+                    break;
+                case OP_SH_ON:
+                    if (!event.pressed) {
+                        swap_hands = true;
+                    }
+                    break;
+                case OP_SH_OFF:
+                    if (!event.pressed) {
+                        swap_hands = false;
+                    }
+                    break;
+    #ifndef NO_ACTION_TAPPING
+                case OP_SH_TAP_TOGGLE:
+                    /* tap toggle */
+                    if (tap_count > 0) {
+                        if (!event.pressed) {
+                            swap_hands = !swap_hands;
+                        }
+                    } else {
+                        swap_hands = event.pressed;
+                    }
+                    break;
+                default:
+                    if (tap_count > 0) {
+                        if (event.pressed) {
+                            register_code(action.swap.code);
+                        } else {
+                            unregister_code(action.swap.code);
+                        }
+                    } else {
+                        swap_hands = event.pressed;
+                    }
+    #endif
             }
-            break;
+#endif
 #ifndef NO_ACTION_FUNCTION
         case ACT_FUNCTION:
             action_function(record, action.func.id, action.func.opt);
@@ -685,6 +726,13 @@ bool is_tap_key(keypos_t key)
                     return true;
             }
             return false;
+        case ACT_SWAP_HANDS:
+            switch (action.swap.code) {
+                case 0x00 ... 0xdf:
+                case OP_SH_TAP_TOGGLE:
+                    return true;
+            }
+            return false;
         case ACT_MACRO:
         case ACT_FUNCTION:
             if (action.func.opt & FUNC_TAP) { return true; }
@@ -725,6 +773,7 @@ void debug_action(action_t action)
         case ACT_MACRO:             dprint("ACT_MACRO");             break;
         case ACT_COMMAND:           dprint("ACT_COMMAND");           break;
         case ACT_FUNCTION:          dprint("ACT_FUNCTION");          break;
+        case ACT_SWAP_HANDS:        dprint("ACT_SWAP_HANDS");        break;
         default:                    dprint("UNKNOWN");               break;
     }
     dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff);
diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h
index 95d2cbf3e4..33da35f35f 100644
--- a/tmk_core/common/action_code.h
+++ b/tmk_core/common/action_code.h
@@ -108,6 +108,8 @@ enum action_kind_id {
     /* Other Keys */
     ACT_USAGE           = 0b0100,
     ACT_MOUSEKEY        = 0b0101,
+    /* One-hand Support */
+    ACT_SWAP_HANDS      = 0b0110,
     /* Layer Actions */
     ACT_LAYER           = 0b1000,
     ACT_LAYER_TAP       = 0b1010, /* Layer  0-15 */
@@ -178,6 +180,11 @@ typedef union {
         uint8_t  opt    :4;
         uint8_t  kind   :4;
     } func;
+    struct action_swap {
+        uint8_t  code   :8;
+        uint8_t  opt   :4;
+        uint8_t  kind   :4;
+    } swap;
 } action_t;
 
 
@@ -296,9 +303,6 @@ enum backlight_opt {
     BACKLIGHT_LEVEL    = 4,
 };
 
-enum command_id {
-    CMD_SWAP_HANDS = 0x14,
-};
 /* Macro */
 #define ACTION_MACRO(id)                ACTION(ACT_MACRO, (id))
 #define ACTION_MACRO_TAP(id)            ACTION(ACT_MACRO, FUNC_TAP<<8 | (id))
@@ -319,6 +323,22 @@ enum function_opts {
 #define ACTION_FUNCTION_TAP(id)         ACTION(ACT_FUNCTION, FUNC_TAP<<8 | (id))
 #define ACTION_FUNCTION_OPT(id, opt)    ACTION(ACT_FUNCTION, (opt)<<8 | (id))
 /* OneHand Support */
-#define ACTION_SWAP_HANDS()             ACTION_COMMAND(CMD_SWAP_HANDS, 0)
+enum swap_hands_pram_tap_op {
+    OP_SH_TOGGLE = 0xF0,
+    OP_SH_TAP_TOGGLE,
+    OP_SH_ON_OFF,
+    OP_SH_OFF_ON,
+    OP_SH_OFF,
+    OP_SH_ON,
+};
+
+#define ACTION_SWAP_HANDS()             ACTION_SWAP_HANDS_ON_OFF()
+#define ACTION_SWAP_HANDS_TOGGLE()      ACTION(ACT_SWAP_HANDS, OP_SH_TOGGLE)
+#define ACTION_SWAP_HANDS_TAP_TOGGLE()  ACTION(ACT_SWAP_HANDS, OP_SH_TAP_TOGGLE)
+#define ACTION_SWAP_HANDS_TAP_KEY(key)  ACTION(ACT_SWAP_HANDS, key)
+#define ACTION_SWAP_HANDS_ON_OFF()      ACTION(ACT_SWAP_HANDS, OP_SH_ON_OFF)
+#define ACTION_SWAP_HANDS_OFF_ON()      ACTION(ACT_SWAP_HANDS, OP_SH_OFF_ON)
+#define ACTION_SWAP_HANDS_ON()          ACTION(ACT_SWAP_HANDS, OP_SH_ON)
+#define ACTION_SWAP_HANDS_OFF()         ACTION(ACT_SWAP_HANDS, OP_SH_OFF)
 
 #endif /* ACTION_CODE_H */

From 66adbfcab5c197f01ead2c07a79b25d2f2b93b1a Mon Sep 17 00:00:00 2001
From: Joe Wasson <jwasson+github@gmail.com>
Date: Thu, 28 Jul 2016 01:25:29 -0700
Subject: [PATCH 3/4] Add default swap configs for a couple of boards.

---
 keyboards/ergodox/infinity/infinity.c | 24 ++++++++++++++++++++++++
 keyboards/planck/planck.c             | 10 ++++++++++
 keyboards/preonic/preonic.c           | 11 +++++++++++
 3 files changed, 45 insertions(+)

diff --git a/keyboards/ergodox/infinity/infinity.c b/keyboards/ergodox/infinity/infinity.c
index f89e046d0d..c5793385fe 100644
--- a/keyboards/ergodox/infinity/infinity.c
+++ b/keyboards/ergodox/infinity/infinity.c
@@ -130,3 +130,27 @@ void ergodox_right_led_3_off(void){
 
 void ergodox_right_led_off(uint8_t led){
 }
+
+#ifdef ONEHAND_ENABLE
+__attribute__ ((weak))
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+    {{0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}},
+    {{0, 10}, {1, 10}, {2, 10}, {3, 10}, {4, 10}},
+    {{0, 11}, {1, 11}, {2, 11}, {3, 11}, {4, 11}},
+    {{0, 12}, {1, 12}, {2, 12}, {3, 12}, {4, 12}},
+    {{0, 13}, {1, 13}, {2, 13}, {3, 13}, {4, 13}},
+    {{0, 14}, {1, 14}, {2, 14}, {3, 14}, {4, 14}},
+    {{0, 15}, {1, 15}, {2, 15}, {3, 15}, {4, 15}},
+    {{0, 16}, {1, 16}, {2, 16}, {3, 16}, {4, 16}},
+    {{0, 17}, {1, 17}, {2, 17}, {3, 17}, {4, 17}},
+    {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}},
+    {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}},
+    {{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}},
+    {{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}},
+    {{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}},
+    {{0, 5}, {1, 5}, {2, 5}, {3, 5}, {4, 5}},
+    {{0, 6}, {1, 6}, {2, 6}, {3, 6}, {4, 6}},
+    {{0, 7}, {1, 7}, {2, 7}, {3, 7}, {4, 7}},
+    {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}},
+};
+#endif
diff --git a/keyboards/planck/planck.c b/keyboards/planck/planck.c
index 8d70bb4e5a..645b450d1d 100644
--- a/keyboards/planck/planck.c
+++ b/keyboards/planck/planck.c
@@ -1,5 +1,15 @@
 #include "planck.h"
 
+#ifdef ONEHAND_ENABLE
+__attribute__ ((weak))
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+  {{11, 0}, {10, 0}, {9, 0}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},
+  {{11, 1}, {10, 1}, {9, 1}, {8, 1}, {7, 1}, {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}},
+  {{11, 2}, {10, 2}, {9, 2}, {8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}},
+  {{11, 3}, {10, 3}, {9, 3}, {8, 3}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}},
+};
+#endif
+
 void matrix_init_kb(void) {
 	// Turn status LED on
 	DDRE |= (1<<6);
diff --git a/keyboards/preonic/preonic.c b/keyboards/preonic/preonic.c
index 889c3fc8fd..d9c119b8da 100644
--- a/keyboards/preonic/preonic.c
+++ b/keyboards/preonic/preonic.c
@@ -1,5 +1,16 @@
 #include "preonic.h"
 
+#ifdef ONEHAND_ENABLE
+__attribute__ ((weak))
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+  {{11, 0}, {10, 0}, {9, 0}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},
+  {{11, 1}, {10, 1}, {9, 1}, {8, 1}, {7, 1}, {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}},
+  {{11, 2}, {10, 2}, {9, 2}, {8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}},
+  {{11, 3}, {10, 3}, {9, 3}, {8, 3}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}},
+  {{11, 4}, {10, 4}, {9, 4}, {8, 4}, {7, 4}, {6, 4}, {5, 4}, {4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}},
+};
+#endif
+
 void matrix_init_kb(void) {
 
     // Turn status LED on

From c20bf83afd698a4535fa1b8df901f6ab1e3cb532 Mon Sep 17 00:00:00 2001
From: Joe Wasson <jwasson+github@gmail.com>
Date: Sat, 20 Aug 2016 18:32:13 -0700
Subject: [PATCH 4/4] Add one-hand key to planck/experimental keymap.

---
 keyboards/planck/keymaps/experimental/Makefile | 1 +
 keyboards/planck/keymaps/experimental/keymap.c | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/keyboards/planck/keymaps/experimental/Makefile b/keyboards/planck/keymaps/experimental/Makefile
index 877c4aed0e..3a8250a9b5 100644
--- a/keyboards/planck/keymaps/experimental/Makefile
+++ b/keyboards/planck/keymaps/experimental/Makefile
@@ -16,6 +16,7 @@ AUDIO_ENABLE = no           # Audio output on port C6
 UNICODE_ENABLE = no         # Unicode
 BLUETOOTH_ENABLE = no       # Enable Bluetooth with the Adafruit EZ-Key HID
 RGBLIGHT_ENABLE = yes        # Enable WS2812 RGB underlight.  Do not enable this with audio at the same time.
+ONEHAND_ENABLE = yes        # Enable one-hand typing
 
 # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
 SLEEP_LED_ENABLE = no    # Breathing sleep LED during USB suspend
diff --git a/keyboards/planck/keymaps/experimental/keymap.c b/keyboards/planck/keymaps/experimental/keymap.c
index 2c12700944..569dbcc8aa 100644
--- a/keyboards/planck/keymaps/experimental/keymap.c
+++ b/keyboards/planck/keymaps/experimental/keymap.c
@@ -70,7 +70,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   {KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_BSPC},
   {KC_ESC,  KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT},
   {KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT },
-  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
+  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_FN0,  KC_FN0,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
 },
 
 /* Colemak
@@ -88,7 +88,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   {KC_TAB,  KC_Q,    KC_W,    KC_F,    KC_P,    KC_G,    KC_J,    KC_L,    KC_U,    KC_Y,    KC_SCLN, KC_BSPC},
   {KC_ESC,  KC_A,    KC_R,    KC_S,    KC_T,    KC_D,    KC_H,    KC_N,    KC_E,    KC_I,    KC_O,    KC_QUOT},
   {KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_K,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT },
-  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
+  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_FN0,  KC_FN0,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
 },
 
 /* Dvorak
@@ -106,7 +106,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   {KC_TAB,  KC_QUOT, KC_COMM, KC_DOT,  KC_P,    KC_Y,    KC_F,    KC_G,    KC_C,    KC_R,    KC_L,    KC_BSPC},
   {KC_ESC,  KC_A,    KC_O,    KC_E,    KC_U,    KC_I,    KC_D,    KC_H,    KC_T,    KC_N,    KC_S,    KC_SLSH},
   {KC_LSFT, KC_SCLN, KC_Q,    KC_J,    KC_K,    KC_X,    KC_B,    KC_M,    KC_W,    KC_V,    KC_Z,    KC_ENT },
-  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
+  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_FN0,  KC_FN0,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
 },
 
 /* Lower
@@ -186,7 +186,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 };
 
 const uint16_t PROGMEM fn_actions[] = {
-
+  ACTION_SWAP_HANDS_TAP_KEY(KC_SPC),
 };
 
 #ifdef AUDIO_ENABLE