Skip to content

Instantly share code, notes, and snippets.

@bergman
Forked from fauxpark/applefn.patch
Last active December 10, 2021 14:20
Show Gist options
  • Save bergman/bcd41a928408b8991253bf728180aaa7 to your computer and use it in GitHub Desktop.
Save bergman/bcd41a928408b8991253bf728180aaa7 to your computer and use it in GitHub Desktop.
QMK Apple Fn

QMK Apple Fn Key

This patch adds support for the Apple Fn key, which unlike most keyboards with Fn keys, is actually sent over the wire. It works by repurposing the reserved byte in the keyboard report to represent the KeyboardFn usage of the AppleVendor Top Case usage page. To apply this patch, download the below file and run git apply /path/to/applefn.patch. Then, add the KC_APPLE_FN (or KC_APFN for short) keycode to your keymap.

There are a couple of caveats to this implementation, however. Firstly, it is not compatible with NKRO, as the NKRO report in QMK has no need for the reserved byte - it is only there for compatibility with the boot protocol. You may also need to set the USB Vendor and Product IDs to that of a genuine Apple keyboard in order for macOS to recognise the Fn key. This is the primary reason this patch has not been integrated into QMK core - Apple would probably not be too happy about people using their vendor ID, and a feature of QMK that relies on the VID/PID pair being set to a specific value is not ideal anyway.

See qmk/qmk_firmware#2179 for a little more info and discussion.

diff --git a/common_features.mk b/common_features.mk
index 8c593024f0..d70f360470 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -658,40 +658,44 @@ endif
JOYSTICK_ENABLE ?= no
VALID_JOYSTICK_TYPES := analog digital
JOYSTICK_DRIVER ?= analog
ifeq ($(strip $(JOYSTICK_ENABLE)), yes)
ifeq ($(filter $(JOYSTICK_DRIVER),$(VALID_JOYSTICK_TYPES)),)
$(error "$(JOYSTICK_DRIVER)" is not a valid joystick driver)
endif
OPT_DEFS += -DJOYSTICK_ENABLE
SRC += $(QUANTUM_DIR)/process_keycode/process_joystick.c
SRC += $(QUANTUM_DIR)/joystick.c
ifeq ($(strip $(JOYSTICK_DRIVER)), analog)
OPT_DEFS += -DANALOG_JOYSTICK_ENABLE
SRC += analog.c
endif
ifeq ($(strip $(JOYSTICK_DRIVER)), digital)
OPT_DEFS += -DDIGITAL_JOYSTICK_ENABLE
endif
endif
+ifeq ($(strip $(APPLE_FN_ENABLE)), yes)
+ OPT_DEFS += -DAPPLE_FN_ENABLE
+endif
+
USBPD_ENABLE ?= no
VALID_USBPD_DRIVER_TYPES = custom vendor
USBPD_DRIVER ?= vendor
ifeq ($(strip $(USBPD_ENABLE)), yes)
ifeq ($(filter $(strip $(USBPD_DRIVER)),$(VALID_USBPD_DRIVER_TYPES)),)
$(error USBPD_DRIVER="$(USBPD_DRIVER)" is not a valid USBPD driver)
else
OPT_DEFS += -DUSBPD_ENABLE
ifeq ($(strip $(USBPD_DRIVER)), vendor)
# Vendor-specific implementations
OPT_DEFS += -DUSBPD_VENDOR
ifeq ($(strip $(MCU_SERIES)), STM32G4xx)
OPT_DEFS += -DUSBPD_STM32G4
SRC += usbpd_stm32g4.c
else
$(error There is no vendor-provided USBPD driver available)
endif
else ifeq ($(strip $(USBPD_DRIVER)), custom)
OPT_DEFS += -DUSBPD_CUSTOM
# Board designers can add their own driver to $(SRC)
diff --git a/quantum/action.c b/quantum/action.c
index 5e81efb671..c44eb5cd60 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -438,40 +438,50 @@ void process_action(keyrecord_t *record, action_t action) {
/* other HID usage */
case ACT_USAGE:
switch (action.usage.page) {
case PAGE_SYSTEM:
if (event.pressed) {
host_system_send(action.usage.code);
} else {
host_system_send(0);
}
break;
case PAGE_CONSUMER:
if (event.pressed) {
host_consumer_send(action.usage.code);
} else {
host_consumer_send(0);
}
break;
}
break;
#endif
+#ifdef APPLE_FN_ENABLE
+ /* Apple Fn */
+ case ACT_APPLE_FN:
+ if (event.pressed) {
+ register_code(KC_APPLE_FN);
+ } else {
+ unregister_code(KC_APPLE_FN);
+ }
+ break;
+#endif
#ifdef MOUSEKEY_ENABLE
/* Mouse key */
case ACT_MOUSEKEY:
if (event.pressed) {
mousekey_on(action.key.code);
} else {
mousekey_off(action.key.code);
}
switch (action.key.code) {
# if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE)
# ifdef POINTING_DEVICE_ENABLE
case KC_MS_BTN1 ... KC_MS_BTN8:
# else
case KC_MS_BTN1 ... KC_MS_BTN3:
# endif
register_button(event.pressed, MOUSE_BTN_MASK(action.key.code - KC_MS_BTN1));
break;
# endif
default:
mousekey_send();
@@ -860,40 +870,47 @@ void register_code(uint8_t code) {
// modifiers will be reported incorrectly, see issue #1708
if (is_key_pressed(keyboard_report, code)) {
del_key(code);
send_keyboard_report();
}
add_key(code);
send_keyboard_report();
}
}
else if
IS_MOD(code) {
add_mods(MOD_BIT(code));
send_keyboard_report();
}
#ifdef EXTRAKEY_ENABLE
else if
IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
else if
IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
#endif
+#ifdef APPLE_FN_ENABLE
+ else if
+ IS_APPLE_FN(code) {
+ add_key(code);
+ send_keyboard_report();
+ }
+#endif
#ifdef MOUSEKEY_ENABLE
else if
IS_MOUSEKEY(code) {
mousekey_on(code);
mousekey_send();
}
#endif
}
/** \brief Utilities for actions. (FIXME: Needs better description)
*
* FIXME: Needs documentation.
*/
void unregister_code(uint8_t code) {
if (code == KC_NO) {
return;
}
#ifdef LOCKING_SUPPORT_ENABLE
else if (KC_LOCKING_CAPS_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
@@ -924,40 +941,47 @@ void unregister_code(uint8_t code) {
send_keyboard_report();
del_key(KC_SCROLL_LOCK);
send_keyboard_report();
}
#endif
else if
IS_KEY(code) {
del_key(code);
send_keyboard_report();
}
else if
IS_MOD(code) {
del_mods(MOD_BIT(code));
send_keyboard_report();
}
else if
IS_SYSTEM(code) { host_system_send(0); }
else if
IS_CONSUMER(code) { host_consumer_send(0); }
+#ifdef APPLE_FN_ENABLE
+ else if
+ IS_APPLE_FN(code) {
+ del_key(code);
+ send_keyboard_report();
+ }
+#endif
#ifdef MOUSEKEY_ENABLE
else if
IS_MOUSEKEY(code) {
mousekey_off(code);
mousekey_send();
}
#endif
}
/** \brief Tap a keycode with a delay.
*
* \param code The basic keycode to tap.
* \param delay The amount of time in milliseconds to leave the keycode registered, before unregistering it.
*/
void tap_code_delay(uint8_t code, uint16_t delay) {
register_code(code);
for (uint16_t i = delay; i > 0; i--) {
wait_ms(1);
}
unregister_code(code);
@@ -1134,40 +1158,43 @@ void debug_record(keyrecord_t record) {
*
* FIXME: Needs documentation.
*/
void debug_action(action_t action) {
switch (action.kind.id) {
case ACT_LMODS:
dprint("ACT_LMODS");
break;
case ACT_RMODS:
dprint("ACT_RMODS");
break;
case ACT_LMODS_TAP:
dprint("ACT_LMODS_TAP");
break;
case ACT_RMODS_TAP:
dprint("ACT_RMODS_TAP");
break;
case ACT_USAGE:
dprint("ACT_USAGE");
break;
+ case ACT_APPLE_FN:
+ dprint("ACT_APPLE_FN");
+ break;
case ACT_MOUSEKEY:
dprint("ACT_MOUSEKEY");
break;
case ACT_LAYER:
dprint("ACT_LAYER");
break;
case ACT_LAYER_MODS:
dprint("ACT_LAYER_MODS");
break;
case ACT_LAYER_TAP:
dprint("ACT_LAYER_TAP");
break;
case ACT_LAYER_TAP_EXT:
dprint("ACT_LAYER_TAP_EXT");
break;
case ACT_MACRO:
dprint("ACT_MACRO");
break;
case ACT_FUNCTION:
dprint("ACT_FUNCTION");
diff --git a/quantum/action_code.h b/quantum/action_code.h
index eb18c36ae8..f6ffc0d68a 100644
--- a/quantum/action_code.h
+++ b/quantum/action_code.h
@@ -34,41 +34,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* ACT_MODS_TAP(001r):
* 001r|mods|0000 0000 Modifiers with OneShot
* 001r|mods|0000 0001 Modifiers with tap toggle
* 001r|mods|0000 00xx (reserved)
* 001r|mods| keycode Modifiers with Tap Key(Dual role)
*
* Other Keys(01xx)
* ----------------
* ACT_USAGE(0100): TODO: Not needed?
* 0100|00| usage(10) System control(0x80) - General Desktop page(0x01)
* 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C)
* 0100|10| usage(10) (reserved)
* 0100|11| usage(10) (reserved)
*
* ACT_MOUSEKEY(0101): TODO: Merge these two actions to conserve space?
* 0101|xxxx| keycode Mouse key
*
* ACT_SWAP_HANDS(0110):
* 0110|xxxx| keycode Swap hands (keycode on tap, or options)
*
- * 0111|xxxx xxxx xxxx (reserved)
+ * ACT_APPLE_FN(0111):
+ * 0111|0000|0000|0000 Apple Fn
*
* Layer Actions(10xx)
* -------------------
* ACT_LAYER(1000):
* 1000|oo00|pppE BBBB Default Layer Bitwise operation
* oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
* ppp: 4-bit chunk part(0-7)
* EBBBB: bits and extra bit
* 1000|ooee|pppE BBBB Layer Bitwise Operation
* oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
* ppp: 4-bit chunk part(0-7)
* EBBBB: bits and extra bit
* ee: on event(01:press, 10:release, 11:both)
*
* ACT_LAYER_MODS(1001):
* 1001|LLLL| mods Layer with modifiers held
*
* ACT_LAYER_TAP(101x):
* 101E|LLLL| keycode On/Off with tap key (0x00-DF)[TAP]
* 101E|LLLL|1110 mods On/Off with modifiers (0xE0-EF)[NOT TAP]
@@ -89,40 +90,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* 1101|xxxx xxxx xxxx (reserved)
* 1110|xxxx xxxx xxxx (reserved)
*
* ACT_FUNCTION(1111):
* 1111| address(12) Function?
* 1111|opt | id(8) Function?
*/
enum action_kind_id {
/* Key Actions */
ACT_MODS = 0b0000,
ACT_LMODS = 0b0000,
ACT_RMODS = 0b0001,
ACT_MODS_TAP = 0b0010,
ACT_LMODS_TAP = 0b0010,
ACT_RMODS_TAP = 0b0011,
/* Other Keys */
ACT_USAGE = 0b0100,
ACT_MOUSEKEY = 0b0101,
/* One-hand Support */
ACT_SWAP_HANDS = 0b0110,
+ /* Apple Fn */
+ ACT_APPLE_FN = 0b0111,
/* Layer Actions */
ACT_LAYER = 0b1000,
ACT_LAYER_MODS = 0b1001,
ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */
ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */
/* Extensions */
ACT_MACRO = 0b1100,
ACT_FUNCTION = 0b1111
};
/** \brief Action Code Struct
*
* NOTE:
* In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15).
* AVR looks like a little endian in avr-gcc.
* Not portable across compiler/endianness?
*
* Byte order and bit order of 0x1234:
* Big endian: Little endian:
* -------------------- --------------------
@@ -199,40 +202,41 @@ enum mods_bit {
MOD_RSFT = 0x12,
MOD_RALT = 0x14,
MOD_RGUI = 0x18,
};
enum mods_codes {
MODS_ONESHOT = 0x00,
MODS_TAP_TOGGLE = 0x01,
};
#define ACTION_KEY(key) ACTION(ACT_MODS, (key))
#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | 0)
#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f) << 8 | (key))
#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | (key))
#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_ONESHOT)
#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f) << 8 | MODS_TAP_TOGGLE)
/** \brief Other Keys
*/
enum usage_pages { PAGE_SYSTEM, PAGE_CONSUMER };
#define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM << 10 | (id))
#define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER << 10 | (id))
+#define ACTION_APPLE_FN() ACTION(ACT_APPLE_FN, 0)
#define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key)
/** \brief Layer Actions
*/
enum layer_param_on {
ON_PRESS = 1,
ON_RELEASE = 2,
ON_BOTH = 3,
};
/** \brief Layer Actions
*/
enum layer_param_bit_op {
OP_BIT_AND = 0,
OP_BIT_OR = 1,
OP_BIT_XOR = 2,
OP_BIT_SET = 3,
};
/** \brief Layer Actions
diff --git a/quantum/keycode.h b/quantum/keycode.h
index 38a29b439b..50699e8d48 100644
--- a/quantum/keycode.h
+++ b/quantum/keycode.h
@@ -17,40 +17,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
* Keycodes based on HID Keyboard/Keypad Usage Page (0x07) plus media keys from Generic Desktop Page (0x01) and Consumer Page (0x0C)
*
* See https://web.archive.org/web/20060218214400/http://www.usb.org/developers/devclass_docs/Hut1_12.pdf
* or http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (older)
*/
#pragma once
/* FIXME: Add doxygen comments here */
#define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED)
#define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF)
#define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL)
#define IS_MOD(code) (KC_LEFT_CTRL <= (code) && (code) <= KC_RIGHT_GUI)
#define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF))
#define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE)
#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_BRID)
+#define IS_APPLE_FN(code) (KC_APFN == (code))
#define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31)
#define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2)
#define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT)
#define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN8)
#define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT)
#define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2)
#define MOD_BIT(code) (1 << MOD_INDEX(code))
#define MOD_INDEX(code) ((code)&0x07)
#define MOD_MASK_CTRL (MOD_BIT(KC_LEFT_CTRL) | MOD_BIT(KC_RIGHT_CTRL))
#define MOD_MASK_SHIFT (MOD_BIT(KC_LEFT_SHIFT) | MOD_BIT(KC_RIGHT_SHIFT))
#define MOD_MASK_ALT (MOD_BIT(KC_LEFT_ALT) | MOD_BIT(KC_RIGHT_ALT))
#define MOD_MASK_GUI (MOD_BIT(KC_LEFT_GUI) | MOD_BIT(KC_RIGHT_GUI))
#define MOD_MASK_CS (MOD_MASK_CTRL | MOD_MASK_SHIFT)
#define MOD_MASK_CA (MOD_MASK_CTRL | MOD_MASK_ALT)
#define MOD_MASK_CG (MOD_MASK_CTRL | MOD_MASK_GUI)
#define MOD_MASK_SA (MOD_MASK_SHIFT | MOD_MASK_ALT)
@@ -196,40 +197,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KC_MNXT KC_MEDIA_NEXT_TRACK
#define KC_MPRV KC_MEDIA_PREV_TRACK
#define KC_MSTP KC_MEDIA_STOP
#define KC_MPLY KC_MEDIA_PLAY_PAUSE
#define KC_MSEL KC_MEDIA_SELECT
#define KC_EJCT KC_MEDIA_EJECT
#define KC_CALC KC_CALCULATOR
#define KC_MYCM KC_MY_COMPUTER
#define KC_WSCH KC_WWW_SEARCH
#define KC_WHOM KC_WWW_HOME
#define KC_WBAK KC_WWW_BACK
#define KC_WFWD KC_WWW_FORWARD
#define KC_WSTP KC_WWW_STOP
#define KC_WREF KC_WWW_REFRESH
#define KC_WFAV KC_WWW_FAVORITES
#define KC_MFFD KC_MEDIA_FAST_FORWARD
#define KC_MRWD KC_MEDIA_REWIND
#define KC_BRIU KC_BRIGHTNESS_UP
#define KC_BRID KC_BRIGHTNESS_DOWN
+/* Apple Fn */
+#define KC_APFN KC_APPLE_FN
+
/* System Specific */
#define KC_BRMU KC_PAUSE
#define KC_BRMD KC_SCROLL_LOCK
/* Mouse Keys */
#define KC_MS_U KC_MS_UP
#define KC_MS_D KC_MS_DOWN
#define KC_MS_L KC_MS_LEFT
#define KC_MS_R KC_MS_RIGHT
#define KC_BTN1 KC_MS_BTN1
#define KC_BTN2 KC_MS_BTN2
#define KC_BTN3 KC_MS_BTN3
#define KC_BTN4 KC_MS_BTN4
#define KC_BTN5 KC_MS_BTN5
#define KC_BTN6 KC_MS_BTN6
#define KC_BTN7 KC_MS_BTN7
#define KC_BTN8 KC_MS_BTN8
#define KC_WH_U KC_MS_WH_UP
#define KC_WH_D KC_MS_WH_DOWN
#define KC_WH_L KC_MS_WH_LEFT
@@ -494,40 +498,43 @@ enum internal_special_keycodes {
KC_MEDIA_PREV_TRACK,
KC_MEDIA_STOP,
KC_MEDIA_PLAY_PAUSE,
KC_MEDIA_SELECT,
KC_MEDIA_EJECT, // 0xB0
KC_MAIL,
KC_CALCULATOR,
KC_MY_COMPUTER,
KC_WWW_SEARCH,
KC_WWW_HOME,
KC_WWW_BACK,
KC_WWW_FORWARD,
KC_WWW_STOP,
KC_WWW_REFRESH,
KC_WWW_FAVORITES,
KC_MEDIA_FAST_FORWARD,
KC_MEDIA_REWIND,
KC_BRIGHTNESS_UP,
KC_BRIGHTNESS_DOWN,
+ /* Apple Fn */
+ KC_APPLE_FN,
+
/* Fn keys */
KC_FN0 = 0xC0,
KC_FN1,
KC_FN2,
KC_FN3,
KC_FN4,
KC_FN5,
KC_FN6,
KC_FN7,
KC_FN8,
KC_FN9,
KC_FN10,
KC_FN11,
KC_FN12,
KC_FN13,
KC_FN14,
KC_FN15,
KC_FN16, // 0xD0
KC_FN17,
KC_FN18,
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index 5007f15f11..901989790d 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -50,40 +50,45 @@ action_t action_for_keycode(uint16_t keycode) {
action_t action = {};
uint8_t action_layer, when, mod;
(void)action_layer;
(void)when;
(void)mod;
switch (keycode) {
case KC_A ... KC_EXSEL:
case KC_LEFT_CTRL ... KC_RIGHT_GUI:
action.code = ACTION_KEY(keycode);
break;
#ifdef EXTRAKEY_ENABLE
case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
break;
case KC_AUDIO_MUTE ... KC_BRIGHTNESS_DOWN:
action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
break;
#endif
+#ifdef APPLE_FN_ENABLE
+ case KC_APPLE_FN:
+ action.code = ACTION_APPLE_FN();
+ break;
+#endif
#ifdef MOUSEKEY_ENABLE
case KC_MS_UP ... KC_MS_ACCEL2:
action.code = ACTION_MOUSEKEY(keycode);
break;
#endif
case KC_TRANSPARENT:
action.code = ACTION_TRANSPARENT;
break;
case QK_MODS ... QK_MODS_MAX:;
// Has a modifier
// Split it up
action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key
break;
#ifndef NO_ACTION_FUNCTION
case KC_FN0 ... KC_FN31:
action.code = keymap_function_id_to_action(FN_INDEX(keycode));
break;
case QK_FUNCTION ... QK_FUNCTION_MAX:;
// Is a shortcut for function action_layer, pull last 12bits
// This means we have 4,096 FN macros at our disposal
diff --git a/tmk_core/protocol/report.c b/tmk_core/protocol/report.c
index 854b59ae48..ed9659f56d 100644
--- a/tmk_core/protocol/report.c
+++ b/tmk_core/protocol/report.c
@@ -224,54 +224,66 @@ void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
}
/** \brief del key bit
*
* FIXME: Needs doc
*/
void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
if ((code >> 3) < KEYBOARD_REPORT_BITS) {
keyboard_report->nkro.bits[code >> 3] &= ~(1 << (code & 7));
} else {
dprintf("del_key_bit: can't del: %02X\n", code);
}
}
#endif
/** \brief add key to report
*
* FIXME: Needs doc
*/
void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#ifdef APPLE_FN_ENABLE
+ if IS_APPLE_FN(key) {
+ keyboard_report->reserved = 1;
+ return;
+ }
+#endif
#ifdef NKRO_ENABLE
if (keyboard_protocol && keymap_config.nkro) {
add_key_bit(keyboard_report, key);
return;
}
#endif
add_key_byte(keyboard_report, key);
}
/** \brief del key from report
*
* FIXME: Needs doc
*/
void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#ifdef APPLE_FN_ENABLE
+ if IS_APPLE_FN(key) {
+ keyboard_report->reserved = 0;
+ return;
+ }
+#endif
#ifdef NKRO_ENABLE
if (keyboard_protocol && keymap_config.nkro) {
del_key_bit(keyboard_report, key);
return;
}
#endif
del_key_byte(keyboard_report, key);
}
/** \brief clear key from report
*
* FIXME: Needs doc
*/
void clear_keys_from_report(report_keyboard_t* keyboard_report) {
// not clear mods
#ifdef NKRO_ENABLE
if (keyboard_protocol && keymap_config.nkro) {
memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits));
return;
}
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index a43755f899..116b057ae6 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -54,44 +54,56 @@
const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
# define SHARED_REPORT_STARTED
#else
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = {
#endif
HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
HID_RI_USAGE(8, 0x06), // Keyboard
HID_RI_COLLECTION(8, 0x01), // Application
#ifdef KEYBOARD_SHARED_EP
HID_RI_REPORT_ID(8, REPORT_ID_KEYBOARD),
#endif
// Modifiers (8 bits)
HID_RI_USAGE_PAGE(8, 0x07), // Keyboard/Keypad
HID_RI_USAGE_MINIMUM(8, 0xE0), // Keyboard Left Control
HID_RI_USAGE_MAXIMUM(8, 0xE7), // Keyboard Right GUI
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
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),
+
+#ifdef APPLE_FN_ENABLE
+ 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),
HID_RI_USAGE_MAXIMUM(8, 0xFF),
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
HID_RI_REPORT_COUNT(8, 0x06),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
// Status LEDs (5 bits)
HID_RI_USAGE_PAGE(8, 0x08), // LED
HID_RI_USAGE_MINIMUM(8, 0x01), // Num Lock
HID_RI_USAGE_MAXIMUM(8, 0x05), // Kana
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
// LED padding (3 bits)
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index bd0f1c21aa..1f4554647f 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -408,44 +408,56 @@ void usbFunctionWriteOut(uchar *data, uchar len) {
const PROGMEM uchar shared_hid_report[] = {
# define SHARED_REPORT_STARTED
#else
const PROGMEM uchar keyboard_hid_report[] = {
#endif
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
#ifdef KEYBOARD_SHARED_EP
0x85, REPORT_ID_KEYBOARD, // Report ID
#endif
// Modifiers (8 bits)
0x05, 0x07, // Usage Page (Keyboard/Keypad)
0x19, 0xE0, // Usage Minimum (Keyboard Left Control)
0x29, 0xE7, // Usage Maximum (Keyboard Right GUI)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x08, // Report Count (8)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
+
+#ifdef APPLE_FN_ENABLE
+ 0x05, 0xFF, // Usage Page (AppleVendor Top Case)
+ 0x09, 0x03, // Usage (KeyboardFn)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+#else
// Reserved (1 byte)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Constant)
+#endif
+
// Keycodes (6 bytes)
0x05, 0x07, // Usage Page (Keyboard/Keypad)
0x19, 0x00, // Usage Minimum (0)
0x29, 0xFF, // Usage Maximum (255)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x81, 0x00, // Input (Data, Array, Absolute)
// Status LEDs (5 bits)
0x05, 0x08, // Usage Page (LED)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x91, 0x02, // Output (Data, Variable, Absolute)
// LED padding (3 bits)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment