Apple Mighty Mouse on Linux HowTo
By Brian Murray (IdleGod at gmail dot com)
Introduction
This will cover how to install and use a Apple Mighty Mouse. I will start by explaining just how to do it, then I will explain why each step is done the way its done.
Watch out, as this howto explains two ways to perform this task; one with the Xorg CVS, and one with the Gentoo sources. You only need, and can do, one. I know most of the tweaking kiddies like gentoo, but I prefer the Xorg CVS version myself. I have created various patches, and am trying to get them submitted to the Xorg tree so that all the axis may be configured from the config file. However, as of yet, you need to patch it in staticly.
Prerequisits
There are several things you will need.
Kernel with evdev support. Most modern kernels have this.
evtest.c. A small C app that gets raw evdev events. (Not needed, but nice to have)
A recent X.Org or XFree86. I have X.Org 6.8.2-r2 from Gentoo's portage for the 'second' section. This gets tricky later on. I also have the latest Xorg CVS version. You can get this from x.org.
evdev.patch. A patch I created with all my changes to Xorg source code.
Notes
- A reader (JP Larocque), has noted that the older kernels dont support the horizontal scrolling. He also states that the latest Xorg doesn't require modifications. I know that in late 7.0, or 7.1, evdev was completely re-written. It is much nicer now, and discovers mouse devices based on names instead of device nodes.
- There is also a new patch for Mozilla to remap the forward and back correctly. https://bugzilla.mozilla.org/show_bug.cgi?id=355477
Configure the kernel
All you will need is evdev.
I found evdev under Device Drivers->Input device support->Event Interface.
Updates to Xorg
Note: all the updates here can be applied to your Xorg source simply by starting at the top of your Xorg CVS source dir, and using patch -p1 < evdev.patch. evdev.patch is availible at the top of this page.
Note: You may omit this section if you have Gentoo. This needs the Xorg CVS or at least a version with the evdev driver added. If you just want it to work on gentoo, jump to 'Installing the applications'
The new xorg has an evdev input driver. By using this instead of the old version, you can get the mouse to work suprisingly easily. Heres what I had to add to get the side scrolling working.
This code starts at line 157 of xc/programs/Xserver/hw/xfree86/input/evdev/evdev.c. Obviously use common sense. Sometimes its not in the exact right place because versions change. I used the CVS version, so its possible that the version 5 minutes from now will be different.
case REL_Z:
if (value > 0)
PostButtonClicks(pInfo, wheel_left_button, value);
if (value < 0)
PostButtonClicks(pInfo, wheel_right_button, -value);
break;
You dont need any xmodmap stuff, since evdev handles the axis's better. I found that the mouse would cause Xorg to crash if it wasn't plugged in, even if it wasn't the core pointer, so I made a small change to line 703. This is actually a bad code hack, and should really be properly fixed. Since I have no idea how to do that, I did this disgusting hack that I'm going to recieve an inbox of spam about.
You dont need, and probably dont want this code, to simply get this driver to work
xf86Msg(X_ERROR, "Unable to open evdev device \"%s\".\n", device);
/* xfree(pEvdev); */
return pInfo;
While you're at it, you may as well force button 8 to do a backspace (back a page in firefox, since I cant find another use for it). So I changed a bit of code a little further down from the first code change. There is a bunch of case BTN_BLAH statements at line 191ish, so I mmoved the BTN_SIDE (button 8, squeeze), down past the break, and added another line, ev.code = KEY_BACKSPACE;. This effectively carrys the button event into the keyboard buttons, and changes the apropriet info so that it thinks its the correct keycode.
- case BTN_SIDE:
case BTN_EXTRA:
case BTN_FORWARD:
case BTN_BACK:
And:
break;
+ case BTN_SIDE:
+ ev.code = KEY_BACKSPACE;
+
default:
PostKbdEvent(pInfo, &ev, value);
Viola! Build and install it. I wont run you through downloading the latest Xorg code, you can figure that out on your own. From here we just need to configure xorg.conf. Heres what I have for the mouse.
Section "InputDevice"
Identifier "MightyMouse"
Driver "evdev"
Option "Device" "/dev/input/mightymouse"
EndSection
Now how easy was that? Add it to the layout of choice, and you're set. You may notice I have a /dev/input/mightymouse. Thats a special dev node of my creation using udev. You an safely use /dev/input/eventX where X is the device number. Or, you can create a node yourself. I created a /etc/udev/rules.d/10-udev.rules file, and put the following in it.
KERNEL=="event*", SYSFS{manufacturer}=="Mitsumi Electric", SYSFS{product}=="Apple Optical USB Mouse", NAME=="input/mightymouse", MODE=="0644"
From here, you can disregard the rest of the info up to the testing section.
Installing the applications
I'm going to stay a bit gentoo specific. Perhaps in a future revision I will add generic X.Org info, and maybe even a patch. Gentoo is a total pain to deal with any source code on.
At this stage, you can emerge X.Org, but you'll probably only want to do a --fetchonly, since were going to be changing some code.
Next, in my /root dir, I untared the contents of /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar.bz2. From there, I modified patch/9002_all_6.7.0-lnx-evdev-mouse.patch.
emerge --fetchonly xorg-x11
tar jxvf /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar.bz2 patch/9002_all_6.7.0-lnx-evdev-mouse.patch
vi patch/9002_all_6.7.0-lnx-evdev-mouse.patch
I then moved the line (I think), 99 (it reads case EV_REL_Z:) to be right above or under the line that reads case EV_REL_HWHEEL:
+ break;
+ case EV_REL_Z:
+ case EV_REL_WHEEL:
+ dz -= ev->value;
+ break;
+ case EV_REL_HWHEEL:
+ dw -= ev->value;
+ break;
Will be:
+ break;
+ case EV_REL_WHEEL:
+ dz -= ev->value;
+ break;
+ case EV_REL_Z:
+ case EV_REL_HWHEEL:
+ dw -= ev->value;
+ break;
Now comes the PITA gentoo part. You need to re-tar that dir you've just untar'd. Since we cant update a compressed archive, you'll need to bunzip2 the file, then run tar uvf /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar patch/*. That should ONLY update files you changed. Then bzip2 the file again. Now we get into the 'holy crap, how do you ever expect to maintain code like that' part.
bunzip2 /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar.bz2
tar uvf /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar patch/*
bzip2 /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar
We need to md5sum the new xorg-x11-6.8.2-patches-0.1.9.tar.bz2, and replace the value in /usr/portage/x11-base/xorg-x11/files/digest-xorg-x11-6.8.2-r2, as well as append the file size. That is easily found out with a simple ls -l of the tarball.
Mine looks like: MD5 dfeae2f547a8e52c0296cb9c84cb3e6c xorg-x11-6.8.2-patches-0.1.9.tar.bz2 165580. Now, you'll need to do the same procedure to /usr/portage/x11-base/xorg-x11/Manifest for the file files/digest-xorg-x11-6.8.2-r2
echo "MD5 " $(md5sum /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar.bz2) " " $(ls -l /usr/portage/distfiles/xorg-x11-6.8.2-patches-0.1.9.tar.bz2 | awk '{print $5}') >> /usr/portage/x11-base/xorg-x11/files/digest-xorg-x11-6.8.2-r2
echo "MD5 " $(md5sum /usr/portage/x11-base/xorg-x11/files/digest-xorg-x11-6.8.2-r2) " " $(ls -l /usr/portage/x11-base/xorg-x11/files/digest-xorg-x11-6.8.2-r2 | awk '{print $5}') >> /usr/portage/x11-base/xorg-x11/Manifest
Then just remove the old one in each.
Finally! You can 'emerge xorg-x11'! This should check the files, and should NOT download any more. If it does, then ask your local #gentoo why its doing it. If you give them this URI, they're gonna spam me with hatemail for my blatent disregard for gentoo's package integrity. Of course, I don't see them making a new mouse work when it shouldn't.
Now we wait for a while. It took me 40 mins to build on my 2.0ghz PM.
Configure the X.Org
I have no clue how to use the configuration apps, and if you're using an X based one, theres a good chance you'll screw this up. The following is the input section for my Mighty Mouse. From here, you'll just add 'MightyMouse' to your ServerLayout.
Section "InputDevice"
Identifier "MightyMouse"
Driver "mouse"
Option "Protocol" "evdev"
Option "Buttons" "8"
Option "Dev Name" "Mitsumi Electric Apple Optical USB Mouse"
Option "ZAxisMapping" "5 6 7 8"
EndSection
Your xmodmap should be as follows:
pointer = 1 2 3 8 4 5 6 7
Testing
You're first instinct is going to be opening Firefox and trying to load a webpage thats too big to scroll across it. I'm sad to say, this wont work, but I'll get to that. Instead, open xev and start scrolling around. Up and Down should generate 4/5. while side-side should generate 6/7. This means your mouse is now completely setup. Gimp, gaim, etc, should all side-scroll with ease. Except for one app: Firefox.
Firefox
It took me a few hours to figure this out, but theres actually an option that changes the forward/back action. Its called: mousewheel.horizscroll.withnokey.action. A setting of 2 does the forward/back thing. A setting of 0 does the side-scroll thing. The other mousewheel.horizscroll.* options should be self-explanitory. Obvously, you find them in "about:config". I have currently opened a bug report with Bugzilla about only giving the option for scroll or history navigation. Obviously 6/7 should be used for scrolling since every other app uses them, so I propose using 8/9 for back/forward. Anyhow, that'll be a few revisions off if ever at all.
Segway
I am happy to say that this all worked for me with very minimal effort. The hardest part was digging through the informational garbage thats out there and cutting to what I needed, and how it worked. That's why in the next section, I intend to explain WHY each is the way it is.
Explaination
For the longest time I was under the impression that ZAxisMapping in xorg.conf/xf86config was to map the buttons of the scroller to other buttons. This is actually a really wrong analogy. Instead, its easier to describe mouse theory. Mouse theory? I must be mad! But in all seriousnes, it's not hard, and it really helps understand the code hack I did, and the very tiny ammount of configuration needed.
First off, theres 2 types of input on a mouse, Keys and Relatives. Now, your mouse buttons are keys. Examples are LeftBtn, RightBtn. These do not include your scroll wheel.
Next is the Relatives. They include a few axis such as X and Y (Gross mouse movement). We also have a few more axis, being: Z, Wheel, and HWheel. Z and Wheel are actually very similar, and on most systems are interchangable. Some mice use Z, while others use Wheel. So, somewhere, deep down in the origional XOrg code, they are aliased together. ZAxisMapping, YAxisMapping, etc, actually just take their respective axis and map their events to buttons. ZAxisMapping has an extra 2 fields too, but they are for re-mapping HWheel to buttons. Option "ZAxisMapping" "6 7" would map the up and down functions of the mouse to emulate buttons 6 and 7.
Via experimentation with evdev, vertical scrolling uses Wheel, and horizontal scrolling uses Z. Mixed with the aliasing, it prevents horizontal scrolling. So, I went through some of the code for XOrg from gentoo, and found the patch that made that change. By moving that code, it instead lumps the Z axis with the HWheel axis. This way it retains the ZAxisMapping syntax. Unfortunately, it will break some other mice. You can fix it by simply ZAxisMapping "5 6 5 6", which will map the Wheel axis to 4,5, as well as the Z and HWheel axis to 4,5. Aparently theres some new code in 6.8.99 that does some horizontal scroll handling.
From there, we move onto the xmodmap. To really understand xmodmap, you have to think of it more like an equation. Each number after the = corosponds to a mouse button, which I will refer to a slot. The numbers themselves, I will refer to as an alias. Each slot is filled with a numbered alias. That slot will then apear to X as the Alias. If that all makes sense.
Another way to explain it would be that it is mapping physical buttons (as loaded in, including AxisMapping directives), to seen keycodes by X.
pointer = 1 2 3 8 4 5 6 7
That line maps the following:
Button 1 - Keycode 1
Button 2 - Keycode 2
Button 3 - Keycode 3
Button 4 - Keycode 8
Button 5 - Keycode 4
Button 6 - Keycode 5
Button 7 - Keycode 6
Button 8 - Keycode 7
As we remember, we used a ZAxisMapping of "5 6 7 8". That means 'Button' 5 and 6 corrospond to keycodes 4 and 5, and 'Buttons' 7 and 8 (HWheel, remember?), map to 6 7.
Wrapup
That should be it. If you have any questions, see my email at the top. I must say, I was skepticle that side-scrolling would be usefull, but after using it for a few minutes, its very useful.