diff --git a/share/man/man4/hkbd.4 b/share/man/man4/hkbd.4 index 6e936b19861..4aefad10846 100644 --- a/share/man/man4/hkbd.4 +++ b/share/man/man4/hkbd.4 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 12, 2020 +.Dd April 23, 2026 .Dt HKBD 4 .Os .Sh NAME @@ -151,6 +151,18 @@ tunables: Debug output level, where 0 is debugging disabled and larger values increase debug message verbosity. Default is 0. +.It Va hw.hid.hkbd.apple_swap_cmd_opt +Swap the Command & Option keys on Apple keyboards if set to 1. +Default is 0. +.It Va hw.hid.hkbd.apple_swap_cmd_ctl +Swap the Command & Control keys on Apple keyboards if set to 1. +Default is 0. +.It Va hw.hid.hkbd.apple_fn_mode +Direct access to media keys without holding Fn if set to 1. +Default is 0. +.It Va hw.hid.hkbd.no_leds +Disables setting of keyboard LEDs if set to 1. +Default is 0. .El .Sh FILES .Bl -tag -width ".Pa /dev/input/event*" -compact diff --git a/share/man/man4/ukbd.4 b/share/man/man4/ukbd.4 index 14d6cca51e6..003600aac08 100644 --- a/share/man/man4/ukbd.4 +++ b/share/man/man4/ukbd.4 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 24, 2018 +.Dd April 23, 2026 .Dt UKBD 4 .Os .Sh NAME @@ -156,6 +156,18 @@ tunables: Debug output level, where 0 is debugging disabled and larger values increase debug message verbosity. Default is 0. +.It Va hw.usb.ukbd.apple_swap_cmd_opt +Swap the Command & Option keys on Apple keyboards if set to 1. +Default is 0. +.It Va hw.usb.ukbd.apple_swap_cmd_ctl +Swap the Command & Control keys on Apple keyboards if set to 1. +Default is 0. +.It Va hw.usb.ukbd.apple_fn_mode +Direct access to media keys without holding Fn if set to 1. +Default is 0. +.It Va hw.usb.ukbd.no_leds +Disables setting of keyboard LEDs if set to 1. +Default is 0. .El .Sh FILES .Bl -tag -width ".Pa /dev/kbd*" -compact diff --git a/sys/dev/hid/hkbd.c b/sys/dev/hid/hkbd.c index c98f4be6916..edfd3f5d4ef 100644 --- a/sys/dev/hid/hkbd.c +++ b/sys/dev/hid/hkbd.c @@ -100,6 +100,8 @@ static int hkbd_debug = 0; #endif static int hkbd_no_leds = 0; static int hkbd_apple_fn_mode = 0; +static int hkbd_apple_swap_cmd_ctl = 0; +static int hkbd_apple_swap_cmd_opt = 0; static SYSCTL_NODE(_hw_hid, OID_AUTO, hkbd, CTLFLAG_RW, 0, "USB keyboard"); #ifdef HID_DEBUG @@ -110,6 +112,10 @@ SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, no_leds, CTLFLAG_RWTUN, &hkbd_no_leds, 0, "Disables setting of keyboard leds"); SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, apple_fn_mode, CTLFLAG_RWTUN, &hkbd_apple_fn_mode, 0, "0 = Fn + F1..12 -> media, 1 = F1..F12 -> media"); +SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, apple_swap_cmd_ctl, CTLFLAG_RWTUN, + &hkbd_apple_swap_cmd_ctl, 0, "Swap Command & Control keys"); +SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, apple_swap_cmd_opt, CTLFLAG_RWTUN, + &hkbd_apple_swap_cmd_opt, 0, "Swap Command & Option keys"); #define INPUT_EPOCH global_epoch_preempt @@ -664,6 +670,30 @@ hkbd_apple_fn_media(uint32_t keycode) } } +static uint32_t +hkbd_apple_doswap_cmd_ctl(uint32_t keycode) +{ + switch (keycode) { + case 0xe3: return 0xe0; /* LCMD -> LCTL */ + case 0xe7: return 0xe4; /* RCMD -> RCTL */ + case 0xe0: return 0xe3; /* LCTL -> LCMD */ + case 0xe4: return 0xe7; /* RCTL -> RCMD */ + default: return keycode; + } +} + +static uint32_t +hkbd_apple_doswap_cmd_opt(uint32_t keycode) +{ + switch (keycode) { + case 0xe3: return 0xe2; /* LCMD -> ROPT */ + case 0xe7: return 0xe6; /* RCMD -> ROPT */ + case 0xe2: return 0xe3; /* LOPT -> LCMD */ + case 0xe6: return 0xe7; /* ROPT -> RCMD */ + default: return keycode; + } +} + static uint32_t hkbd_apple_swap(uint32_t keycode) { @@ -765,6 +795,10 @@ hkbd_intr_callback(void *context, void *data, hid_size_t len) key = hkbd_apple_fn(key); if (apply_apple_fn_media) key = hkbd_apple_fn_media(key); + if (hkbd_apple_swap_cmd_ctl) + key = hkbd_apple_doswap_cmd_ctl(key); + if (hkbd_apple_swap_cmd_opt) + key = hkbd_apple_doswap_cmd_opt(key); if (sc->sc_flags & HKBD_FLAG_APPLE_SWAP) key = hkbd_apple_swap(key); if (key == KEY_NONE || key >= HKBD_NKEYCODE) @@ -780,6 +814,10 @@ hkbd_intr_callback(void *context, void *data, hid_size_t len) key = hkbd_apple_fn(key); if (apply_apple_fn_media) key = hkbd_apple_fn_media(key); + if (hkbd_apple_swap_cmd_ctl) + key = hkbd_apple_doswap_cmd_ctl(key); + if (hkbd_apple_swap_cmd_opt) + key = hkbd_apple_doswap_cmd_opt(key); if (sc->sc_flags & HKBD_FLAG_APPLE_SWAP) key = hkbd_apple_swap(key); if (key == KEY_NONE || key == KEY_ERROR || key >= HKBD_NKEYCODE) diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 7a33a9ad2ef..104e51c082c 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -99,6 +99,8 @@ static int ukbd_debug = 0; static int ukbd_no_leds = 0; static int ukbd_pollrate = 0; static int ukbd_apple_fn_mode = 0; +static int ukbd_apple_swap_cmd_ctl = 0; +static int ukbd_apple_swap_cmd_opt = 0; static SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "USB keyboard"); @@ -112,6 +114,10 @@ SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RWTUN, &ukbd_pollrate, 0, "Force this polling rate, 1-1000Hz"); SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, apple_fn_mode, CTLFLAG_RWTUN, &ukbd_apple_fn_mode, 0, "0 = Fn + F1..12 -> media, 1 = F1..F12 -> media"); +SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, apple_swap_cmd_ctl, CTLFLAG_RWTUN, + &ukbd_apple_swap_cmd_ctl, 0, "Swap Command & Control keys"); +SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, apple_swap_cmd_opt, CTLFLAG_RWTUN, + &ukbd_apple_swap_cmd_opt, 0, "Swap Command & Option keys"); #define UKBD_EMULATE_ATSCANCODE 1 #define UKBD_DRIVER_NAME "ukbd" @@ -720,6 +726,30 @@ ukbd_apple_fn_media(uint32_t keycode) } } +static uint32_t +ukbd_apple_doswap_cmd_ctl(uint32_t keycode) +{ + switch (keycode) { + case 0xe3: return 0xe0; /* LCMD -> LCTL */ + case 0xe7: return 0xe4; /* RCMD -> RCTL */ + case 0xe0: return 0xe3; /* LCTL -> LCMD */ + case 0xe4: return 0xe7; /* RCTL -> RCMD */ + default: return keycode; + } +} + +static uint32_t +ukbd_apple_doswap_cmd_opt(uint32_t keycode) +{ + switch (keycode) { + case 0xe3: return 0xe2; /* LCMD -> ROPT */ + case 0xe7: return 0xe6; /* RCMD -> ROPT */ + case 0xe2: return 0xe3; /* LOPT -> LCMD */ + case 0xe6: return 0xe7; /* ROPT -> RCMD */ + default: return keycode; + } +} + static uint32_t ukbd_apple_swap(uint32_t keycode) { @@ -839,6 +869,10 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) key = ukbd_apple_fn(key); if (apply_apple_fn_media) key = ukbd_apple_fn_media(key); + if (ukbd_apple_swap_cmd_ctl) + key = ukbd_apple_doswap_cmd_ctl(key); + if (ukbd_apple_swap_cmd_opt) + key = ukbd_apple_doswap_cmd_opt(key); if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) key = ukbd_apple_swap(key); if (key == KEY_NONE || key >= UKBD_NKEYCODE) @@ -853,6 +887,10 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error) key = ukbd_apple_fn(key); if (apply_apple_fn_media) key = ukbd_apple_fn_media(key); + if (ukbd_apple_swap_cmd_ctl) + key = ukbd_apple_doswap_cmd_ctl(key); + if (ukbd_apple_swap_cmd_opt) + key = ukbd_apple_doswap_cmd_opt(key); if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) key = ukbd_apple_swap(key); if (key == KEY_NONE || key == KEY_ERROR || key >= UKBD_NKEYCODE)