Thinkpad Fn-F8: Toggle Touchpad - working in oS 12.1

Installation of oS 12.1 with KDE on a Thinkpad T520 up to know really nice!

Linux 3.1.9-1.4-desktop x86_64
openSUSE 12.1 (x86_64)
KDE: 4.7.2 (4.7.2) “release 5”

With the help of khotkeys all Thinkpad hotkeys worked - all but one: Fn-F8 !

Trying to assign Fn-F8, which is recognized as XF86TouchpadToggle by xev, is not supported by Qt, and therefore leads to a message like “the key you pressed is not supported by Qt” (Sorry, don’t know the exact message in English since I installed DE language support) in the synaptics applet.

This pulls us back to basics: acpi_hotkey

Unfortunately a previous solution Thinkpad Fn-F8: Toggle Touchpad Example does not work any more since I was not able to get the display settings and credentials for X11 fixed in /usr/lib/acpid/thinkpad_handler.
Because of this probably all attempts with xvkbd failed as well.

Searching for a solution (I need to get this touchpad disabled while typing text and especially while scrolling with the Thinkstick ) I found acpi_fakekey. However here also a apparently deprecated method using /dev/input/event0 (which is the keyboard on my machine) was used.

So finally I found a solution using /dev/uinput that I would like to share.
It still kind of strange: We intercept the Fn-F8 key event, which is ignored by Qt and inject instead an Ctrl-Alt-T event into Qt, which is mapped by the synaptic applet in KDE.


/* 	$Id: acpi_fake_alt-ctrl-t.c,v 1.8 2012/03/10 20:11:01 root Exp $	 */

#ifndef lint
static char vcid] = "$Id: acpi_fake_alt-ctrl-t.c,v 1.8 2012/03/10 20:11:01 root Exp $";
#endif /* lint */

/* 
   Boundary conditions:
   - KDE environment
   - synaptics driver active
   - ALT-CTRL-T defined as ToggleTouchpad command in synaptics applet
   - Fn-F8 ignored by Qt (thats why can't simply redefine it)

   Feed in the three keys acc. /usr/include/linux/input.h
       KEY_T, KEY_LEFTALT, KEY_LEFTCTRL 
*/


/* based on

   acpi_fakekey.c nach

   http://en.gentoo-wiki.com/wiki/ACPI/Map_events_to_keyboard_shortcut

   changed to use /dev/uinput based on
  
   http://www.linuxforums.org/forum/ubuntu-linux/161718-its-no-effect-when-using-uinput.html
   http://www.einfochips.com/download/dash_jan_tip.pdf
   http://thiemonge.org/getting-started-with-uinput
   https://launchpadlibrarian.net/19907781/acpi_fakekey.c

*/

#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <syslog.h>


int main() {
        int fd;
        int key;
        struct input_event event;
	struct uinput_user_dev dev;

	openlog("fake_alt-ctrl-t: ", LOG_PID, LOG_SYSLOG);
	syslog(LOG_NOTICE, "faking ALT-CTRL-T");
		
	fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
	if (fd < 0) {
		syslog(LOG_NOTICE, "%m");
		exit(EXIT_FAILURE);
	}        
        
	memset(&dev, 0, sizeof(dev));
	strncpy(dev.name, "ACPI Virtual Keyboard Device", UINPUT_MAX_NAME_SIZE);
	dev.id.version = 4;
	dev.id.bustype = BUS_USB;
	dev.id.product = 1; // dummy
	dev.id.vendor = 1; // dummy

	ioctl(fd, UI_SET_EVBIT, EV_KEY);

	// we somehow need to 'enable' the keys we want to use
	ioctl(fd, UI_SET_KEYBIT, KEY_T);
	ioctl(fd, UI_SET_KEYBIT, KEY_LEFTALT);
	ioctl(fd, UI_SET_KEYBIT, KEY_LEFTCTRL);

	write(fd, &dev, sizeof(dev));

	if (ioctl(fd, UI_DEV_CREATE)) {
	  syslog(LOG_NOTICE, "%m");
	  return EXIT_FAILURE;
	}

	if (!fd) {
	  syslog(LOG_NOTICE, "%m");
	  return 2;
	}

	sleep(1);

        event.type = EV_KEY;
        event.value = 1;

        event.code = KEY_LEFTCTRL;
        write(fd, &event, sizeof event);
        event.code = KEY_LEFTALT;
        write(fd, &event, sizeof event);
        event.code = KEY_T;
        write(fd, &event, sizeof event);

        event.value = 0;
        event.code = KEY_T;
        write(fd, &event, sizeof event);
        event.code = KEY_LEFTALT;
        write(fd, &event, sizeof event);
        event.code = KEY_LEFTCTRL;
        write(fd, &event, sizeof event);

       	ioctl(fd, UI_DEV_DESTROY);
	close (fd);

	closelog();
	return EXIT_SUCCESS;

}


This program is called in usr/lib/acpid/thinkpad_handler as follows:


# XF86ToggleTouchpad
if  "$WHAT" = "00000080" -a "$SERIAL" = "00001008" ]; then
        # Fn+F8
	/usr/local/bin/acpi_fake_alt-ctrl-t
fi

/PiNy