this makes the extra keys on most apple macbooks and apple
usb/bluetooth-via-usb keyboards work like they do in mac os. most
importantly, fn+up arrow does page up, fn+down does page down,
fn+left does home, fn+right does end, fn+backspace does delete, and
fn+return does insert. it also makes fn+f10 mute, fn+f11 lower the
volume, and fn+f12 raise the volume through the wscons/audio stuff
already in place.
i've only tested it on a 1st gen macbook air and on a generic usb
keyboard that didn't break. some of this code comes from freebsd
and netbsd.
please test on usb-connected keyboards, especially on any apples.
Index: dev/usb/ukbd.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ukbd.c,v
retrieving revision 1.55
diff -u -p -u -p -r1.55 ukbd.c
--- dev/usb/ukbd.c 3 Jul 2011 15:47:17 -0000 1.55
+++ dev/usb/ukbd.c 11 Jul 2011 03:45:29 -0000
@@ -132,6 +132,9 @@ struct ukbd_softc {
u_char sc_dying;
+ int sc_apple_fn;
+ struct hid_location sc_apple_fn_loc;
+
void (*sc_munge)(void *, uint8_t *, u_int);
};
@@ -182,6 +185,7 @@ struct ukbd_translation {
#ifdef __loongson__
void ukbd_gdium_munge(void *, uint8_t *, u_int);
#endif
+void ukbd_apple_munge(void *, uint8_t *, u_int);
uint8_t ukbd_translate(const struct ukbd_translation *, size_t,
uint8_t);
int
@@ -207,15 +211,18 @@ ukbd_attach(struct device *parent, struc
struct hidkbd *kbd = &sc->sc_kbd;
struct usb_attach_arg *uaa = aux;
struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ struct hid_data *d;
+ struct hid_item h;
usb_hid_descriptor_t *hid;
u_int32_t qflags;
- int dlen, repid;
+ int dlen, repid, size;
void *desc;
kbd_t layout = (kbd_t)-1;
sc->sc_hdev.sc_intr = ukbd_intr;
sc->sc_hdev.sc_parent = uha->parent;
sc->sc_hdev.sc_report_id = uha->reportid;
+ sc->sc_apple_fn = 0;
uhidev_get_report_desc(uha->parent, &desc, &dlen);
repid = uha->reportid;
@@ -227,6 +234,25 @@ ukbd_attach(struct device *parent, struc
if (hidkbd_attach(self, kbd, 1, qflags, repid, desc, dlen) != 0)
return;
+ /* check for apple keyboards that need Fn-key help */
+ if (uha->uaa->vendor == USB_VENDOR_APPLE) {
+ uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
+ d = hid_start_parse(desc, size, hid_input);
+ while (hid_get_item(d, &h)) {
+ if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff &&
+ HID_GET_USAGE(h.usage) == 0x0003 &&
+ h.kind == hid_input && (h.flags & HIO_VARIABLE)) {
+ sc->sc_apple_fn = 1;
+ sc->sc_apple_fn_loc = h.loc;
+ sc->sc_munge = ukbd_apple_munge;
+#ifdef DIAGNOSTIC
+ printf(", apple Fn-key help\n");
+#endif
+ }
+ }
+ hid_end_parse(d);
+ }
+
if (uha->uaa->vendor == USB_VENDOR_TOPRE &&
uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) {
/* ignore country code on purpose */
@@ -437,6 +463,50 @@ ukbd_translate(const struct ukbd_transla
if (table->original == keycode)
return table->translation;
return 0;
+}
+
+void
+ukbd_apple_munge(void *vsc, uint8_t *ibuf, u_int ilen)
+{
+ struct ukbd_softc *sc = vsc;
+ struct hidkbd *kbd = &sc->sc_kbd;
+ uint8_t *pos, *spos, *epos, xlat;
+
+ static const struct ukbd_translation apple_fn_trans[] = {
+ { 40, 73 }, /* return -> insert */
+ { 42, 76 }, /* backspace -> delete */
+#ifdef notyet
+ { 58, 0 }, /* F1 -> screen brightness down */
+ { 59, 0 }, /* F2 -> screen brightness up */
+ { 60, 0 }, /* F3 */
+ { 61, 0 }, /* F4 */
+ { 62, 0 }, /* F5 -> keyboard backlight down */
+ { 63, 0 }, /* F6 -> keyboard backlight up */
+ { 64, 0 }, /* F7 -> audio back */
+ { 65, 0 }, /* F8 -> audio pause/play */
+ { 66, 0 }, /* F9 -> audio next */
+#endif
+ { 67, 127 }, /* F10 -> audio mute */
+ { 68, 128 }, /* F11 -> audio volume down */
+ { 69, 129 }, /* F12 -> audio volume up */
+ { 79, 77 }, /* right -> end */
+ { 80, 74 }, /* left -> home */
+ { 81, 78 }, /* down -> page down */
+ { 82, 75 } /* up -> page up */
+ };
+
+ if (!hid_get_data(ibuf, &sc->sc_apple_fn_loc))
+ return;
+
+ spos = ibuf + kbd->sc_keycodeloc.pos / 8;
+ epos = spos + kbd->sc_nkeycode;
+
+ for (pos = spos; pos != epos; pos++) {
+ xlat = ukbd_translate(apple_fn_trans,
+ nitems(apple_fn_trans), *pos);
+ if (xlat != 0)
+ *pos = xlat;
+ }
}
#ifdef __loongson__