From d4c935d8fa6495f7f925c3109db8e9390136bf79 Mon Sep 17 00:00:00 2001
From: Ryan Neff <ryan.ray.neff@fluke.com>
Date: Wed, 31 Aug 2022 12:29:26 -0700
Subject: [PATCH] Added personal Iris Rev6a layout and Milk 2% layout (#17600)

by JellyTitan
---
 .../keebio/iris/keymaps/two_knob/config.h     |  62 +++++
 .../keebio/iris/keymaps/two_knob/keymap.c     | 261 ++++++++++++++++++
 .../keebio/iris/keymaps/two_knob/readme.md    |  15 +
 .../keebio/iris/keymaps/two_knob/rules.mk     |  15 +
 .../iris/keymaps/two_knob/two_knob.json       | 185 +++++++++++++
 .../keymaps/copypasta_macfancy/config.h       |   6 +
 .../keymaps/copypasta_macfancy/keymap.c       |  56 ++++
 .../keymaps/copypasta_macfancy/readme.md      |  18 ++
 .../keymaps/copypasta_macfancy/rules.mk       |   4 +
 9 files changed, 622 insertions(+)
 create mode 100644 keyboards/keebio/iris/keymaps/two_knob/config.h
 create mode 100644 keyboards/keebio/iris/keymaps/two_knob/keymap.c
 create mode 100644 keyboards/keebio/iris/keymaps/two_knob/readme.md
 create mode 100644 keyboards/keebio/iris/keymaps/two_knob/rules.mk
 create mode 100644 keyboards/keebio/iris/keymaps/two_knob/two_knob.json
 create mode 100644 keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/config.h
 create mode 100644 keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/keymap.c
 create mode 100644 keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/readme.md
 create mode 100644 keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/rules.mk

diff --git a/keyboards/keebio/iris/keymaps/two_knob/config.h b/keyboards/keebio/iris/keymaps/two_knob/config.h
new file mode 100644
index 0000000000..37ffb20a2f
--- /dev/null
+++ b/keyboards/keebio/iris/keymaps/two_knob/config.h
@@ -0,0 +1,62 @@
+// Copyright 2022 Ryan Neff (@JellyTitan)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define EE_HANDS
+
+/* Turn off RGB light when host is asleep. (Doesn't seem to work for mac)? */
+#define RGBLIGHT_SLEEP
+#define RGBLIGHT_LAYERS
+/* Decrease decay of heatmap rgb effect */
+#define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 50
+/* If you're setting colors per key, this is required. */
+#define SPLIT_LAYER_STATE_ENABLE
+
+/* If you type too fast, it confuses the Mod key combos. This resolves it: */
+#define IGNORE_MOD_TAP_INTERRUPT
+
+/* Set tapdance speed */
+#define TAPPING_TERM 210
+
+/* Allows for the setting of constant mouse speed levels. */
+/* Delay between pressing a movement key and cursor movement */
+#define MOUSEKEY_DELAY 10
+/* Time between cursor movements in milliseconds */
+#define MOUSEKEY_INTERVAL 16
+/* Step size */
+#define MOUSEKEY_MOVE_DELTA 8
+/* Maximum cursor speed at which acceleration stops */
+#define MOUSEKEY_MAX_SPEED 2
+/* Time until maximum cursor speed is reached */
+#define MOUSEKEY_TIME_TO_MAX 40
+/* Maximum number of scroll steps per scroll action */
+#define MOUSEKEY_WHEEL_MAX_SPEED 42
+/* Time until maximum scroll speed is reached */
+#define MOUSEKEY_WHEEL_TIME_TO_MAX 15
+
+// Tweak how the mouse cursor moves. https://docs.qmk.fm/#/feature_mouse_keys
+// Accelerated mode (default).
+// MOUSEKEY_DELAY  10  Delady between pressing a movement key and cursor movement
+// MOUSEKEY_INTERVAL 20  Time between cursor movements in milliseconds
+// MOUSEKEY_MOVE_DELTA 8 Step size
+// MOUSEKEY_MAX_SPEED  10  Maximum cursor speed at which acceleration stops
+// MOUSEKEY_TIME_TO_MAX  30  Time until maximum cursor speed is reached
+// MOUSEKEY_WHEEL_DELAY  10  Delay between pressing a wheel key and wheel movement
+// MOUSEKEY_WHEEL_INTERVAL 80  Time between wheel movements
+// MOUSEKEY_WHEEL_MAX_SPEED  8 Maximum number of scroll steps per scroll action
+// MOUSEKEY_WHEEL_TIME_TO_MAX  40  Time until maximum scroll speed is reached
+
+// Kinetic mode, alternate to the default mode.
+// MK_KINETIC_SPEED  undefined Enable kinetic mode
+// MOUSEKEY_DELAY  5 Delay between pressing a movement key and cursor movement
+// MOUSEKEY_INTERVAL 10  Time between cursor movements in milliseconds
+// MOUSEKEY_MOVE_DELTA 5 Step size for accelerating from initial to base speed
+// MOUSEKEY_INITIAL_SPEED  100 Initial speed of the cursor in pixel per second
+// MOUSEKEY_BASE_SPEED 1000  Maximum cursor speed at which acceleration stops
+// MOUSEKEY_DECELERATED_SPEED  400 Decelerated cursor speed
+// MOUSEKEY_ACCELERATED_SPEED  3000  Accelerated cursor speed
+// MOUSEKEY_WHEEL_INITIAL_MOVEMENTS  16  Initial number of movements of the mouse wheel
+// MOUSEKEY_WHEEL_BASE_MOVEMENTS 32  Maximum number of movements at which acceleration stops
+// MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS  48  Accelerated wheel movements
+// MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS  8 Decelerated wheel movements
diff --git a/keyboards/keebio/iris/keymaps/two_knob/keymap.c b/keyboards/keebio/iris/keymaps/two_knob/keymap.c
new file mode 100644
index 0000000000..aeeb2df905
--- /dev/null
+++ b/keyboards/keebio/iris/keymaps/two_knob/keymap.c
@@ -0,0 +1,261 @@
+// Copyright 2022 Ryan Neff (@JellyTitan)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+enum custom_layers {
+    _QWERTY,
+    _LOWER,
+    _RAISE,
+    _ADJUST,
+};
+
+/* Defines macros for use with the configurators "Any" key. (These are non-standard macros). */
+/* Move active application right half. */
+#define KC_CSGRA LCTL(LSFT(LGUI(KC_RGHT)))
+/* Move active application to left half. */
+#define KC_CSGLA LCTL(LSFT(LGUI(KC_LEFT)))
+/* Maximize active application. */
+#define KC_MAXIM LCTL(LSFT(LGUI(KC_UP)))
+/* Minimize active application. */
+#define KC_MINIM LCTL(LSFT(LGUI(KC_DOWN)))
+
+/* Rotary encoder variables used to hold down Command (GUI) key while cycling through open programs. */
+bool is_cmd_tab_active = false;
+uint16_t cmd_tab_timer = 0;  
+
+enum custom_keycodes {
+    QWERTY = SAFE_RANGE,
+    LOWER,
+    RAISE,
+    ADJUST,
+    CMD_TAB_CW,
+    CMD_TAB_CCW,
+};
+
+/**
+ * Tap Dance declarations
+ */
+enum tapdances {
+    _TD_FIVE_ENTER,
+};
+
+/* Tapdance */
+#define TD_FIVE_ENTER TD(_TD_FIVE_ENTER)
+
+/**
+ * Tap Dance definitions
+ *
+ * NOTE - if your not using tapdance, comment out:
+ * TAP_DANCE_ENABLE = yes in rules.mk
+ * define TAPPING_TERM 175 in config.h
+ * else you'll get a compile error.
+ *
+ * To use this in the configurator, enter the name 'TD_FIVE_ENTER' in the "Any" key.
+ */
+qk_tap_dance_action_t tap_dance_actions[] = {
+    /* Tap once for 5, twice for Enter. */
+    [_TD_FIVE_ENTER] = ACTION_TAP_DANCE_DOUBLE(KC_5, KC_ENT),
+};
+
+/**
+ * Keymap. Generated via configurator.
+ *
+ * You can download/upload the two_know.json to the configurator:
+ * https://config.qmk.fm/#/keebio/iris/rev6a/LAYOUT
+ *
+ * If you make changes and download the json, you can run qmk json2c two_knob.json to get converted text. 
+ * You can copy and paste it here.
+ * You will have to reneame the array keys from ints to the custom keycode names.
+ *
+ * The rotary encoders are programmed manually below because the configurator does not support them yet.
+ */
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+    [_QWERTY] = LAYOUT(KC_EQL, KC_1, KC_2, KC_3, KC_4, TD_FIVE_ENTER, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS, LT(1, KC_DEL), LT(2, KC_A), LCTL_T(KC_S), KC_D, LGUI_T(KC_F), KC_G, KC_H, RGUI_T(KC_J), KC_K, RCTL_T(KC_L), LT(2, KC_SCLN), LT(1, KC_QUOT), KC_LSPO, LALT_T(KC_Z), KC_X, KC_C, KC_V, KC_B, KC_MINIM, KC_MAXIM, KC_N, KC_M, KC_COMM, KC_DOT, RALT_T(KC_SLSH), KC_RSPC, QK_GESC, KC_SPC, KC_BSPC, KC_TAB, KC_ENT, KC_DEL),
+    [_LOWER]  = LAYOUT(KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_TRNS, KC_EXLM, KC_AT, KC_LCBR, KC_RCBR, KC_PIPE, DT_PRNT, KC_7, KC_8, KC_9, KC_ASTR, KC_F12, KC_TRNS, KC_HASH, KC_DLR, KC_LPRN, KC_RPRN, KC_GRV, DT_UP, KC_4, KC_5, KC_6, KC_PPLS, KC_TRNS, KC_TRNS, KC_HASH, KC_DLR, KC_LBRC, KC_RBRC, KC_TILD, KC_TRNS, KC_TRNS, DT_DOWN, KC_1, KC_2, KC_3, KC_PSLS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_P0),
+    [_RAISE]  = LAYOUT(RGB_TOG, KC_ACL0, KC_ACL1, KC_ACL2, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_MOD, RGB_RMOD, RGB_HUI, RGB_HUD, KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_UP, KC_BTN2, RGB_SAI, RGB_SAD, KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, RGB_VAI, RGB_VAD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_SPI, RGB_SPD, KC_TRNS, KC_TRNS, KC_CSGLA, KC_CSGRA, KC_TRNS, KC_TRNS),
+    [_ADJUST] = LAYOUT(
+        //┌────────┬────────┬────────┬────────┬────────┬────────┐                          ┌────────┬────────┬────────┬────────┬────────┬────────┐
+        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+        //├────────┼────────┼────────┼────────┼────────┼────────┤                          ├────────┼────────┼────────┼────────┼────────┼────────┤
+        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+        //├────────┼────────┼────────┼────────┼────────┼────────┤                          ├────────┼────────┼────────┼────────┼────────┼────────┤
+        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+        //├────────┼────────┼────────┼────────┼────────┼────────┼────────┐        ┌────────┼────────┼────────┼────────┼────────┼────────┼────────┤
+        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+        //└────────┴────────┴────────┴───┬────┴───┬────┴───┬────┴───┬────┘        └───┬────┴───┬────┴───┬────┴───┬────┴────────┴────────┴────────┘
+        _______, _______, _______, _______, _______, _______
+        // └────────┴────────┴────────┘                 └────────┴────────┴────────┘
+    )
+};
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+    switch (keycode) {
+        case LOWER:
+            if (record->event.pressed) {
+                layer_on(_LOWER);
+                update_tri_layer(_LOWER, _RAISE, _ADJUST);
+            } else {
+                layer_off(_LOWER);
+                update_tri_layer(_LOWER, _RAISE, _ADJUST);
+            }
+            return false;
+            break;
+        case RAISE:
+            if (record->event.pressed) {
+                layer_on(_RAISE);
+                update_tri_layer(_LOWER, _RAISE, _ADJUST);
+            } else {
+                layer_off(_RAISE);
+                update_tri_layer(_LOWER, _RAISE, _ADJUST);
+            }
+            return false;
+        case CMD_TAB_CW:
+            if (record->event.pressed) {
+                if (!is_cmd_tab_active) {
+                    is_cmd_tab_active = true;
+                    register_code(KC_LGUI);
+                }
+                cmd_tab_timer = timer_read();
+                register_code(KC_TAB);
+            } else {
+                unregister_code(KC_TAB);
+            }
+            break;
+        case CMD_TAB_CCW:
+            if (record->event.pressed) {
+                if (!is_cmd_tab_active) {
+                    is_cmd_tab_active = true;
+                    register_code(KC_LGUI);
+                }
+                cmd_tab_timer = timer_read();
+                tap_code16(S(KC_TAB));
+            } else {
+                unregister_code(KC_TAB);
+            }
+            break;
+    }
+    return true;
+}
+
+/**
+ * Define lighting layers.
+ *
+ * Iris rev6a uses WS2812 RGB Matrix lighting.
+ * The RGB Matrix lighting option has already been enabled in ../../rev6a/config.h
+ * You'll need to add #define SPLIT_LAYER_STATE_ENABLE to config.h if you
+ * will be customizing the LED's per key.
+ *
+ * Here's how to customize the colors per layer and per key:
+ * https://github.com/qmk/qmk_firmware/blob/master/docs/feature_rgb_matrix.md#direct-operation-iddirect-operation
+ *
+ * If you start getting real weird with it, your likely to exceed the firmware limit of 28672.
+ * You may need to selectively disable some effects:
+ * https://github.com/qmk/qmk_firmware/blob/master/docs/feature_rgb_matrix.md#rgb-matrix-effects-idrgb-matrix-effects
+ *
+ * There are 68 Leds. Printed on the board itself, the led numbers are 1-68.
+ * For color addressing, use 0-67 as the index number.
+ * rgb_matrix_set_color(index, r, g, b)
+ *
+ * Here's an LED number guide:
+ * FRONT
+ * Left Hand                    Right Hand
+ * |00|01|02|03|04|05|          |39|38|37|36|35|34|
+ * |11|10|09|08|07|06|          |40|41|42|43|44|45|
+ * |12|13|14|15|16|17|          |51|50|49|48|47|46|
+ * |23|22|21|20|19|18|27|    |61|52|53|54|55|56|57|
+ *             |24|25|26|    |60|59|58|
+ * REVERSE
+ * Right Hand                   Left Hand
+ * |65|--|--|66|--|67|          |33|--|32|--|--|31|
+ * |--|--|--|--|--|--|          |--|--|--|--|--|--|
+ * |--|--|--|--|--|--|          |--|--|--|--|--|--|
+ * |64|--|--|63|--|--|--|    |--|--|--|29|--|--|30|
+ *             |--|62|--|    |--|28|--|
+ */
+// void rgb_matrix_indicators_user(void) {
+//   if (IS_LAYER_ON(1)) {
+//     /* Upperleft most key red: */
+//     rgb_matrix_set_color(0,255,0,0);
+//     /* Upperright most front key blue: */
+//     rgb_matrix_set_color(0,0,255,0);
+//     /* Bottom right on lefthand Green: */
+//     rgb_matrix_set_color(0, RGB_GREEN);
+//   }
+//   else if (IS_LAYER_ON(2)) {
+//     /* RGB +/- controls. */
+//     rgb_matrix_set_color(35, RGB_RED);
+//     rgb_matrix_set_color(34, RGB_BLUE);
+//     rgb_matrix_set_color(37, RGB_RED);
+//     rgb_matrix_set_color(36, RGB_BLUE);
+//     rgb_matrix_set_color(44, RGB_RED);
+//     rgb_matrix_set_color(45, RGB_BLUE);
+//     rgb_matrix_set_color(47, RGB_RED);
+//     rgb_matrix_set_color(46, RGB_BLUE);
+//     rgb_matrix_set_color(56, RGB_RED);
+//     rgb_matrix_set_color(57, RGB_BLUE);
+//     /* RGB Toggle. */
+//     rgb_matrix_set_color(00, RGB_PURPLE);
+//     /* Move screen left/right. */
+//     rgb_matrix_set_color(26, RGB_YELLOW);
+//     rgb_matrix_set_color(60, RGB_YELLOW);
+//     /* Arrow keys. */
+//     rgb_matrix_set_color(50, RGB_PURPLE);
+//     rgb_matrix_set_color(49, RGB_PURPLE);
+//     rgb_matrix_set_color(48, RGB_PURPLE);
+//     rgb_matrix_set_color(42, RGB_PURPLE);
+//     /* Mouse movement arrows. */
+//     rgb_matrix_set_color(14, RGB_ORANGE);
+//     rgb_matrix_set_color(15, RGB_ORANGE);
+//     rgb_matrix_set_color(16, RGB_ORANGE);
+//     rgb_matrix_set_color(8, RGB_ORANGE);
+//     /* Mouse buttons. */
+//     rgb_matrix_set_color(41, RGB_ORANGE);
+//     rgb_matrix_set_color(43, RGB_ORANGE);
+//     /* Mouse acceleration. */
+//     rgb_matrix_set_color(01, 200, 165, 0);
+//     rgb_matrix_set_color(02, 255, 200, 0);
+//     rgb_matrix_set_color(03, 255, 235, 0);
+//   }
+// }
+
+/**
+ * Rotary Encoder.
+ *
+ * This can't be programmed through configurator. You must do it here.
+ *
+ * This uses the amazing "Encoder map" feature which replicates the normal keyswitch layer handling functionality, but with encoders.
+ * https://docs.qmk.fm/#/feature_encoders?id=encoder-map 
+ * 
+ * Uses a variant of the Super-alt-tab macro to switch between open applications on a mac. (Command-tab)
+ * https://docs.qmk.fm/#/feature_macros?id=super-alt%e2%86%aftab
+ */
+#if defined(ENCODER_MAP_ENABLE)
+    const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
+        /* Left Hand */                                                     /* Right Hand */
+        /* Switch between tabs. (Control + Tab). */                         /* Switch between open apps on Mac. (Command + Tab + timer logic) */
+        [_QWERTY] =  { ENCODER_CCW_CW(S(C(KC_TAB)), C(KC_TAB)),             ENCODER_CCW_CW(CMD_TAB_CCW, CMD_TAB_CW)  },
+        /* Scrolls left & right. (Shift + Mouse Wheel Up). */               /* Scrolls up and down. (Page Down & Page Up - mouse wheel scroll incraments are too small) */
+        [_LOWER] =  { ENCODER_CCW_CW(S(KC_MS_WH_UP), S(KC_MS_WH_DOWN)),     ENCODER_CCW_CW(KC_PGDN, KC_PGUP)  },
+        /* Selects adjacent words. (Command + Shift + Right Arrow). */      /* Jumps to end/start of line. Hold shift to select. (Gui + arrow). */
+        [_RAISE] =  { ENCODER_CCW_CW(C(S(KC_LEFT)), C(S(KC_RGHT))),         ENCODER_CCW_CW(G(KC_LEFT), G(KC_RGHT))  },
+        /* Scroll through RGB Modes */                                      /* Right & left arrow */
+        [_ADJUST] = { ENCODER_CCW_CW(RGB_RMOD, RGB_MOD),                    ENCODER_CCW_CW(KC_LEFT, KC_RGHT) },
+    };
+#endif
+
+
+/**
+ * Helper function for rotary encoder.
+ *
+ * If the timer has elapsed, the Command/Gui tab will be released.
+ * You can adjust the milliseconds to speed up the CMD key release.
+ */
+void matrix_scan_user(void) {
+    if (is_cmd_tab_active) {
+        if (timer_elapsed(cmd_tab_timer) > 900) {
+            unregister_code(KC_LGUI);
+            is_cmd_tab_active = false;
+        }
+    }
+}
diff --git a/keyboards/keebio/iris/keymaps/two_knob/readme.md b/keyboards/keebio/iris/keymaps/two_knob/readme.md
new file mode 100644
index 0000000000..728650fcb9
--- /dev/null
+++ b/keyboards/keebio/iris/keymaps/two_knob/readme.md
@@ -0,0 +1,15 @@
+# Two Knob Keymap for Iris Rev6a
+![two_knobs](https://i.imgur.com/JqGPWCn.png)
+
+This keymap is derived from Ergodox layouts and is adapted for the [Iris6a](https://docs.keeb.io/iris-rev6-build-guide). It is notable for it's semi-complex programming examples that include the use of rotary encoders.
+
+Plenty of useful examples:
+* Advanced knob programming! (Three-layer usage + clicks)
+* Advanced RGB! (Per-key lighting)
+* Macros! (Fancy key combos tied to the rotary encoders)
+* Tap Dance! (Double tap your '5' key for 'Enter')
+* Dynamic Tapping term! (Dial in the double tap speed)
+
+The qwerty key layout is my adaptation of the ergodox defaults. If this is your first split keyboard, you probably want a different key layout. 
+
+I stopped using the fancy RGB programming pretty quickly. It was a complex to get working initially, so I'm leaving the examples here for others. (As a touch typist - not terribly helpful, but it looks nice). YMMV.
diff --git a/keyboards/keebio/iris/keymaps/two_knob/rules.mk b/keyboards/keebio/iris/keymaps/two_knob/rules.mk
new file mode 100644
index 0000000000..dd49f77547
--- /dev/null
+++ b/keyboards/keebio/iris/keymaps/two_knob/rules.mk
@@ -0,0 +1,15 @@
+# Copyright 2022 Ryan Neff (@JellyTitan)
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Turn on mouse:
+MOUSEKEY_ENABLE = yes
+# Turn on tap dance:
+TAP_DANCE_ENABLE = yes
+# Dynamic Tapping Term:
+DYNAMIC_TAPPING_TERM_ENABLE = yes
+# Replicates the normal keyswitch layer handling functionality, but with encoders:
+ENCODER_MAP_ENABLE = yes
+# Console for debug:
+# This is enabled by the parent iris rev6a config - turning it off saves us some space.
+# You can find the other iris default options here:  keyboards/keebio/iris/rev6a/rules.mk
+CONSOLE_ENABLE = no
diff --git a/keyboards/keebio/iris/keymaps/two_knob/two_knob.json b/keyboards/keebio/iris/keymaps/two_knob/two_knob.json
new file mode 100644
index 0000000000..62fb931873
--- /dev/null
+++ b/keyboards/keebio/iris/keymaps/two_knob/two_knob.json
@@ -0,0 +1,185 @@
+{
+  "version": 1,
+  "notes": "Based on legacy Ergodox layouts.",
+  "documentation": "\"This file is a QMK Configurator export. You can import this at <https://config.qmk.fm>. It can also be used directly with QMK's source code.\n\nTo setup your QMK environment check out the tutorial: <https://docs.qmk.fm/#/newbs>\n\nYou can convert this file to a keymap.c using this command: `qmk json2c {keymap}`\n\nYou can compile this keymap using this command: `qmk compile {keymap}`\"\n",
+  "keyboard": "keebio/iris/rev6a",
+  "keymap": "two_knob",
+  "layout": "LAYOUT",
+  "layers": [
+    [
+      "KC_EQL",
+      "KC_1",
+      "KC_2",
+      "KC_3",
+      "KC_4",
+      "ANY(TD_FIVE_ENTER)",
+      "KC_6",
+      "KC_7",
+      "KC_8",
+      "KC_9",
+      "KC_0",
+      "KC_MINS",
+      "KC_TAB",
+      "KC_Q",
+      "KC_W",
+      "KC_E",
+      "KC_R",
+      "KC_T",
+      "KC_Y",
+      "KC_U",
+      "KC_I",
+      "KC_O",
+      "KC_P",
+      "KC_BSLS",
+      "LT(1,KC_DEL)",
+      "LT(2,KC_A)",
+      "LCTL_T(KC_S)",
+      "KC_D",
+      "LGUI_T(KC_F)",
+      "KC_G",
+      "KC_H",
+      "RGUI_T(KC_J)",
+      "KC_K",
+      "RCTL_T(KC_L)",
+      "LT(2,KC_SCLN)",
+      "LT(1,KC_QUOT)",
+      "KC_LSPO",
+      "LALT_T(KC_Z)",
+      "KC_X",
+      "KC_C",
+      "KC_V",
+      "KC_B",
+      "ANY(KC_MINIM)",
+      "ANY(KC_MAXIM)",
+      "KC_N",
+      "KC_M",
+      "KC_COMM",
+      "KC_DOT",
+      "RALT_T(KC_SLSH)",
+      "KC_RSPC",
+      "QK_GESC",
+      "KC_SPC",
+      "KC_BSPC",
+      "KC_TAB",
+      "KC_ENT",
+      "KC_DEL"
+    ],
+    [
+      "KC_TRNS",
+      "KC_F1",
+      "KC_F2",
+      "KC_F3",
+      "KC_F4",
+      "KC_F5",
+      "KC_F6",
+      "KC_F7",
+      "KC_F8",
+      "KC_F9",
+      "KC_F10",
+      "KC_F11",
+      "KC_TRNS",
+      "KC_EXLM",
+      "KC_AT",
+      "KC_LCBR",
+      "KC_RCBR",
+      "KC_PIPE",
+      "ANY(DT_PRNT)",
+      "KC_7",
+      "KC_8",
+      "KC_9",
+      "KC_ASTR",
+      "KC_F12",
+      "KC_TRNS",
+      "KC_HASH",
+      "KC_DLR",
+      "KC_LPRN",
+      "KC_RPRN",
+      "KC_GRV",
+      "ANY(DT_UP)",
+      "KC_4",
+      "KC_5",
+      "KC_6",
+      "KC_PPLS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_HASH",
+      "KC_DLR",
+      "KC_LBRC",
+      "KC_RBRC",
+      "KC_TILD",
+      "KC_TRNS",
+      "KC_TRNS",
+      "ANY(DT_DOWN)",
+      "KC_1",
+      "KC_2",
+      "KC_3",
+      "KC_PSLS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_P0"
+    ],
+    [
+      "RGB_TOG",
+      "KC_ACL0",
+      "KC_ACL1",
+      "KC_ACL2",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "RGB_MOD",
+      "RGB_RMOD",
+      "RGB_HUI",
+      "RGB_HUD",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_MS_U",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_BTN1",
+      "KC_UP",
+      "KC_BTN2",
+      "RGB_SAI",
+      "RGB_SAD",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_MS_L",
+      "KC_MS_D",
+      "KC_MS_R",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_LEFT",
+      "KC_DOWN",
+      "KC_RGHT",
+      "RGB_VAI",
+      "RGB_VAD",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "KC_TRNS",
+      "RGB_SPI",
+      "RGB_SPD",
+      "KC_TRNS",
+      "KC_TRNS",
+      "ANY(KC_CSGLA)",
+      "ANY(KC_CSGRA)",
+      "KC_TRNS",
+      "KC_TRNS"
+    ]
+  ],
+  "author": "https://github.com/JellyTitan"
+}
diff --git a/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/config.h b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/config.h
new file mode 100644
index 0000000000..bbd93cfc16
--- /dev/null
+++ b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/config.h
@@ -0,0 +1,6 @@
+// Copyright 2022 Ryan Neff (@JellyTitan)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define TAPPING_TERM 200
diff --git a/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/keymap.c b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/keymap.c
new file mode 100644
index 0000000000..6f21c630bf
--- /dev/null
+++ b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/keymap.c
@@ -0,0 +1,56 @@
+// Copyright 2022 Ryan Neff (@JellyTitan)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+enum tapdance_keycodes { 
+    TD_KEY_1,
+    TD_KEY_2
+};
+
+void dance_key_one(qk_tap_dance_state_t *state, void *user_data) {
+    if (state->count == 1) {
+        /* Copy for Mac. */
+        /* Windows & Linux use Ctrl+C: tap_code16(C(KC_C)) */
+        tap_code16(G(KC_C));
+        reset_tap_dance(state);
+    } else if (state->count == 2) {
+        /* Cut for Mac. */
+        /* Windows & Linux use Ctrl+X: tap_code16(C(KC_X)) */
+        tap_code16(G(KC_X));
+        reset_tap_dance(state);
+    } else if (state->count == 3) {
+        /* Plain old Tab. */
+        tap_code(KC_TAB);
+        reset_tap_dance(state);
+    }
+}
+
+void dance_key_two(qk_tap_dance_state_t *state, void *user_data) {
+    if (state->count == 1) {
+        /* Paste for Mac. */
+        /* Windows & Linux use Ctrl+V: tap_code16(C(KC_V)) */
+        tap_code16(G(KC_V));
+        reset_tap_dance(state);
+    } else if (state->count == 2) {
+        /* Paste as value Gui+Shift+V for Mac. */
+        /* Windows & Linux use Ctrl+Shift V: tap_code16(C(S(KC_V))) */
+        tap_code16(G(S(KC_V)));
+        reset_tap_dance(state);
+    } else if (state->count == 3) {
+        /* Tab between programs for mac Gui+Tab.  */
+        /* Windows & Linux use Ctrl+Tab: tap_code16(C(KC_TAB)) */
+        tap_code16(G(KC_TAB));
+        reset_tap_dance(state);
+    }
+}
+
+qk_tap_dance_action_t tap_dance_actions[] = {
+    [TD_KEY_1] = ACTION_TAP_DANCE_FN(dance_key_one), 
+    [TD_KEY_2] = ACTION_TAP_DANCE_FN(dance_key_two)
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+    [0] = LAYOUT(TD(TD_KEY_1),
+    TD(TD_KEY_2))
+};
diff --git a/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/readme.md b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/readme.md
new file mode 100644
index 0000000000..722e7491bc
--- /dev/null
+++ b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/readme.md
@@ -0,0 +1,18 @@
+# Copypasta Macfancy Keymap for Milk 2%
+
+![copypasta_macfancy](https://i.imgur.com/7LMZZrL.png)
+
+Extra fancy copy/paste utilities for the Milk 2% keyboard on MacOS. Milk 2% designed by [Spaceman](https://github.com/Spaceboards/SpaceboardsHardware/tree/master/Keyboards/2%25%20Milk).
+
+Uses Tapping term for double and tripple tapping.
+Tapping speed can be adjusted with TAPPING_TERM in config.h
+
+### Key One
+- 1 Tap: Copy
+- 2 Taps: Cut
+- 3 Taps: Tab
+
+### Key Two
+- 1 Tap: Paste
+- 2 Taps: Paste as Value
+- 3 Taps: Tab between programs
diff --git a/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/rules.mk b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/rules.mk
new file mode 100644
index 0000000000..628a960a71
--- /dev/null
+++ b/keyboards/spaceman/2_milk/keymaps/copypasta_macfancy/rules.mk
@@ -0,0 +1,4 @@
+# Copyright 2022 Ryan Neff (@JellyTitan)
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+TAP_DANCE_ENABLE = yes	# Tap Dance