[PATCH evdev 3/4] Add a property to toggle fnmode on Apple keyboards
Peter Hutterer
peter.hutterer at who-t.net
Tue May 17 22:00:57 PDT 2011
On Apple keyboards, the multimedia function keys are overlaid with the F
keys. F1 is also BrightnessDown, F10 is Mute, etc. The kernel provides a
tweak to enable/disable this.
/sys/module/hid_apple/parameters/fnmode
0 .. keyboard sends Fx keys
1 .. keyboard sends multimedia keys
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
include/evdev-properties.h | 3 +
src/Makefile.am | 3 +-
src/apple.c | 168 ++++++++++++++++++++++++++++++++++++++++++++
src/evdev.c | 1 +
src/evdev.h | 1 +
5 files changed, 175 insertions(+), 1 deletions(-)
create mode 100644 src/apple.c
diff --git a/include/evdev-properties.h b/include/evdev-properties.h
index 16f2af7..8887cd1 100644
--- a/include/evdev-properties.h
+++ b/include/evdev-properties.h
@@ -75,4 +75,7 @@
/* CARD32 */
#define EVDEV_PROP_THIRDBUTTON_THRESHOLD "Evdev Third Button Emulation Threshold"
+/* BOOL, 1 value, true → send function keys, false → send multimedia keys */
+#define EVDEV_PROP_APPLE_FNMODE "Evdev Apple Function Keys"
+
#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index d1efe53..b3a5671 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,5 +37,6 @@ AM_CPPFLAGS =-I$(top_srcdir)/include
emuMB.c \
emuThird.c \
emuWheel.c \
- draglock.c
+ draglock.c \
+ apple.c
diff --git a/src/apple.c b/src/apple.c
new file mode 100644
index 0000000..1a82e2a
--- /dev/null
+++ b/src/apple.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Peter Hutterer (peter.hutterer at redhat.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <evdev.h>
+#include <evdev-properties.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <exevents.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <X11/Xatom.h>
+
+/* Apple-specific controls.
+ *
+ * On Apple keyboards, the multimedia function keys are overlaid with the F
+ * keys. F1 is also BrightnessDown, F10 is Mute, etc. The kernel provides a
+ * tweak to enable/disable this.
+ *
+ * /sys/module/hid_apple/parameters/fnmode
+ * 0 .. keyboard sends Fx keys
+ * 1 .. keyboard sends multimedia keys
+ */
+
+#define FNMODE_PATH "/sys/module/hid_apple/parameters/fnmode"
+#define APPLE_VENDOR 0x5ac
+#define APPLE_KEYBOARD 0x220
+
+static Atom prop_fnmode;
+static Bool fnmode_readonly; /* set if we can only read fnmode */
+
+
+/**
+ * @retval 0 fnmode is set to function keys
+ * @retval 1 fnmode is set to multimedia keys
+ * @retval -1 Error, see errno
+ */
+static int
+get_fnmode(void)
+{
+ int fd;
+ char retvalue;
+
+ fd = open(FNMODE_PATH, O_RDWR);
+ if (fd < 0)
+ {
+ if (errno == EACCES)
+ {
+ fnmode_readonly = TRUE;
+ fd = open(FNMODE_PATH, O_RDONLY);
+ }
+ }
+
+ if (fd < 0)
+ return -1;
+
+ if (read(fd, &retvalue, 1) != 1)
+ return -1;
+
+ close(fd);
+
+ if (retvalue != '0' && retvalue != '1')
+ {
+ xf86Msg(X_ERROR, "Invalid fnmode value: %c\n", retvalue);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return retvalue == '1';
+}
+
+/**
+ * @param fnmode 0 for function keys, 1 for multimedia keys
+ * @return 0 on success, -1 otherwise (check errno)
+ */
+static int
+set_fnmode(Bool fnmode)
+{
+ int fd;
+ char mode;
+
+ fd = open(FNMODE_PATH, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ mode = fnmode ? '1' : '0';
+
+ if (write(fd, &mode, 1) != 1)
+ return -1;
+
+ close(fd);
+
+ return 0;
+}
+
+static int
+EvdevAppleSetProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly)
+{
+ if (atom == prop_fnmode)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (fnmode_readonly)
+ return BadAccess;
+
+ if (!checkonly)
+ set_fnmode(*(CARD8*)val->data);
+ }
+
+ return Success;
+}
+
+void
+EvdevAppleInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+ char fnmode;
+
+ if (pEvdev->id_vendor != APPLE_VENDOR ||
+ pEvdev->id_product != APPLE_KEYBOARD)
+ return;
+
+ fnmode = get_fnmode();
+ if (fnmode == -1)
+ {
+ xf86IDrvMsg(pInfo, X_ERROR, "Failed to get fnmode (%s)\n", strerror(errno));
+ return;
+ }
+
+ prop_fnmode = MakeAtom(EVDEV_PROP_APPLE_FNMODE, strlen(EVDEV_PROP_APPLE_FNMODE), TRUE);
+ XIChangeDeviceProperty(dev, prop_fnmode, XA_INTEGER, 8,
+ PropModeReplace, 1, &fnmode, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_fnmode, FALSE);
+ XIRegisterPropertyHandler(dev, EvdevAppleSetProperty, NULL, NULL);
+}
diff --git a/src/evdev.c b/src/evdev.c
index d93adb4..38868c4 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1359,6 +1359,7 @@ EvdevInit(DeviceIntPtr device)
Evdev3BEmuInitProperty(device);
EvdevWheelEmuInitProperty(device);
EvdevDragLockInitProperty(device);
+ EvdevAppleInitProperty(device);
return Success;
}
diff --git a/src/evdev.h b/src/evdev.h
index 1741e59..6434c3f 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -243,4 +243,5 @@ void EvdevMBEmuInitProperty(DeviceIntPtr);
void Evdev3BEmuInitProperty(DeviceIntPtr);
void EvdevWheelEmuInitProperty(DeviceIntPtr);
void EvdevDragLockInitProperty(DeviceIntPtr);
+void EvdevAppleInitProperty(DeviceIntPtr);
#endif
--
1.7.4.4
More information about the xorg-devel
mailing list