diff --git a/data/constants/keycodes/keycodes_0.0.2.hjson b/data/constants/keycodes/keycodes_0.0.2.hjson
new file mode 100644
index 0000000000..7ba1ecf201
--- /dev/null
+++ b/data/constants/keycodes/keycodes_0.0.2.hjson
@@ -0,0 +1,96 @@
+{
+ "ranges": {
+ "0x0000/0x00FF": {
+ "define": "QK_BASIC"
+ },
+ "0x0100/0x1EFF": {
+ "define": "QK_MODS"
+ },
+ "0x2000/0x1FFF": {
+ "define": "QK_MOD_TAP"
+ },
+ "0x4000/0x0FFF": {
+ "define": "QK_LAYER_TAP"
+ },
+ "0x5000/0x01FF": {
+ "define": "QK_LAYER_MOD"
+ },
+ "0x5200/0x001F": {
+ "define": "QK_TO"
+ },
+ "0x5220/0x001F": {
+ "define": "QK_MOMENTARY"
+ },
+ "0x5240/0x001F": {
+ "define": "QK_DEF_LAYER"
+ },
+ "0x5260/0x001F": {
+ "define": "QK_TOGGLE_LAYER"
+ },
+ "0x5280/0x001F": {
+ "define": "QK_ONE_SHOT_LAYER"
+ },
+ "0x52A0/0x001F": {
+ "define": "QK_ONE_SHOT_MOD"
+ },
+ "0x52C0/0x001F": {
+ "define": "QK_LAYER_TAP_TOGGLE"
+ },
+ // 0x52E0/0x001F - UNUSED
+ // 0x5300/0x02FF - UNUSED
+ "0x5600/0x00FF": {
+ "define": "QK_SWAP_HANDS"
+ },
+ "0x5700/0x00FF": {
+ "define": "QK_TAP_DANCE"
+ },
+ // 0x5800/0x17FF - UNUSED
+ "0x7000/0x00FF": {
+ "define": "QK_MAGIC"
+ },
+ "0x7100/0x00FF": {
+ "define": "QK_MIDI"
+ },
+ "0x7200/0x01FF": {
+ "define": "QK_SEQUENCER"
+ },
+ "0x7400/0x003F": {
+ "define": "QK_JOYSTICK"
+ },
+ "0x7440/0x003F": {
+ "define": "QK_PROGRAMMABLE_BUTTON"
+ },
+ "0x7480/0x003F": {
+ "define": "QK_AUDIO"
+ },
+ "0x74C0/0x003F": {
+ "define": "QK_STENO"
+ },
+ // 0x7500/0x01FF - UNUSED
+ "0x7700/0x007F": {
+ "define": "QK_MACRO"
+ },
+ // 0x7780/0x007F - UNUSED
+ "0x7800/0x00FF": {
+ "define": "QK_LIGHTING"
+ },
+ // 0x7900/0x02FF - UNUSED
+ "0x7C00/0x01FF": {
+ "define": "QK_QUANTUM"
+ },
+ "0x7E00/0x00FF": {
+ "define": "QK_KB"
+ },
+ "0x7F00/0x00FF": {
+ "define": "QK_USER"
+ },
+ "0x8000/0x7FFF": {
+ "define": "QK_UNICODE"
+ }
+ },
+ "keycodes": {
+ "0x7E00": {
+ "key": "SAFE_RANGE"
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/constants/keycodes/keycodes_0.0.2_basic.hjson b/data/constants/keycodes/keycodes_0.0.2_basic.hjson
new file mode 100644
index 0000000000..b5b038d83b
--- /dev/null
+++ b/data/constants/keycodes/keycodes_0.0.2_basic.hjson
@@ -0,0 +1,12 @@
+{
+ "keycodes": {
+ "0x00E8": {
+ "group": "media",
+ "key": "KC_AIRPLANE_MODE",
+ "label": "Toggle Airplane Mode",
+ "aliases": [
+ "KC_AIRP"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/keycodes.md b/docs/keycodes.md
index f660c7f526..7be03748ae 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -209,6 +209,7 @@ See also: [Basic Keycodes](keycodes_basic.md)
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down |✔ |✔ |✔ |
|`KC_CONTROL_PANEL` |`KC_CPNL` |Open Control Panel |✔ | | |
|`KC_ASSISTANT` |`KC_ASST` |Launch Context-Aware Assistant |✔ | | |
+|`KC_AIRPLANE_MODE` |`KC_AIRP` |Toggle Airplane Mode |✔ | |✔ |
1. The Linux kernel HID driver recognizes [nearly all keycodes](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-input.c), but the default bindings depend on the DE/WM.
2. Treated as F13-F15.
diff --git a/docs/keycodes_basic.md b/docs/keycodes_basic.md
index d2a49100d1..9f8cea5829 100644
--- a/docs/keycodes_basic.md
+++ b/docs/keycodes_basic.md
@@ -223,6 +223,7 @@ These keycodes are not part of the Keyboard/Keypad usage page. The `SYSTEM_` key
|`KC_BRIGHTNESS_DOWN` |`KC_BRID`|Brightness Down |
|`KC_CONTROL_PANEL` |`KC_CPNL`|Open Control Panel |
|`KC_ASSISTANT` |`KC_ASST`|Launch Assistant |
+|`KC_AIRPLANE_MODE` |`KC_AIRP`|Toggle Airplane Mode|
## Number Pad
diff --git a/quantum/action.c b/quantum/action.c
index abf9834d2f..3ea58daf8b 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -532,6 +532,9 @@ void process_action(keyrecord_t *record, action_t action) {
case PAGE_CONSUMER:
host_consumer_send(event.pressed ? action.usage.code : 0);
break;
+ case PAGE_RADIO:
+ host_radio_send(event.pressed);
+ break;
}
break;
#endif
diff --git a/quantum/action_code.h b/quantum/action_code.h
index 58d929016d..7b9230bfa1 100644
--- a/quantum/action_code.h
+++ b/quantum/action_code.h
@@ -198,11 +198,14 @@ enum mods_codes {
enum usage_pages {
PAGE_SYSTEM,
PAGE_CONSUMER,
+ PAGE_RADIO,
};
#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_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key)
+/* Not setting code, defaulting to action.usage.code = 0 */
+#define ACTION_USAGE_RADIO ACTION(ACT_USAGE, PAGE_RADIO << 10)
/** \brief Layer Actions
*/
diff --git a/quantum/keycodes.h b/quantum/keycodes.h
index c013858e78..577917c24f 100644
--- a/quantum/keycodes.h
+++ b/quantum/keycodes.h
@@ -304,6 +304,7 @@ enum qk_keycode_defines {
KC_RIGHT_SHIFT = 0x00E5,
KC_RIGHT_ALT = 0x00E6,
KC_RIGHT_GUI = 0x00E7,
+ KC_AIRPLANE_MODE = 0x00E8,
SH_TG = 0x56F0,
SH_TT = 0x56F1,
SH_MON = 0x56F2,
@@ -863,6 +864,7 @@ enum qk_keycode_defines {
KC_RGUI = KC_RIGHT_GUI,
KC_RCMD = KC_RIGHT_GUI,
KC_RWIN = KC_RIGHT_GUI,
+ KC_AIRP = KC_AIRPLANE_MODE,
CL_SWAP = MAGIC_SWAP_CONTROL_CAPSLOCK,
CL_NORM = MAGIC_UNSWAP_CONTROL_CAPSLOCK,
CL_TOGG = MAGIC_TOGGLE_CONTROL_CAPSLOCK,
@@ -1306,7 +1308,7 @@ enum qk_keycode_defines {
#define IS_INTERNAL_KEYCODE(code) ((code) >= KC_NO && (code) <= KC_TRANSPARENT)
#define IS_BASIC_KEYCODE(code) ((code) >= KC_A && (code) <= KC_EXSEL)
#define IS_SYSTEM_KEYCODE(code) ((code) >= KC_SYSTEM_POWER && (code) <= KC_SYSTEM_WAKE)
-#define IS_MEDIA_KEYCODE(code) ((code) >= KC_AUDIO_MUTE && (code) <= KC_ASSISTANT)
+#define IS_MEDIA_KEYCODE(code) ((code) >= KC_AUDIO_MUTE && (code) <= KC_AIRPLANE_MODE)
#define IS_MOUSE_KEYCODE(code) ((code) >= KC_MS_UP && (code) <= KC_MS_ACCEL2)
#define IS_MODIFIERS_KEYCODE(code) ((code) >= KC_LEFT_CTRL && (code) <= KC_RIGHT_GUI)
#define IS_SWAP_HANDS_KEYCODE(code) ((code) >= SH_TG && (code) <= SH_OS)
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index c4336440f9..3111402ee4 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -64,6 +64,9 @@ action_t action_for_keycode(uint16_t keycode) {
case KC_AUDIO_MUTE ... KC_ASSISTANT:
action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
break;
+ case KC_AIRPLANE_MODE:
+ action.code = ACTION_USAGE_RADIO;
+ break;
#endif
case KC_MS_UP ... KC_MS_ACCEL2:
action.code = ACTION_MOUSEKEY(keycode);
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 62a11faff7..4804b6825f 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -959,6 +959,30 @@ void send_extra(report_extra_t *report) {
#endif
}
+void send_radio(report_radio_t *report) {
+#ifdef EXTRAKEY_ENABLE
+ osalSysLock();
+ if (usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+ osalSysUnlock();
+ return;
+ }
+
+ if (usbGetTransmitStatusI(&USB_DRIVER, SHARED_IN_EPNUM)) {
+ /* Need to either suspend, or loop and call unlock/lock during
+ * every iteration - otherwise the system will remain locked,
+ * no interrupts served, so USB not going through as well.
+ * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
+ if (osalThreadSuspendTimeoutS(&(&USB_DRIVER)->epc[SHARED_IN_EPNUM]->in_state->thread, TIME_MS2I(10)) == MSG_TIMEOUT) {
+ osalSysUnlock();
+ return;
+ }
+ }
+
+ usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)report, sizeof(report_radio_t));
+ osalSysUnlock();
+#endif
+}
+
void send_programmable_button(report_programmable_button_t *report) {
#ifdef PROGRAMMABLE_BUTTON_ENABLE
osalSysLock();
diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c
index 2c6654e9a6..6d12e56812 100644
--- a/tmk_core/protocol/host.c
+++ b/tmk_core/protocol/host.c
@@ -159,6 +159,21 @@ void host_consumer_send(uint16_t usage) {
(*driver->send_extra)(&report);
}
+void host_radio_send(bool state) {
+ if (!driver) return;
+
+ /* It's a toggle button, state==true means to toggle it.
+ * !state means there's no change. */
+ if (!state) return;
+
+ report_radio_t report = {
+ .report_id = REPORT_ID_RADIO,
+ .state = (uint8_t)state,
+ };
+ send_radio(&report);
+}
+__attribute__((weak)) void send_radio(report_radio_t *report) {}
+
#ifdef JOYSTICK_ENABLE
void host_joystick_send(joystick_t *joystick) {
if (!driver) return;
diff --git a/tmk_core/protocol/host.h b/tmk_core/protocol/host.h
index dfa86cd7b5..16f1844d59 100644
--- a/tmk_core/protocol/host.h
+++ b/tmk_core/protocol/host.h
@@ -47,6 +47,7 @@ void host_keyboard_send(report_keyboard_t *report);
void host_mouse_send(report_mouse_t *report);
void host_system_send(uint16_t usage);
void host_consumer_send(uint16_t usage);
+void host_radio_send(bool usage);
void host_programmable_button_send(uint32_t data);
uint16_t host_last_system_usage(void);
diff --git a/tmk_core/protocol/host_driver.h b/tmk_core/protocol/host_driver.h
index 7dc6c3d810..9c22bff3fa 100644
--- a/tmk_core/protocol/host_driver.h
+++ b/tmk_core/protocol/host_driver.h
@@ -33,3 +33,4 @@ typedef struct {
void send_joystick(report_joystick_t *report);
void send_digitizer(report_digitizer_t *report);
void send_programmable_button(report_programmable_button_t *report);
+void send_radio(report_radio_t *report);
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 8f36e02b9a..cdcdea9d64 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -612,6 +612,12 @@ void send_programmable_button(report_programmable_button_t *report) {
#endif
}
+void send_radio(report_radio_t *report) {
+#ifdef EXTRAKEY_ENABLE
+ send_report(SHARED_IN_EPNUM, report, sizeof(report_radio_t));
+#endif
+}
+
void send_digitizer(report_digitizer_t *report) {
#ifdef DIGITIZER_ENABLE
send_report(DIGITIZER_IN_EPNUM, report, sizeof(report_digitizer_t));
diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h
index e4526e4ee6..54be534f7b 100644
--- a/tmk_core/protocol/report.h
+++ b/tmk_core/protocol/report.h
@@ -29,6 +29,7 @@ enum hid_report_ids {
REPORT_ID_MOUSE,
REPORT_ID_SYSTEM,
REPORT_ID_CONSUMER,
+ REPORT_ID_RADIO,
REPORT_ID_PROGRAMMABLE_BUTTON,
REPORT_ID_NKRO,
REPORT_ID_JOYSTICK,
@@ -196,6 +197,11 @@ typedef struct {
uint16_t usage;
} __attribute__((packed)) report_extra_t;
+typedef struct {
+ uint8_t report_id;
+ uint8_t state;
+} __attribute__((packed)) report_radio_t;
+
typedef struct {
uint8_t report_id;
uint32_t usage;
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 02f1c089d3..b0135dea0a 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -320,6 +320,20 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_REPORT_SIZE(8, 16),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
+
+ HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
+ HID_RI_USAGE(8, 0x0C), // Wireless Radio Controls
+ HID_RI_COLLECTION(8, 0x01), // Application
+ HID_RI_REPORT_ID(8, REPORT_ID_RADIO),
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(8, 0x01),
+ HID_RI_USAGE(8, 0xC6), // Wireless Radio Button
+ HID_RI_REPORT_COUNT(8, 1),
+ HID_RI_REPORT_SIZE(8, 1),
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
+ HID_RI_REPORT_SIZE(8, 7),
+ HID_RI_INPUT(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+ HID_RI_END_COLLECTION(0),
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 8816ff44c4..96b43e1440 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -303,6 +303,14 @@ void send_programmable_button(report_programmable_button_t *report) {
#endif
}
+void send_radio(report_radio_t *report) {
+#ifdef EXTRAKEY_ENABLE
+ if (usbInterruptIsReadyShared()) {
+ usbSetInterruptShared((void *)report, sizeof(report_radio_t));
+ }
+#endif
+}
+
/*------------------------------------------------------------------*
* Request from host *
*------------------------------------------------------------------*/
@@ -536,6 +544,20 @@ const PROGMEM uchar shared_hid_report[] = {
0x75, 0x10, // Report Size (16)
0x81, 0x00, // Input (Data, Array, Absolute)
0xC0, // End Collection
+
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x0C, // USAGE (Wireless Radio Controls)
+ 0xA1, 0x01, // COLLECTION (Application)
+ 0x85, REPORT_ID_RADIO, // Report ID (Radio)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x09, 0xC6, // Usage (Wireless Radio Button)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x06, // Input (Data, Variable, Relative)
+ 0x75, 0x07, // Report Size (7)
+ 0x81, 0x03, // INPUT (Constant, Variable, Absolute)
+ 0xC0, // End Collection
#endif
#ifdef JOYSTICK_ENABLE