05.11.2010

Automatic screen rotation on HP touchsmart notebooks

Update 3: Apparently the python script which is advertised on some sites got more attention than it had when I first read about it and has even been set up as a Launchpad project. The huge CPU overhead has been taken care of (it's now event-based) and it supports more than just one laptop model. I haven't tried a new version of the script, but I guess it does the job just as fine as my script does (I can't tell which script is better). Feel free to test out both ways, I'd be happy to hear of some comparisons!

Update 2: There's a new article on this topic. I've managed to build a package out of the stuff I wrote here and made it available in my Launchpad PPA. It should be much easier to just install and configure it than to follow this whole guide. Here's the direct link to the article:
http://linuxquirks.blogspot.com/2010/11/freddeb.html

Update: According to feedback, this solution is not yet guaranteed to work, even for similar laptops. Feel free to test it and report any errors (helps me a lot), though. I will try to create an installable package out of all this, but this will take some time.

As I wrote in an earlier article, I possess an HP touchsmart tm2-1090eg notebook whichcan be turned into a tablet PC. Since the automatic screen rotation is not working out-of-the-box on Ubuntu and since I couldn't get the rotate-screen-button on the right side of the display to work yet, I've been getting by with a hand-written script. I wrote a Tcl/Tk program which uses xrandr and xsetwacom to rotate the screen according to my wishes.
By request of Felix, the first person to write a comment to this blog :), I looked into possibilities to automatically rotate the screen upon turning the display. I thought that since I managed to write an ACPI handler for CPU frequency scaling depending on the status of the power supply (there will be a post on this, too), I might give it a try. And guess what? I did it!
Unfortunately, my first guess was wrong. Turning around the display and putting it on top of the keyboard didn't create any ACPI events. However, I noticed some strange noise on dmesg:
atkbd serio0: Use 'setkeycodes e058 ' to make it known
atkbd serio0: Unknown key pressed (translated set 2, code 0xd9 on isa0060/serio0).
atkbd serio0: Use 'setkeycodes e059 ' to make it known.
atkbd serio0: Unknown key released (translated set 2, code 0xd9 on isa0060/serio0).

Hell yes, dmesg even told me what to do! Here's what I did:
  1. Find out the scan code - turn the display, put it down, pull it back up and inspect the messages:
    Code:
    $ dmesg
    There should be some messages like the ones I received. The first one is the key code from putting down the display, the second one is the code from pulling it back up.
    Note: If You don't get any messages like those, chances are that Your kernel already knows the keys. Try to bind something to them using the GNOME "Keyboard Shortcuts" or see if they generate key events by using xev.
  2. Find out which key code is available for mapping. There's no patented way for doing this. I just tried out some codes and looked what the GNOME "Keyboard Shortcuts" called the code. For me, the codes 220 and 221 worked well, since there is no button issuing these codes.
  3. Create an upstart script to set the keycodes on system startup. Setting the codes is not persistens, so You have to do it after each reboot. Use an upstart script to accomplish the job. As root, create a file /etc/init/tablet-mode.conf and put something like this inside:
    Code:
    # tablet-mode
    #
    # Map key codes to the scan codes emitted by the display when putting it down on
    # the keyboard.

    description "Tablet PC mode"
    author "Frederik Möllers"

    start on local-filesystems

    script
        setkeycodes e058 220
        setkeycodes e059 221
    end script
  4. Create a program to rotate the screen. Basically You just need to use xrandr to rotate the screen and xsetwacom to turn the tablet orientation. You can also use my Tcl/Tk program (requires wish to run, install the package if You want to use it) which also offers a GUI to use manually. Put the following code in a file (e.g. /usr/local/bin/rotatescreen, make it executable and You can call it with rotatescreen tableton and rotatescreen tabletoff. It not only turns the display and the tablet orientation but also disables the touch mode. This prevents the cursor from jumping around when You write with the stylus and touch the display with Your hand. Of course, You can customize the Tcl/Tk program to fit Your wishes. Even if You're not experienced in Tcl or Tk, the syntax should be quite easy. So here's the code:
    Code:
    #! /bin/bash
    #\
    exec wish "$0" "$@"

    proc rotate_0 {} {
       exec xrandr --output LVDS1 --rotate normal
       exec xsetwacom --set 11 rotate NONE
       exec xsetwacom --set 12 rotate NONE
       exec xsetwacom --set 13 rotate NONE
    }

    proc rotate_90 {} {
       exec xrandr --output LVDS1 --rotate left
       exec xsetwacom --set 11 rotate CCW
       exec xsetwacom --set 12 rotate CCW
       exec xsetwacom --set 13 rotate CCW
    }

    proc rotate_180 {} {
       exec xrandr --output LVDS1 --rotate inverted
       exec xsetwacom --set 11 rotate HALF
       exec xsetwacom --set 12 rotate HALF
       exec xsetwacom --set 13 rotate HALF
    }

    proc rotate_270 {} {
       exec xrandr --output LVDS1 --rotate right
       exec xsetwacom --set 11 rotate CW
       exec xsetwacom --set 12 rotate CW
       exec xsetwacom --set 13 rotate CW
    }

    proc touch_on {} {
       exec xsetwacom --set 11 Touch on
    }

    proc touch_off {} {
       exec xsetwacom --set 11 Touch off
    }

    proc quit {} {
       destroy .
       exit
    }

    if {$argc > 0} {
       switch "[lindex $argv 0]" {
          "0" {
             rotate_0
          }
          "90" {
             rotate_90
          }
          "180" {
             rotate_180
          }
          "270" {
             rotate_270
          }
          "tableton" {
             rotate_180
             touch_off
          }
          "tabletoff" {
             rotate_0
             touch_on
          }
          default {
             puts "Cannot rotate [lindex $argv 0] degrees!"
          }
       }
       exit
    }

    wm title . "Screen rotation"
    wm geometry . +605+300
    frame .deg
    button .deg.0 -text "0°" -command "rotate_0; quit"
    button .deg.90 -text "90°" -command "rotate_90; quit"
    button .deg.180 -text "180°" -command "rotate_180; quit"
    button .deg.270 -text "270°" -command "rotate_270; quit"
    pack .deg.0 .deg.90 .deg.180 .deg.270 -in .deg -pady 3 -side top
    frame .touch
    button .touch.ton -text "Touch on" -command "touch_on; quit"
    button .touch.toff -text "Touch off" -command "touch_off; quit"
    pack .touch.ton .touch.toff -in .touch -pady 3 -side top
    button .cancel -text "Cancel" -command "quit"
    pack .deg .touch .cancel -pady 6 -side top
    bind . "rotate_0; quit"
    bind . "rotate_90; quit"
    bind . "rotate_180; quit"
    bind . "rotate_270; quit"
    bind . "quit"
    bind . "quit"
    bind . "quit"
  5. Bind the keys to the program using GNOME "Keyboard Shortcuts" (or the equivalent for Your desktop manager). Create a binding with the command rotatescreen tableton and one with the command rotatescreen tabletoff and set the bindings by turning Your display, putting it down and pulling it back up.

Thanks again to Felix who told me to search for a way. I had already given up on this and didn't think I would find a way to get the screen rotation to work automatically.

That's it! You're done!

9 Kommentare:

  1. You're great !!!!!

    i will try it just now and give you a feedback!!

    love ure work keep it on!!

    AntwortenLöschen
  2. Dieser Kommentar wurde vom Autor entfernt.

    AntwortenLöschen
  3. I do not have enough time today to try out your instructions completely, but I have only just worked once but "rotatescreen: command not found" my terminal says
    maybe i have missed something ...

    i will give it a try later!
    it it possible to write a installation script?
    i would help if could, i have some experience in windows programming: Pascal / Delphi and a little C + +, i never tried something with unix or so ...

    AntwortenLöschen
  4. I've changed the recommended path for the script. Take the code, put it into a text file (save it as "rotatescreen"), (as root) move that file to /usr/local/bin and make it executable (chmod +x /usr/local/bin/rotatescreen). That should do the trick.

    I will see if I can make a package out of all this, but that will take a while.

    AntwortenLöschen
  5. the package thingy would be great!! but i will give it a try today (hopefully successful)

    AntwortenLöschen
  6. today i tried again your instructions, just change the path of the script... and now i can call the command "rotatescreen tableton" but if i do i get an error message back:

    rror in startup script: warning: output LVDS1 not found; ignoring
    while executing
    "exec xrandr --output LVDS1 --rotate inverted"
    (procedure "rotate_180" line 2)
    invoked from within
    "rotate_180"
    ("tableton" arm line 2)
    invoked from within
    "switch "[lindex $argv 0]" {
    "0" {
    rotate_0
    }
    "90" {
    rotate_90
    }
    "180" {
    rotate_180
    }
    ..."
    invoked from within
    "if {$argc > 0} {
    switch "[lindex $argv 0]" {
    "0" {
    rotate_0
    }
    "90" {
    rotate_90
    }
    "180" {
    r..."
    (file "/usr/local/bin/rotatescreen" line 46)


    ... where is the problem? am i doing something wrong?

    AntwortenLöschen
  7. Looks like Your display has a different name than mine. That's odd, since You have the same laptop. Can You send me the output of the command "xrandr"? I can then try to determine the name automatically during package installation.

    AntwortenLöschen
  8. ok maybe it is caused by the switchable graphic-cards
    here is my xrandr out put if the Intel-Card is used:
    $ xrandr
    Screen 0: minimum 320 x 200, current 1280 x 800, maximum 8192 x 8192
    VGA1 disconnected (normal left inverted right x axis y axis)
    LVDS1 connected 1280x800+0+0 (normal left inverted right x axis y axis) 261mm x 163mm
    1280x800 60.0*+
    1024x768 60.0
    800x600 60.3 56.2
    640x480 59.9
    DP1 disconnected (normal left inverted right x axis y axis)
    TV1 disconnected (normal left inverted right x axis y axis)

    AntwortenLöschen
  9. Sorry for taking so long.
    According to Your xrandr output, the script should work, since the LVDS1 display is stated as "connected".
    However, I completed the package and it's available in my Launchpad PPA. A guide on how to install it is here:
    http://linuxquirks.blogspot.com/2010/11/freddeb.html

    Are You able to use the ATI card in linux? If yes, how? Still, even if You used the ATI card, the display should still be LVDS1...
    If the script still gives the same error, You can try to rotate the screen manually using:
    xrandr --output LVDS1 --rotate inverted
    If You're able to switch the graphics card, You should try it using the intel card and send me the output of the normal 'xrandr' command when using the ATI card, so that I can include that in the package.

    AntwortenLöschen