Using hdaps for screen rotation
In the middle of fighting to get the X61's screen rotate button to talk to xrandr, I realized that the laptop already has an accelerometer in it and given that, the screen rotate button was a crappy UI anyway.
So, here's a way to make the laptop automatically rotate the screen, based on the accelerometer, when in tablet mode. It was written on a system running Ubuntu 8.10, but any system with ACPI and HDAPS configured should work.
First, we need two files to tell acpid to stick a flag in the filesystem when switching between tablet and laptop modes.
event=ibm/hotkey HKEY 00000080 00005009 action=/usr/bin/touch /var/lib/acpi-support/tablet
event=ibm/hotkey HKEY 00000080 0000500a action=/bin/rm -f /var/lib/acpi-support/tablet
Second, we need something to rotate the screen when the HDAPS device passes a certain movement threshold.
#!/usr/bin/env python import glob import select import struct import sys import os from fcntl import ioctl JS_EVENT_FMT = "IhBB" JS_EVENT_SIZE = struct.calcsize(JS_EVENT_FMT) # Event types -- JS_EVENT_BUTTON = 0x01 # button pressed/released JS_EVENT_AXIS = 0x02 # joystick moved JS_EVENT_INIT = 0x80 # "virtual" event flag # ioctl magic codes for device info -- JSIOCGAXES = 0x80016a11 # axis count JSIOCGBUTTONS = 0x80016a12 # button count JSIOCGNAME = 0x81006a13 # device name # ~0.56 is straight vertical TILT_THRESHOLD = 0.38 # Names of xinput devices to rotate with the screen TOUCH_DEVICES = "stylus eraser pad touch".split() def find_hdaps(): for filename in glob.glob("/dev/input/js*") + glob.glob("/dev/js*"): try: dev = open(filename, "rb") except (IOError, OSError): continue else: axes = struct.unpack( "b", ioctl(dev, JSIOCGAXES, " ")) buttons = struct.unpack( "b", ioctl(dev, JSIOCGBUTTONS, " ")) name = struct.unpack( "1024s", ioctl(dev, JSIOCGNAME, " " * 1024)) name = name.rstrip().strip("\x00") if name == "hdaps": return dev else: dev.close() def set_state(state): os.system("xrandr -o %s" % state) pen_rot = ["normal", "right", "left", "inverted"].index(state) for dev in TOUCH_DEVICES: os.system("xsetwacom set %s rotate %d" % (dev, pen_rot)) def main(argv): state = "normal" dev = find_hdaps() if not dev: raise SystemExit("Unable to find HDAPS joystick device.") while select.select([dev], , ): # Unpack the event and send it! evt = dev.read(JS_EVENT_SIZE) time, value, etype, number = struct.unpack(JS_EVENT_FMT, evt) if etype & JS_EVENT_AXIS: value = value / 32768.0 if number == 0 and value > TILT_THRESHOLD: new_state = "normal" elif number == 0 and value < -TILT_THRESHOLD: new_state = "inverted" elif number == 1 and value < -TILT_THRESHOLD: new_state = "left" elif number == 1 and value > TILT_THRESHOLD: new_state = "right" else: new_state = state if state != new_state: if (new_state != "normal" and not os.path.exists("/var/lib/acpi-support/tablet")): new_state = "normal" if new_state != state: state = new_state set_state(state) if __name__ == "__main__": main(sys.argv[1:])
/etc/init.d/acpid reload, and run
autorotate.py. Switch your laptop to tablet mode, and spin it around. The screen should rotate appropriately. If you find it rotates too easily or not easily enough, tweak the TILT_THRESHOLD variable. If you named your XInput devices for the touchscreen differently, change the TOUCH_DEVICES string.