Skip to content

Instantly share code, notes, and snippets.

@arkku
Last active March 3, 2024 14:22
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arkku/95e661db1377342a7ce570a8d5bc9850 to your computer and use it in GitHub Desktop.
Save arkku/95e661db1377342a7ce570a8d5bc9850 to your computer and use it in GitHub Desktop.
Patch for QMK firmware to add two keycodes for Apple Fn: KC_APFN simulates the key directly, whereas APFN_LAYER(x) works as MO(x) but also registers as holding down Apple Fn _when no other key is pressed_. APFN_KEY(x) is key x together with Apple Fn.
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index c976b8296d..335b432e78 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -108,6 +108,12 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/mousekey.c
endif
+ifeq ($(strip $(APPLE_FN_ENABLE)), yes)
+ OPT_DEFS += -DAPPLE_FN_ENABLE -DENABLE_APPLE_FN_KEY=1
+else
+ OPT_DEFS += -DENABLE_APPLE_FN_KEY=0
+endif
+
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pmw3389 pimoroni_trackball custom
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
diff --git a/keyboards/gmmk/pro/config.h b/keyboards/gmmk/pro/config.h
index aba69c8872..aa1a262d90 100644
--- a/keyboards/gmmk/pro/config.h
+++ b/keyboards/gmmk/pro/config.h
@@ -20,8 +20,13 @@
/* USB Device descriptor parameter */
#define DEVICE_VER 0x0001
+#if ENABLE_APPLE_FN_KEY
+#define VENDOR_ID 0x05AC
+#define PRODUCT_ID 0x021E
+#else
#define VENDOR_ID 0x320F
#define PRODUCT_ID 0x5044
+#endif
#define MANUFACTURER Glorious
#define PRODUCT GMMK Pro
diff --git a/keyboards/gmmk/pro/rev1/iso/rules.mk b/keyboards/gmmk/pro/rev1/iso/rules.mk
index d3afa4d432..fccc7035b6 100644
--- a/keyboards/gmmk/pro/rev1/iso/rules.mk
+++ b/keyboards/gmmk/pro/rev1/iso/rules.mk
@@ -8,14 +8,15 @@ BOOTLOADER = stm32-dfu
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
-MOUSEKEY_ENABLE = yes # Mouse keys
+MOUSEKEY_ENABLE = no # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
-NKRO_ENABLE = yes # Enable N-Key Rollover
+NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
ENCODER_ENABLE = yes
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = AW20216
+APPLE_FN_ENABLE = yes
diff --git a/quantum/action.c b/quantum/action.c
index 4e81a5466f..cc6e53c102 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -306,6 +306,10 @@ void register_button(bool pressed, enum mouse_buttons button) {
}
#endif
+#if ENABLE_APPLE_FN_KEY
+static bool virtual_apple_fn_on = false;
+#endif
+
/** \brief Take an action and processes it.
*
* FIXME: Needs documentation.
@@ -585,6 +589,53 @@ void process_action(keyrecord_t *record, action_t action) {
layer_off(action.layer_mods.layer);
}
break;
+#if ENABLE_APPLE_FN_KEY
+ case ACT_APPLE_FN:
+ if (event.pressed) {
+ if (action.key.code) {
+ if (!virtual_apple_fn_on) {
+ add_key(KC_APPLE_FN);
+ send_keyboard_report();
+ virtual_apple_fn_on = true;
+ }
+ add_key(action.key.code);
+ send_keyboard_report();
+ } else {
+ virtual_apple_fn_on = false;
+ register_code(KC_APPLE_FN);
+ }
+ } else {
+ if (action.key.code) {
+ del_key(action.key.code);
+ if (virtual_apple_fn_on) {
+ del_key(KC_APPLE_FN);
+ virtual_apple_fn_on = false;
+ }
+ send_keyboard_report();
+ } else {
+ unregister_code(KC_APPLE_FN);
+ }
+ }
+ break;
+#ifdef NO_ACTION_TAPPING
+ case ACT_LAYER_TAP:
+ case ACT_LAYER_TAP_EXT:
+ if (action.layer_tap.code == OP_APPLE_FN) {
+ if (event.pressed) {
+ layer_on(action.layer_tap.val);
+ register_code(KC_APPLE_FN);
+ virtual_apple_fn_on = true;
+ } else {
+ if (virtual_apple_fn_on) {
+ virtual_apple_fn_on = false;
+ unregister_code(KC_APPLE_FN);
+ }
+ layer_off(action.layer_tap.val);
+ }
+ }
+ break;
+#endif
+#endif
# ifndef NO_ACTION_TAPPING
case ACT_LAYER_TAP:
case ACT_LAYER_TAP_EXT:
@@ -653,6 +704,21 @@ void process_action(keyrecord_t *record, action_t action) {
}
break;
# endif
+#if ENABLE_APPLE_FN_KEY
+ case OP_APPLE_FN:
+ if (event.pressed) {
+ layer_on(action.layer_tap.val);
+ register_code(KC_APPLE_FN);
+ virtual_apple_fn_on = true;
+ } else {
+ if (virtual_apple_fn_on) {
+ virtual_apple_fn_on = false;
+ unregister_code(KC_APPLE_FN);
+ }
+ layer_off(action.layer_tap.val);
+ }
+ break;
+#endif
default:
/* tap key */
if (event.pressed) {
@@ -892,6 +958,13 @@ __attribute__((weak)) void register_code(uint8_t code) {
*/
#endif
{
+#if ENABLE_APPLE_FN_KEY
+ if (virtual_apple_fn_on) {
+ del_key(KC_APPLE_FN);
+ send_keyboard_report();
+ virtual_apple_fn_on = false;
+ }
+#endif
// Force a new key press if the key is already pressed
// without this, keys with the same keycode, but different
// modifiers will be reported incorrectly, see issue #1708
@@ -919,6 +992,12 @@ __attribute__((weak)) void register_code(uint8_t code) {
mousekey_send();
}
#endif
+#if ENABLE_APPLE_FN_KEY
+ else if (code == KC_APPLE_FN) {
+ add_key(code);
+ send_keyboard_report();
+ }
+#endif
}
/** \brief Utilities for actions. (FIXME: Needs better description)
@@ -979,6 +1058,12 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
mousekey_send();
}
#endif
+#if ENABLE_APPLE_FN_KEY
+ else if (code == KC_APPLE_FN) {
+ del_key(code);
+ send_keyboard_report();
+ }
+#endif
}
/** \brief Tap a keycode with a delay.
diff --git a/quantum/action_code.h b/quantum/action_code.h
index 20b3e459d2..4409ac4618 100644
--- a/quantum/action_code.h
+++ b/quantum/action_code.h
@@ -51,6 +51,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* ACT_SWAP_HANDS(0110):
* 0110|xxxx| keycode Swap hands (keycode on tap, or options)
*
+ * 0111|0001 xxxx xxxx Apple Fn + key
* 0111|xxxx xxxx xxxx (reserved)
*
* Layer Actions(10xx)
@@ -77,8 +78,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* 101E|LLLL|1111 0010 Off/On (0xF2) [NOT TAP]
* 101E|LLLL|1111 0011 Set/Clear (0xF3) [NOT TAP]
* 101E|LLLL|1111 0100 One Shot Layer (0xF4) [TAP]
- * 101E|LLLL|1111 xxxx Reserved (0xF5-FF)
- * ELLLL: layer 0-31(E: extra bit for layer 16-31)
+ * 101E|LLLL|1111 0101 Apple Fn Layer (0xF5)
+ * 101E|LLLL|1111 xxxx Reserved (0xF6-FF)
*/
enum action_kind_id {
/* Key Actions */
@@ -98,6 +99,9 @@ enum action_kind_id {
ACT_LAYER_MODS = 0b1001,
ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */
ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */
+#if ENABLE_APPLE_FN_KEY
+ ACT_APPLE_FN = 0b0111
+#endif
};
/** \brief Action Code Struct
@@ -222,6 +226,9 @@ enum layer_param_tap_op {
OP_OFF_ON,
OP_SET_CLEAR,
OP_ONESHOT,
+#if ENABLE_APPLE_FN_KEY
+ OP_APPLE_FN
+#endif
};
#define ACTION_LAYER_BITOP(op, part, bits, on) ACTION(ACT_LAYER, (op) << 10 | (on) << 8 | (part) << 5 | ((bits)&0x1f))
#define ACTION_LAYER_TAP(layer, key) ACTION(ACT_LAYER_TAP, (layer) << 8 | (key))
@@ -254,6 +261,12 @@ enum layer_param_tap_op {
#define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0)
#define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0)
+#if ENABLE_APPLE_FN_KEY
+#define ACTION_APPLE_FN_KEY(key) ACTION(ACT_APPLE_FN, (key))
+#define ACTION_APPLE_FN() ACTION_APPLE_FN_KEY(0)
+#define ACTION_APPLE_FN_LAYER(layer) ACTION_LAYER_TAP((layer), OP_APPLE_FN)
+#endif
+
/* OneHand Support */
enum swap_hands_param_tap_op {
OP_SH_TOGGLE = 0xF0,
diff --git a/quantum/keycode.h b/quantum/keycode.h
index 3c80a386d1..762b1bf73f 100644
--- a/quantum/keycode.h
+++ b/quantum/keycode.h
@@ -502,9 +502,17 @@ enum internal_special_keycodes {
KC_MEDIA_FAST_FORWARD,
KC_MEDIA_REWIND,
KC_BRIGHTNESS_UP,
- KC_BRIGHTNESS_DOWN
+ KC_BRIGHTNESS_DOWN,
+
+#if ENABLE_APPLE_FN_KEY
+ KC_APFN,
+#endif
};
+#if ENABLE_APPLE_FN_KEY
+#define KC_APPLE_FN KC_APFN
+#endif
+
enum mouse_keys {
/* Mouse Buttons */
#ifdef VIA_ENABLE
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index c1940f0fd3..efda95d52c 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -58,6 +58,17 @@ action_t action_for_keycode(uint16_t keycode) {
case KC_LEFT_CTRL ... KC_RIGHT_GUI:
action.code = ACTION_KEY(keycode);
break;
+#if ENABLE_APPLE_FN_KEY
+ case KC_APPLE_FN:
+ action.code = ACTION_APPLE_FN();
+ break;
+ case QK_APPLE_FN_MOD ... QK_APPLE_FN_MOD_MAX:
+ action.code = ACTION_APPLE_FN_KEY(keycode & 0xFF);
+ break;
+ case QK_APPLE_FN ... QK_APPLE_FN_MAX:
+ action.code = ACTION_APPLE_FN_LAYER(keycode & 0x1F);
+ break;
+#endif
#ifdef EXTRAKEY_ENABLE
case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 40355d799a..c99a814cf6 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -37,6 +37,12 @@ enum quantum_keycodes {
QK_RALT = 0x1400,
QK_RGUI = 0x1800,
QK_MODS_MAX = 0x1FFF,
+#if ENABLE_APPLE_FN_KEY
+ QK_APPLE_FN_MOD = 0x3E00,
+ QK_APPLE_FN_MOD_MAX = 0x3EFF,
+ QK_APPLE_FN = 0x3FE0,
+ QK_APPLE_FN_MAX = 0x3FFF,
+#endif
QK_LAYER_TAP = 0x4000,
QK_LAYER_TAP_MAX = 0x4FFF,
QK_TO = 0x5000,
@@ -823,6 +829,11 @@ enum quantum_keycodes {
// L-ayer, T-ap - 256 keycode max, 16 layer max
#define LT(layer, kc) (QK_LAYER_TAP | (((layer)&0xF) << 8) | ((kc)&0xFF))
+#if ENABLE_APPLE_FN_KEY
+#define APFN_LAYER(layer) (QK_APPLE_FN | ((layer) & 0x1F))
+#define APFN_KEY(key) (QK_APPLE_FN_MOD | ((key) & 0xFF))
+#endif
+
// M-od, T-ap - 256 keycode max
#define MT(mod, kc) (QK_MOD_TAP | (((mod)&0x1F) << 8) | ((kc)&0xFF))
diff --git a/tmk_core/protocol/report.c b/tmk_core/protocol/report.c
index 5755098c60..ab596b603e 100644
--- a/tmk_core/protocol/report.c
+++ b/tmk_core/protocol/report.c
@@ -241,6 +241,12 @@ void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
* FIXME: Needs doc
*/
void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#if ENABLE_APPLE_FN_KEY
+ if (key == KC_APPLE_FN) {
+ keyboard_report->reserved = 1;
+ return;
+ }
+#endif
#ifdef NKRO_ENABLE
if (keyboard_protocol && keymap_config.nkro) {
add_key_bit(keyboard_report, key);
@@ -255,6 +261,12 @@ void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) {
* FIXME: Needs doc
*/
void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#if ENABLE_APPLE_FN_KEY
+ if (key == KC_APFN) {
+ keyboard_report->reserved = 0;
+ return;
+ }
+#endif
#ifdef NKRO_ENABLE
if (keyboard_protocol && keymap_config.nkro) {
del_key_bit(keyboard_report, key);
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 063bd2c3f1..a7fc5672b6 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -71,10 +71,22 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = {
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+
+#if ENABLE_APPLE_FN_KEY
+ HID_RI_USAGE_PAGE(8, 0xFF), // AppleVendor Top Case
+ HID_RI_USAGE(8, 0x03), // KeyboardFn
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01),
+ HID_RI_REPORT_COUNT(8, 0x01),
+ HID_RI_REPORT_SIZE(8, 0x08),
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+#else
// Reserved (1 byte)
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_CONSTANT),
+#endif
+
// Keycodes (6 bytes)
HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
HID_RI_USAGE_MINIMUM(8, 0x00),
@arkku
Copy link
Author

arkku commented Dec 12, 2022

@nitsujri Hi, I can look into it at some point, but you may have luck with this fork of QMK, branch feature/apple_fn: https://github.com/arkku/qmk_firmware/tree/feature/apple_fn

@nitsujri
Copy link

I just tried to merge qmk master into your apple_fn branch, there's only 3 files that conflict but they conflict in ways that I don't understand (something like 5k files changed,phew!). Like I can't find where:

#define KC_INT6 KC_INTERNATIONAL_6
#define KC_INT7 KC_INTERNATIONAL_7
#define KC_INT8 KC_INTERNATIONAL_8
#define KC_INT9 KC_INTERNATIONAL_9
#define KC_LNG1 KC_LANGUAGE_1
#define KC_LNG2 KC_LANGUAGE_2
#define KC_LNG3 KC_LANGUAGE_3
#define KC_LNG4 KC_LANGUAGE_4
#define KC_LNG5 KC_LANGUAGE_5
#define KC_LNG6 KC_LANGUAGE_6
#define KC_LNG7 KC_LANGUAGE_7
#define KC_LNG8 KC_LANGUAGE_8

This block of keycode.h is now gone? as well as a large chunk of quantum_keycodes.h has disappeared.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment