evdevPatch
I spent a little while finding the right place to put two lines of code to enforce
natural scrolling on my computer. Read on for the story, or scroll to the end
for my fix.
Explanation
Natural scrolling is a feature introduced by Apple in OS X Lion. Basically,
it is reversed scrolling. The user who wants this considers their finger to
be moving the content, not the scroll bar. Apple separates the settings
between trackpads and regular mice. Personally, I like both set to natural
scrolling.
The Old Fix
xmodmap -e "pointer = 1 2 3 5 4"
This little bit of code is a wonderful workaround to get natural scrolling in
X11.
The Problem
I use Gnome 3. Gnome 3's default apps use new smooth scroll UI elements from
their gtk. Unfortunately, these new smooth scroll regions don't respect X11
buttons. They do their own thing with relative events so as to detect how
fast the user has scrolled.
Now, Gnome 3's settings panel has a natural scrolling option, but it only
affects trackpads. My workaround has been to use the old fix above and leave
the natural scrolling off. But this makes everything backwards in any of the
new smooth scroll regions. I had been living with it since switching to Gnome
3.
An Idea For A Better Fix
Changing the buttons at the X11 level was too high up. I needed a lower level
fix. A hardware fix would work and wouldn't even be computer dependent, but I
decided not to break my mouse. I decided to try to fix it at the driver
level. I use Gentoo Linux and manually compile the Liunx kernel (with the
Gentoo patches). So, I started exploring the source files in
/usr/src/linux/drivers/input/. After a while, I
found the right place in /usr/src/linux/drivers/input/evdev.c.
The Actual Fix
I was on kernel 3.12.10-r1 at the time I created this. I'd like to keep an
up to date patch up, but I know that will never happen. So, if things
change, you'll have to figure out what to do.
Thanks should go to the author of
this page.
static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t mono, ktime_t real)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;
if (client->revoked)
return;
event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
for (v = vals; v != vals + count; v++) {
event.type = v->type;
event.code = v->code;
event.value = v->value;
/* ----------I added this section.---------- */
if(event.type == EV_REL && (event.code == REL_WHEEL || event.code == REL_HWHEEL))
event.value = -event.value;
/* ---------- But only to here. ---------- */
__pass_event(client, &event);
if (v->type == EV_SYN && v->code == SYN_REPORT)
wakeup = true;
}
spin_unlock(&client->buffer_lock);
if (wakeup)
wake_up_interruptible(&evdev->wait);
}