News (Sep. 2003):
Alex Harper (who had built the scrolling features into
uControl)
has taken the info on extended modes on apple trackpads and built a
whole new driver around it. His
SideTrack
is at its first public beta right now and already more feature rich and robust
than my hack (and also has a GUI installer and control panel).
Better get his
SideTrack instead of my hack for a robust and actively maintained scrolling-trackpad.
I've allways been thinking that it must be possible to create some fancy hacks with my iBook's built in TrackPad (or TouchPad - whatever you want to call it) - if only i could get it to spit out more detailed information than the standard mouse emulation it performs by default.
The TrackPad built into the iBook is a ADB (Apple Desktop Bus) device that has a built in Microcontroller for talking the ADB protocol, interpreting the sensory input, translating it into relative mouse motion information and reckognizing some basic gestures (short taps can be interpreted as clicks, a tap-and-a-half can be interpreted as the button-down event that preceeds a drag operation).
But what i wanted was the absolute position of the Finger on the TouchPad so i could reckognize hotspots within the driver and do different things based on where, when and how the motion is reckognized. So i started seaching the Web, Usenet, Apples Developer Center, ... only to find: nothing!
Well - nothing specific for the TouchPad - but still some interesting reads:
On the way i found some other information on ADB devices (especially notebook keyboards) that might be useful later on
Next i had a deeper look at Apples ADB Mouse Driver which is published as part of Open Darwin. You can check it out of their CVS from the commandline like this (type anoncvs when asked for a password):
mkdir opendarwin cd opendarwin cvs -D :pserver:anonymous@anoncvs.opendarwin.org:/Volumes/src/cvs/od login cvs checkout src/AppleADBMouse/ open src/AppleADBMouse/AppleADBMouse.pbproj |
Then i started hacking around in the driver and loading it into the running system. To do that, you have to first unload the current ADB mouse driver and then load the fresh one (as root):
sudo su - cd opendarwin/src/AppleADBMouse/build kextunload /System/Library/Extensions/AppleADBMouse.kext chown -R root.wheel ./AppleADBMouse.kext kextload ./AppleADBMouse.kext chown -R <username> ./AppleADBMouse.kext |
First, i tried configuring the TrackPad to different handler IDs - since the space-alien document seemed to suggest this as the primary means of changing a devices behavior. I got the following acceptable IDs:
Next, i had a closer look at the methods AppleADBMouseType4::start(), AppleADBMouseType4::enableEnhancedMode() and AppleADBMouseType4::setParamProperties() in Apples driver implementation (they contain some hints about special Panther Settings by the way - but no actually differnt code...):
First, the system decides, if it has a W-Enhanced TrackPad by looking for an indicator for 4 Buttons present. My iBook doesn't have them. Instead it reports 2: the physical button is number one and the simulated button (the one activated by tapping) is number two. It seems, W-enhanced TrackPads report additional flags (Palm-detected, outzone) via additional pseudo-buttons. Incidently, that is an exact feature of the Synaptics TouchPad whose technical docs i mentioned above. The even call it W-Mode...
Anyway: next the code 'enables enhanced mode' - that is: activate a mode that can potentially deal with tap-click and tab/2-drag by first writing 0x0D into byte 6 of register 2. The original value is 0x03. In that mode it behaves just like a plain mouse and does not deal with taps. To actually activate these features, additional flags have to be set in register 1.
Next experiment was writing different values into this byte 6 of register 2. And BOOM! That did it!
Writing 0x00 into this location turned the contents of register 0 (the data reported for every
action on the pad) into something that had nothing to do with relative motion anymore.
After some fiddling, i figured out, it was (nearly) the encoding, the Synaptics TouchPad from above
used for absolute positioning. And you even get Z-Axis data: an indicator, of how much the capacitive
measure of the pad is activated. It does not really report pressure but rather the area covered by
skin.
So here is the summary:
Register 0:
2, 5 or 8 bytes of motion data - depending on the mode.
in absolute mode:
Byte/Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | phys. btn. (inv. logic) | bit 0..6 of X-axis data | ||||||
1 | allways 1 | bit 0..6 of Y-axis data | ||||||
2 | allways 1 | bit 7..9 of y-axis data | allways 1 | bit 7..9 of x-axis data | ||||
3 | allways 1 | bit 10..12 of y-axis data | allways 1 | bit 10..12 of x-axis data | ||||
4 | allways 1 | bit 0..2 of z-axis data | allways 1 | bit 3..5 of z-axis data |
Register1:
byte | value | r/w | purpose |
0 | 0x74 ='t' | r | Magic id tpad |
1 | 0x70 ='p' | r | |
2 | 0x61 ='a' | r | |
3 | 0x64 ='d' | r | |
4 | 0x01 | r | ? |
5 | 0x90 | r | ? |
6 | 0x03 | rw | 0x00: absolute mode,
0x03: plain relative mode 0x0D: enhanced relative mode |
7 | 0x02 | r | ? |
And finally: here is what is known about Register 2
(which only makes sense in enhanced relative mode):
byte \ bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | enable soft click | tap detection time (unit?) def.Val: 0x19 | ||||||
1 | enable soft drag | ? defVal = 0x14 | ||||||
2 | ? defVal = 0x19 | |||||||
3 | enable tap to drop | downtime (?) defVal = 0xb2 | ||||||
4 | ? defVal = 0xb2 | |||||||
5 | ? defVal = 0x8a | |||||||
6 | ? defVal = 0x1b | |||||||
7 | ? defVal = 0x19 | W-Mode? |
Armed with that knowledge i could go forth and create my own replacement for the AppleADBMouse driver. My version can detect a hot scrolling area (usually the right end of the touchpad) and issue scroll events when the finger touched down in that area and is subsequently moved up and down.
it installs a sysctl to configure its features. It also uses the standard mouse config options
thru the usual mouse preference pane
(enable tapping and dragging - tap-to-drop is not implemented yet since i don't use it).
The sysctl scrollpad.activate knows the following values (ORed together):
bit | value | meaning | annotation |
0 | 1 | scrollPad mode active | bit 0 and 1 are exclusive - if neither is set, the default touchpad behaviour by apple is restored |
1 | 2 | absolute mode active | |
2 | 4 | scrolling inverted | scroll the document instead of the window... |
3 | 8 | keep moving | move the pointer further when the finger reaches an edge of the pad... |
4 | 16 | debug | lots of output into the /var/log/system.log... |
5 | 32 | left scrolling hotspot | put the scroll sensitive area to the left... |
My implementation of the touch gestures is still - well - less than perfect... In order to reckognize, that a click is not followed by a second half-tap that initiates a drag gesture, i would have to get the driver invoked when nothing happens. And that does not happen - at least not out of the box. There may be possibilities with timers and such. But i have no idea, how.
Here is a diagram of what happens / should happen when the finger taps once, one-and-a-half times
or twice:
The ScrollPad hack is based on apples ADBMouse driver code and as such it is available under the ASPL: Apples open source license.
Author:
Heiko Hellweg, last modified: September 2003 |