summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorRhinoceros2015-06-09 09:25:01 +1000
committerRhinoceros2015-06-09 09:25:01 +1000
commitd7bdec1ddd492a2c75a11cd57886f24f079fa583 (patch)
tree1205ac92b064f0ca399f07f3450c6d1c17247dfd
downloadaur-d7bdec1ddd492a2c75a11cd57886f24f079fa583.tar.gz
Initial commit of 2.9.0-1
* Based on the previous version of 2.6.4-1, but this has now been lost.
-rw-r--r--.SRCINFO31
-rw-r--r--PKGBUILD38
-rw-r--r--ahm-2.9.0.patch1375
-rw-r--r--ahm.install29
4 files changed, 1473 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..2bdd35d48e9d
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,31 @@
+pkgbase = xf86-input-evdev-ahm
+ pkgdesc = X.org evdev input driver + at home modifier patch
+ pkgver = 2.9.0
+ pkgrel = 1
+ url = https://gitorious.org/at-home-modifier
+ install = ahm.install
+ arch = i686
+ arch = x86_64
+ groups = xorg-drivers
+ groups = xorg
+ license = custom
+ makedepends = xorg-server-devel
+ makedepends = resourceproto
+ makedepends = scrnsaverproto
+ depends = glibc
+ depends = systemd
+ depends = mtdev
+ depends = libevdev
+ provides = xf86-input-evdev=2.9.0
+ conflicts = xorg-server<1.15.0
+ conflicts = X-ABI-XINPUT_VERSION<20
+ conflicts = X-ABI-XINPUT_VERSION>=21
+ conflicts = xf86-input-evdev
+ options = !makeflags
+ source = http://xorg.freedesktop.org//releases/individual/driver/xf86-input-evdev-2.9.0.tar.bz2
+ source = ahm-2.9.0.patch
+ sha256sums = 0c0c4aa393cb027a2304967944867a21a340bcad2e5efe630291b6906c3abc35
+ sha256sums = 450fb96642910a84fa578e7a001c746b6f3d656ec24532f3f3744bfd7234b18e
+
+pkgname = xf86-input-evdev-ahm
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..df8398b9095f
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,38 @@
+# $Id$
+# Maintainer: Jan de Groot <jgc@archlinux.org>
+# Contributor: Alexander Baldeck <Alexander@archlinux.org>
+
+_name=at-home-modifier
+pkgname=xf86-input-evdev-ahm
+_pkgname_orig=xf86-input-evdev
+pkgver=2.9.0
+pkgrel=1
+pkgdesc="X.org evdev input driver + at home modifier patch"
+arch=(i686 x86_64)
+url="https://gitorious.org/at-home-modifier"
+_url_orig="http://xorg.freedesktop.org/"
+license=('custom')
+depends=('glibc' 'systemd' 'mtdev' 'libevdev')
+makedepends=('xorg-server-devel' 'resourceproto' 'scrnsaverproto')
+conflicts=('xorg-server<1.15.0' 'X-ABI-XINPUT_VERSION<20' 'X-ABI-XINPUT_VERSION>=21' 'xf86-input-evdev')
+provides=('xf86-input-evdev=2.9.0')
+options=('!makeflags')
+groups=('xorg-drivers' 'xorg')
+install=ahm.install
+source=(${_url_orig}/releases/individual/driver/${_pkgname_orig}-${pkgver}.tar.bz2 ahm-2.9.0.patch)
+sha256sums=('0c0c4aa393cb027a2304967944867a21a340bcad2e5efe630291b6906c3abc35'
+ '450fb96642910a84fa578e7a001c746b6f3d656ec24532f3f3744bfd7234b18e')
+
+build() {
+ cd ${_pkgname_orig}-${pkgver}
+ patch -p1 -i $srcdir/ahm-2.9.0.patch
+ ./configure --prefix=/usr
+ make
+}
+
+package() {
+ cd ${_pkgname_orig}-${pkgver}
+ make DESTDIR="${pkgdir}" install
+ install -m755 -d "${pkgdir}/usr/share/licenses/${pkgname}"
+ install -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/"
+}
diff --git a/ahm-2.9.0.patch b/ahm-2.9.0.patch
new file mode 100644
index 000000000000..3aafe169ccd2
--- /dev/null
+++ b/ahm-2.9.0.patch
@@ -0,0 +1,1375 @@
+diff -aur xf86-input-evdev-2.9.0.orig/README "xf86-input-evdev-2.9.0.fixed manually/README"
+--- xf86-input-evdev-2.9.0.orig/README 2013-04-10 16:24:31.000000000 +1000
++++ "xf86-input-evdev-2.9.0.fixed manually/README" 2014-06-08 14:47:16.720207597 +1000
+@@ -1,20 +1,680 @@
+-xf86-input-evdev - Generic Linux input driver for the Xorg X server
++Welcome to "At Home Modifier" hack of xf86-input-evdev. The original
++README is moved to README.orig.
+
+-Please submit bugs & patches to the Xorg bugzilla:
++Search for the word "News" for the news.
+
+- https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
++Contents
++========
++* What it is
++* Web site
++* Get it
++* Usage
++ * FAQ
++* Author
++* Bugs
++* Future direction
++* Random bits
++* History (News are here)
++* Source code
++* Copyright
+
+-All questions regarding this software should be directed at the
+-Xorg mailing list:
++What it is
++==========
++It enables for example "Shift/Space dual role key." When you press the
++space key alone, it's a space; but when you press it with another key,
++it's a shift. And/or Alt/Esc, AltGr/BS...
+
+- http://lists.freedesktop.org/mailman/listinfo/xorg
++It is a fork of evdev driver = xf86-input-evdev. It's ** only for
++Linux ** - X in other platforms don't use evdev driver. You can use
++"keydouble" referred below if you're not a Linux user. For MS Win
++users, there's AutoHotKey.
+
+-The master development code repository can be found at:
++With this hack, your hands can stay at the home position almost
++always, and feel more "at home", thus "At Home Modifier".
+
+- git://anongit.freedesktop.org/git/xorg/driver/xf86-input-evdev
++More precisely, you specify pairs of two keycodes, the "original", and
++the "translated". The last event gets recorded in this patch. After
++the press of one of "original" keys, the driver instead reports a
++translated key press event. When an original key is released, it sends
++a release of the translated key. And it sends a press and release of
++the original key if necessary, judging from the last event.
+
+- http://cgit.freedesktop.org/xorg/driver/xf86-input-evdev
++Web site
++========
++http://gitorious.org/at-home-modifier/pages/Home
+
+-For more information on the git code manager, see:
++Distro forum threads:
++* Gentoo: https://forums.gentoo.org/viewtopic-t-865313.html
++* Arch: https://bbs.archlinux.org/viewtopic.php?pid=938140
++* Ubuntu: http://ubuntuforums.org/showthread.php?p=10907505
++* Debian: http://forums.debian.net/viewtopic.php?f=20&t=65950
+
+- http://wiki.x.org/wiki/GitPage
++Get it
++======
++
++Download
++--------
++The tar.gz is here:
++http://gitorious.org/at-home-modifier/download/blobs/raw/master/source/ahm-2.8.0.tar.gz
++
++You can also download the patch against the Xorg's original driver,
++"xf86-input-evdev" from the website.
++
++git
++---
++Git access is available, too. For the first time, install git, and clone as
++ $ cd some/dir
++ $ git clone git://gitorious.org/at-home-modifier/at-home-modifier.git
++
++You can receive updates by
++ $ cd some/dir/at-home-modifier
++ $ git pull
++
++Version tags
++------------
++ $ git tag -l "ahm*"
++lists all releases, like ahm-2.5.1.
++
++You can see the difference to the original code by:
++ $ git diff xf86-input-evdev-2.5.0..ahm-2.5.0
++
++Install
++-------
++* Gentoo Linux users can use ebuild files. Visit the Gentoo Forum thread.
++* Arch Linux AUR entries are there. Visit the Arch Forum thread.
++* Debian and its derivatives: Visit the Debian Forum thread.
++
++Forum threads are listed above.
++
++Other Linux users can install it by replacing xf86-input-evdev.
++Compilation can be done just the same way as the original. I'd
++appreciate it a lot if you could send me your distro support.
++
++** Server upgrading note **
++When you upgrade your xorg-server-x.y.z, be sure to rebuild this
++driver, too. (Change in z doesn't affect, but x or y does.)
++
++Usage
++=====
++First, know the keycodes you need, which are numbers assigned to each
++physical key. It's easiest to install and invoke "xev" commands. In my
++case it says space is 65, and left shift is 50. OK. (See below for
++complicated cases.) Then write your xorg.conf or
++xorg.conf.d/10-keyboard.conf:
++
++ # For the details see "man xorg.conf" or your distro doc.
++ Section "InputClass"
++ Identifier "my keyboard"
++ Driver "evdev"
++ Option "XKBOptions" "terminate:ctrl_alt_bksp" # and so on
++
++ # If you save this file under xorg.conf.d/ :
++ Option "AutoServerLayout" "on"
++
++ MatchIsKeyboard "on"
++ # If you have multiple keyboards, you want something like one of them:
++ # MatchProduct "AT Translated Set 2 keyboard"
++ # MatchUSBID "0566:3029"
++ # Name is found in Xorg log, following the message "Adding input device"
++ # or by
++ # $ cat /proc/bus/input/devices
++
++ ### at-home-modifier options begin here.
++ # The basic option.
++ Option "TransMod" "65:50 102:241" # Defines key/modifier pairs.
++
++ ## Fine tuning options. Explained in a later section.
++ # For the first time, omit them.
++
++ # Option "AhmTimeout" "400" # In millisecond.
++ # Option "AhmDelay" "65 102" # Delayed keys. Seperate by spaces.
++ # Option "AhmFreezeTT" "true"
++ # Option "AhmResetTime" "10" # In sec.
++ # Option "AhmPaddingInterval" "10" # In millisecond.
++ EndSection
++
++If you want to specify multiple pairs for TransMod, separate them with
++whitespaces, like this:
++
++ Option "TransMod" "65:240 102:241 100:241"
++
++Don't forget to restart X!
++
++Notice that the modifier keys should come to the second of pairs.
++
++Options recognized by at-home-modifier (in fact, by any X drivers)
++are printed to X log, typically /var/log/Xorg.0.log, like this:
++
++ [ 50.579] (**) Option "AhmTimeout" "400"
++
++Fine tuning options
++-------------------
++For the first time, skip this section. Come back after you actually
++try.
++
++*** Other keys ***
++
++Assume you want the Left-Alt to be Alt/Esc. Then assign Esc to that
++key, using xmodmap. If you don't have any other Alt keys, then allocate
++Alt to keycode 240 or so, which must be unused on usual keyboards.
++
++For more complicated changes, you can tamper with files in
++/usr/share/X11/xkb/symbols/. See also the section "More on keycodes"
++below.
++
++The bottom row of my keyboard is Esc-BS-Spc-Ret-Tab, from left to
++right, with the overlay Alt-Shift-Ctrl-Shift-Alt. (Japanese keyboards
++have many keys you can press with thumbs. Now you can switch Firefox tabs
++with thumbs.=)
++
++You can use any keys for transmods. "d" & "k" (and so on) may be good.
++When you want to capitalize the left-hand keys, press "k", and "d"
++for right-hands. This may sound too complex, but you'll be soon
++accustomed.
++
++*** Cancellation by long press (timeout) ***
++
++Suppose you were about to input shift + A and pressed space/shift, but
++you changed your mind. If you release the space/shift key, you'll
++receive one space, but it's not what you want!
++
++Actually, a workaround is provided by time-out; a long enough press
++cancels that kind of press. If you have the following line in evdev
++driver configuration,
++
++ Option "AhmTimeout" "400" # In millisecond.
++
++then a single press and release of space/shift key produces nothing if
++the press lasts more than 0.4 sec. The default is 0.6 sec. You can
++disable timeout by setting it to 0.
++
++*** Fast type fix (delay) ***
++
++(Probably this option is not so satisfactory) Users of this hack often
++have "tongue-twister of fingers": Suppose you want a space and a lower
++case x. If the first press of space/shift is followed first by a press
++of x and then a release of space/shift, you'll get an upper-case X
++instead.
++
++To fix it, you can let "delay" be associated to space/shift, like:
++
++ Option "AhmDelay" "65 102" # Delayed keys. Separate by white space
++
++Then the press of x (or any) following space/shift is "delayed",
++and completes after release of space/shift or x.
++
++There's a trade off. Whenever you want a real shift, you have to
++release the space/shift later.
++
++This feature is not (yet) satisfactory for the author. Maybe it
++should be treated as a modifier only if the key is pressed long
++enough (say 100ms), in addition to / instead of the press-release
++orders.
++
++*** Successive transmod tuning ***
++
++A subtle fix is enabled by default; suppose a transmod X has been
++pressed. If "transmod Y press, X release" follows, then the press of Y
++is treated as the original key. It's probably what you want.
++
++You can disable it by setting the boolean option "AhmFreezeTT" to false.
++("TT" is meant for "transmod-transmod".)
++
++See also "Corner cases in press and release order" below.
++
++*** Reset ***
++
++Sometimes translated modifiers get frozen (See "Switching VT" section
++below), so a workaround is provided; just leave the keyboard long
++enough time (default 10 secs) untouched.
++
++You can change this time with the following option:
++ Option "AhmResetTime" "10" # In sec.
++To disable this feature, set it to 0.
++
++Reset is implemented by sending release events to all translated
++modifiers, and clearing internal variables. The time measurement is
++not exact, and the maximal error is 1 sec. (Implementation note: It's
++because the sub-second field of timeval struct is ignored.) The exact
++time things get reset is the first time you touch the keyboard.
++
++*** Gtk widget double-press workaround (padding interval) ***
++
++Suppose you focus a gtk window with a button widget. When you press
++the shift/space, the button should be pressed. But with this hack,
++you may have to press the key twice; the first press merely focuses
++the button, and the second key press becomes the real push.
++
++As a workaround, "padding interval" can be set:
++ Option "AhmPaddingInterval" "10" # In millisecond.
++The default value is 10 ms, and I think it's good, but if it doesn't
++work, set it bigger.
++
++How it works: remember that a release of shift/space key, without touching
++other keys, sends a release of shift, a press of space, and its
++release. Padding interval is inserted between the shift release and
++the space press. Bigger the value, likelier to work, but the latency
++gets bigger, too.
++
++I don't know what's happening inside of gtk, but this solves.
++
++More on keycodes
++----------------
++It's good to know that you can also tell keycodes by looking at
++/usr/share/X11/xkb/keycodes/evdev in order to customize the keyboard
++layout with XKB. For example that file says:
++
++ <SPCE> = 65; // space
++ ...
++ <LFSH> = 50; // left shift
++
++Ok, but what's this?
++ <AE02> = 11;
++
++Hm, if you use for example Italian layout, see
++/usr/share/X11/xkb/symbols/it. It has lines:
++
++ xkb_symbols "basic" {
++ ...
++ key <AE02> { [ 2, quotedbl, twosuperior, dead_doubleacute ] };
++ ...
++ }
++
++ xkb_symbols "nodeadkeys" {
++ // Modifies the basic italian layout to eliminate all dead keys
++ ...
++ key <AE02> { [ 2, quotedbl, twosuperior, doubleacute ] };
++ ...
++ }
++
++Aha, so that key is basically "2".
++
++FAQ
++---
++* Q: I need to input Shift+Space. How can I do it if my space is
++ Space/Shift key?
++ A: Simple. Turn both of the original Space and Shift into Space/Shift keys,
++ for example.
++
++Please!
++-------
++If you think this fork is good, please tell it to others, at blogs,
++forums, etc. If it doesn't become popular, it remains my personal hack,
++and it may soon become impossible for me to maintain!
++
++Or, you can upvote this answer in stackoverflow.com to draw more
++attention:
++http://stackoverflow.com/a/8935973
++
++Please give your feedback. The host site doesn't provide an access
++counter, so I can't measure the popularity.
++
++Author
++======
++Teika kazura <teika ahm-is-great at lavabit ahm-is-great dot com>
++
++Delete "ahm-is-great" in the address.
++
++It's good *not* to trust authors you find on the Web. You may be
++reassured to know that I was a developer of Sawfish window manager:
++ http://sawfish.wikia.com/wiki/User:Teika_kazura
++
++Bugs
++====
++
++Fixed bugs
++----------
++* In 2.6.3
++ ** Gtk widget double press issue.
++ To push a gtk button, sometimes you had to press space/shift key
++ twice, but this is fixed. If it doesn't work out-of-box, set
++ "AhmPaddingInterval" option.
++ (This "bug" is not the author's fault, but what's bad for users
++ are bugs.=)
++
++ ** Reset and Delayed key
++ "Delay" and "Reset" are features introduced in 2.6.2. If a delayed
++ key is pressed after a long enough period is passed (i.e. a reset is
++ done), the press was ignored. It's fixed now.
++
++* In 2.6.2
++ ** Key release interference bug
++ Suppose you press x, space/shift, release x, release
++ space/shift. Probably you wanted "x ". But formerly, only "x" is
++ sent. (More precisely, "x" + shift are sent. Don't confuse it with
++ "AhmDelay".)
++
++ ** Frozen key bug
++ Probably ahm-2.6.0 has introduced a new bug which makes some keys
++ irresponsive. The bug existed in theory, but the author has never
++ experienced it actually.
++
++ ** Memory leak
++ Previous version had slight memory leaks (almost unnoticeable).
++
++ ** (obsolete) keycode limit
++ __This feature is deleted in 2.6.3__
++ X's keycode limit is 255, but linux input driver's keycode limit is
++ 0x2ff. Now it accepts input codes > 255.
++
++* In 2.6.0
++ ** Double shift bug
++ Suppose both key a and b are translated to shift. Press a, b, and
++ release b. Then it should be 'B', but it used to emit lower b. It's
++ because the release of shift was sent before b key press.
++
++Known bugs
++----------
++* Switching VT: If your Ctrl is a transmod key, when you switch from X
++ to a virtual console with Ctrl + Alt + F1, and switch back to X with
++ Alt + F1, Ctrl get frozen. This is mitigated with "reset" feature.
++
++ It happens because Ctrl is pressed at the first switching, but the
++ release is only sent to the VT, not to X, in particular to this driver.
++
++Not a bug
++---------
++Many keyboards fail to send some combinations of key presses. For
++example, mine doesn't report Left-alt + space(Ctrl intended) +
++cursor-down nor alt + space + delete (whereas alt + space + up is
++dispatched!!) All normal symbol keys pressed with alt + space work.
++
++Keyboards with "n-key rollover" are the solution, and completely ok
++for this hack, but they may be expensive. (USB connection can't report
++7 or more simultaneous presses, but it doesn't matter for us.)
++
++*** Limitations ***
++This driver is unaware of others, for example of synaptic driver.
++Suppose you press space/shift and the left click of notebook touchpad.
++It'll work as shift + click, but a space key event follows. (Timeout
++can give a workaround.)
++
++Future direction
++================
++Probably the author, Teika kazura, won't develop this hack any more as
++a fork of X evdev driver.
++
++Realistic solutions are to re-implement it using X Record extension
++and XTest extension. There's already Space2Ctrl and Keydouble. See
++below for more. (X Record records inputs, and XTest synthesizes
++events. They're better than mine since they work in user space. The
++codes are far smaller and much easier to read, and you don't have to
++keep up with Xorg changes so much.)
++
++It's great if it's integrated into AutoKey[2]. It's a nice utility
++similar to AutoHotKey for MS Win, and it has some automation power
++using Python. It also uses X Record extension, and probably interfere
++with Space2Ctrl and Keydouble. Unfortunately, the AutoKey developer is
++not interested.[3] If you can, please help them.
++
++[2] http://code.google.com/p/autokey/
++[3] http://code.google.com/p/autokey/issues/detail?id=200
++
++This hack can't be merged upstream.[1] One unlikely solution is to
++implement this in "XKB2", which will, probably, never be written.
++(Wayland is far likelier to be than XKB2.)
++
++[1] http://lists.x.org/archives/xorg/2010-December/052133.html
++
++Wish items
++----------
++Autorepeat support. For example, you press space/shift twice in a row,
++and/or hold it long enough, then it's turned to the press of space,
++rather than shift.
++
++Delay improvement. See the "Delay" section
++
++Two-way arguments: currently an original-translated pair is written
++as "65:50". It's better to allow "65:50m" or "50m:65", "m" meaning
++"modifier".
++
++"Dynamic configuration", or config changes on-the-fly may be good, for
++example enabling some keys only when you're using an input method. I
++don't know anything about socket or inter-process communication, so
++please tell me how to do it. (Space2Ctrl and Keydouble don't need
++this. Simply kill the process and run another.)
++
++See also this page for some ideas:
++http://www.ruska.it/michal/fork.html
++
++Bug reporting
++-------------
++When you report a bug, don't forget to disable autorepeat by
++ $ xset -r [<keycode>]
++
++It's better to make AhmResetTime big, and if you enable AhmDelay,
++set it big, too.
++
++I compile with -Wall -Wextra, and my code does not bring in any extra
++warning.
++
++Corner cases in press and release order
++---------------------------------------
++There're many corner cases, and I can't predict all. The option
++"AhmFreezeTT" is easy not only to reason, but also to code, but
++more complicated examples may not be so.
++
++More may be possible, by knowing which keys are modifiers. (This hack
++doesn't use any information which are modifiers. What's done is a
++simple translation.) You can get the required information by Xlib or
++XKB, but it'll be an inverted implementation, fetching the high-level
++part from the raw world.
++
++Or programmable configuration (together with timestamp support),
++something like an automaton, may help. But don't ask me it. I don't
++know how to design such logic nor to write a parser.
++
++Random bits
++===========
++
++Will this patch speed up typing?
++--------------------------------
++In my case, it didn't. But I (or my hands) feel far better and I can't
++do without this fork any more. It's much less tiring, so it may be
++more efficient if you use keyboard for long time in a day.
++
++In fact, this hack introduces some nicety. Options like delay and
++timeout are intended for the cure, but they bring in others.
++
++Warning: Health issue
++---------------------
++This hack is likely to reduce the use of your pinkies, and the risk of
++their injury like RSI. However, overuse of keyboards can damage *any*
++digits and other parts of your hand, although pinkies are most
++vulnerable.
++
++Good keyboards
++--------------
++If you can buy a Japanese keyboard, I recommend one. The Japanese
++keyboard is a "cheap Kinesis"; the space key is short, and there're
++keys around the space key which can be easily pressed with thumbs.
++(Have you ever heard of Kinesis Contoured Keyboard?) See for example
++http://en.wikipedia.org/wiki/Keyboard_layout
++
++But it's only the layout. I can't assure the overall quality. Of course
++it's better to try before you buy...
++
++"Realforce" keyboard made by Topre is unique with capacitive key
++switches whose touch is really soft. "HHK Professional" (HHK = Happy
++Hacking Keyboard) also uses Topre's switch.
++
++Kinesis contoured, Realforce and HHK Professional come with n-key
++rollover. (See also "not a bug" section above for "key rollover".)
++
++FYI: mine is OWL-KB86STD made by Owltech. It's cheap, and has cheap
++touch, but I like the layout. You can buy it from Amazon Japan.
++(I don't like Amazon hegemony, but they provide English interface.
++Many Japanese keyboards are sold at amazon.com, too.)
++
++OWL-KB109BM(B)IIB has "Cherry mx brown switches", so may be good.
++See http://forums.gentoo.org/viewtopic.php?p=7019478#7019478 for more
++discussion.
++
++Alternatives
++============
++There're some alternative candidates of at-home-modifier.
++
++* Xcape, Space2Ctrl & Keydouble
++ https://github.com/alols/xcape (xcape)
++ https://github.com/r0adrunner/Space2Ctrl (Space2Ctrl)
++ https://github.com/baskerville/keydouble (Keydouble)
++
++ Xcape is independently written by Albin Olsson. Accepts
++ configuration with key names in addition to keycodes. The keydouble
++ author recommends xcape over keydouble.
++
++ Space2Ctrl by "r0adrunner" is minimal, only supports "Space to
++ Ctrl", and not configurable. Written in C++.
++
++ Keydouble by "baskerville" is a rewrite of Space2Ctrl in C. Has a
++ bit less options than mine.
++
++Obsolete alternatives
++---------------------
++* actkbd: It works by direct access to /dev/input, but not updated
++ since 2007. I don't think it's flexible enough.
++
++ http://users.softlab.ntua.gr/~thkala/projects/actkbd/
++
++* 窓使いの憂鬱 (Mado-tsukai no yū-utsu; meaning "Spleen of Windows
++ Users") for Linux & Darwin: It's a port of a Windows key tuner
++ software "窓使いの憂鬱", comparable to AutoHotkey. Japanese
++ documentation only. The author is not reachable. Not maintained
++ actively. It uses uinput. The last update was in Nov 2011.
++
++ http://www42.tok2.com/home/negidakude/
++
++History
++=======
++
++News
++----
++* 2.8.0 (jun 2013):
++ * Merged upstream 2.8.0.
++ More precisely,
++ * There're two fix-up commits after 2.8.0 in the upstream. They're
++ merged too.
++ * In ahm-2.7.1, configure option "--without-mtdev" was added. But
++ now it's deleted, and mtdev dependency is mandatory.
++
++* 2.7.3 (nov 2012):
++ * Merged upstream 2.7.3. Ahm-2.7.2 was never released.
++
++* 2.7.1 (jun 2012):
++ * Merged upstream 2.7.0. No any change in ahm per se, except doc.
++ * An upstream bugfix of horizontal scroll, X.Org Bug 46205, is
++ included. (The fix is published after the 2.7.0 release.)
++ * Added an option to configure script "--without-mtdev". The
++ upstream code always checks mtdev, and enable it when found.
++ If you don't pass the above option, it falls back to the
++ original behavior.
++
++ This change, commit 371543edf0b, probably has to be reverted
++ before merging upstream 2.8.0. The upstream suggests mtdev
++ dependence will be forced in future versions.
++ * Read also "Future direction" section in this README.
++ * The hack version is 2.7.1, not 2.7.0, without much reason.
++
++* 2.6.4 (dec 2011):
++ * Other device awareness
++ When you press space/shift and a mouse button, the result used to be
++ shift + click, ok, but also followed by an extra, unwanted
++ space, as if the click hadn't happened. It's because each device
++ ignored others. Now it's fixed, as long as the mouse is also
++ handled by evdev driver. (Notebook touchpads are dealt by
++ synaptics driver, so it's not fixed, and won't be fixed. Use
++ AhmTimeout option as a workaround.)
++
++ Thanks to the ArchLinux forum user "grimp3ur" for the idea.
++* 2.6.3 (nov 2011):
++ * Bugs fixed
++ Gtk button double press bug. Reset and delayed key bug.
++ * Big keycode support is deleted.
++ In 2.6.2, big keycode support was introduced, but it's
++ deleted. loadkeys (1) command suffices.
++* 2.6.2 (oct 2011):
++ * New features
++ Long press cancellation (Option "AhmTimeout"), fast type fix
++ (Option "AhmDelay"), successive transmod tuning (Option
++ "AhmFreezeTT"), reset (Option "AhmResetTime") are implemented.
++
++ Thanks to the ArchLinux forum user "bloom" for the idea of
++ long press cancellation.
++ * Bugs fixed
++ Release interference bug, keycode limit bug, and 2 other minor
++ bugs are fixed.
++ * Documentation
++ New sections: "Not a bug", "Corner cases", "Alternatives", "Source
++ code".
++ New bug item: "Switching VT".
++ New wish items: "Dynamic configuration", "autorepeat support"
++ * Feature deleted in later release.
++ "Big keycode support" is introduced in 2.6.2, but deleted in 2.6.3.
++* 2.6.1 was never released.
++* 2.6.0 (apr 2011): Merged upstream 2.6.0. "Double shift bug" is fixed.
++* 2.5.1 (feb 2011): Minor documentation updates.
++* 2.5.0 (feb 2011): Initial release. Forked from upstream 2.5.0 = xf86-input-evdev-2.5.0.
++
++Versions 2.X.y are based on the upstream 2.X.0, unless noted explicitly.
++
++Background
++----------
++What was proposed originally was called "SandS" - stands for "Space and
++Shift" - which dates back to year 2001, by K. Kimura.[1] There's
++implementations in Mac and Win, and has a modest popularity in Japan
++still in year 2011. (K. Kimura has also contributed a lot to Japanese
++input methods.)
++
++In 2008 T. Matsuyama implemented it for X keyboard driver.[2] Then
++came a port to evdev driver by "jeneshicc".[3] But they lack
++generality; you can only use physical shift, alt, and space keys. My
++code is based on the last patch. I appreciate their work.
++
++[1] (Japanese) http://hp.vector.co.jp/authors/VA002116/
++[2] (Japanese)
++http://dev.ariel-networks.com/Members/matsuyama/keyboard-customize
++[3] (Japanese):
++http://d.hatena.ne.jp/jeneshicc/20100306/1267843799
++
++Space2Ctrl was (probably) written independently in 2011.
++
++Source code
++===========
++
++(Rather than developing this hack more, I recommend you to deal with
++Keydouble or AutoKey.)
++
++Required knowledge
++------------------
++Required is only C knowledge, none of X. I've added some comments, so
++it must be easy to understand.
++
++src/evdev.h
++-----------
++Search for "ahm variables".
++
++In src/evdev.c, gcc __attribute__ is used. To support other compilers,
++it's defined null when __GNUC__ is not defined.
++
++src/evdev.c
++-----------
++* Parsing options
++ Ahm options are parsed in function NewEvdevPreInit. Search for
++ "parse ahm options".
++
++* Earlier event handling
++ In the Xorg original code, keyboard events are handled by
++ EvdevQueueKbdEvent. Ahm wraps it with AhmStep1 and AhmStep2, and
++ WrapEvdevQueueKbdEvent.
++
++* Later event handling
++ In the original code, events get really sent in
++ EvdevPostQueuedEvents. To implement AhmPaddingInterval, this
++ function is changed a bit, by queuing key events in ahm's own queue,
++ and asynchronous timer is set. Timer related functions I've added
++ are: AhmWakeupHandler, AhmBlockHandler, AhmRegisterTimers and
++ AhmFinalise.
++
++License
++=======
++Distributed under MIT License; Same as Xorg.
+Only in xf86-input-evdev-2.9.0.fixed manually/: README.orig
+diff -aur xf86-input-evdev-2.9.0.orig/src/evdev.c "xf86-input-evdev-2.9.0.fixed manually/src/evdev.c"
+--- xf86-input-evdev-2.9.0.orig/src/evdev.c 2014-05-20 15:41:26.000000000 +1000
++++ "xf86-input-evdev-2.9.0.fixed manually/src/evdev.c" 2014-06-08 15:03:08.040591069 +1000
+@@ -141,6 +141,8 @@
+ static Atom prop_virtual;
+ static Atom prop_scroll_dist;
+
++static InputInfoPtr ahmLastEventDevice;
++
+ static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode)
+ {
+ InputInfoPtr pInfo;
+@@ -282,23 +284,359 @@
+ return &pEvdev->queue[pEvdev->num_queue - 1];
+ }
+
+-void
++/*
++ * Returns 0 on failure, 1 on success.
++ * In the original, upstream code, it's a void function.
++ */
++int
+ EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
+ {
+ int code = ev->code + MIN_KEYCODE;
+ EventQueuePtr pQueue;
+
+- /* Filter all repeated events from device.
+- We'll do softrepeat in the server, but only since 1.6 */
+- if (value == 2)
+- return;
++ /* Filter all repeated events from device.
++ We'll do softrepeat in the server, but only since 1.6 */
++ if (value == 2){
++ return 1;
++ }
++
++ if ((pQueue = EvdevNextInQueue(pInfo)))
++ {
++ pQueue->type = EV_QUEUE_KEY;
++ pQueue->detail.key = code;
++ pQueue->val = value;
++ return 1;
++ }
++ else{
++ return 0;
++ }
++}
+
+- if ((pQueue = EvdevNextInQueue(pInfo)))
+- {
+- pQueue->type = EV_QUEUE_KEY;
+- pQueue->detail.key = code;
+- pQueue->val = value;
++/*
++ * Inside of AhmStep2, the keycode is X value. Restore the linux/input.h
++ * value which EvdevQueueKbdEvent accepts.
++ */
++static int
++WrapEvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value, int code){
++ ev->code = code - MIN_KEYCODE;
++ return EvdevQueueKbdEvent(pInfo, ev, value);
++}
++
++/* If the transmod "orig" key is pressed long enough and thus
++ timed out, it returns 1. Otherwise 0 */
++static int ahmTimedOutP(long int lastSec, long int lastUsec, struct input_event *ev, int timeOut){
++
++ /* timeOut is not set */
++ if(timeOut == 0){
++ return 0;
++ }
++
++ if( (ev->time.tv_sec - lastSec) * 1000
++ + (ev->time.tv_usec - lastUsec) / 1000
++ > timeOut){
++ return 1;
++ }else{
++ return 0;
++ }
++}
++
++/*
++ * Handles transmod and timeout
++ * code is X code, i.e. ev->code + MIN_KEYCODE
++ */
++static void
++AhmStep2(InputInfoPtr pInfo, struct input_event *ev, int value, int code)
++{
++ EvdevPtr pEvdev = pInfo->private;
++
++ int lastPressCode;
++
++ unsigned int * transModTable = pEvdev->transModTable;
++ int * transModCount = pEvdev->transModCount;
++
++ lastPressCode = pEvdev->lastPressCode;
++
++ if(value == 1){
++ pEvdev->lastPressCode = code;
++ }
++
++ if((value == 0)
++ && transModTable[lastPressCode]
++ && (lastPressCode != code)
++ && transModTable[code]
++ && (pEvdev->lastValue == 1)
++ && pEvdev->ahmFreezeTT){
++ /* Implements AhmFreezeTT */
++ transModCount[transModTable[lastPressCode]]--;
++ if(transModCount[transModTable[lastPressCode]] <= 0){
++ WrapEvdevQueueKbdEvent(pInfo, ev, 0, transModTable[lastPressCode]);
++ }
++ if(transModCount[transModTable[lastPressCode]] < 0){
++ /*
++ * Usually this doesn't happen, but not never, either.
++ * Thus in fact this line is necessary.
++ */
++ transModCount[transModTable[lastPressCode]] = 0;
++ }
++ WrapEvdevQueueKbdEvent(pInfo, ev, 1, lastPressCode);
++ pEvdev->transModFreeze[lastPressCode] = 1;
++
++ /* Treat the latest keycode as usual in the following. */
++ }
++
++ if(transModTable[code]){
++ if(pEvdev->transModFreeze[code] == 1){
++ /*
++ * When a freeze happens is explained above.
++ * If it's frozen, send the original key code.
++ */
++ WrapEvdevQueueKbdEvent(pInfo, ev, value, code);
++ pEvdev->transModFreeze[code] = 0;
++ }else{
++ /* Transmod, not frozen */
++
++ if(value == 1){
++ /* press */
++
++ /*
++ * Role of transModCount: suppose both key a and b are translated
++ * to left shift. Press a, b, and release b. Then it should be 'B'.
++ * But without transModCount, first the shift would be released,
++ * so lower b be emitted.
++ */
++ transModCount[transModTable[code]]++;
++ WrapEvdevQueueKbdEvent(pInfo, ev, 1, transModTable[code]);
++ }else{
++ /* release */
++ transModCount[transModTable[code]]--;
++ if(transModCount[transModTable[code]] <= 0){
++ WrapEvdevQueueKbdEvent(pInfo, ev, 0, transModTable[code]);
++ }
++ if(transModCount[transModTable[code]] < 0){
++ /*
++ * Usually this doesn't happen, but not never, either.
++ * Thus in fact this line is necessary.
++ */
++ transModCount[transModTable[code]] = 0;
++ }
++
++ if((lastPressCode == code)
++ && (ahmLastEventDevice == pInfo)
++ && (ahmTimedOutP(pEvdev->lastEventTime.tv_sec,
++ pEvdev->lastEventTime.tv_usec,
++ ev, pEvdev->ahmTimeout) == 0)
++ ){
++ /*
++ * Simple press and release of a transMod key, so
++ * send the original code.
++ */
++ WrapEvdevQueueKbdEvent(pInfo, ev, 1, code);
++ WrapEvdevQueueKbdEvent(pInfo, ev, 0, code);
++ }
++ }
+ }
++ }else{
++ /* Plain key */
++ if(value){
++ transModCount[code]++;
++ WrapEvdevQueueKbdEvent(pInfo, ev, 1, code);
++ }else{
++ transModCount[code]--;
++ if(transModCount[code] <= 0){
++ WrapEvdevQueueKbdEvent(pInfo, ev, 0, code);
++ }
++ if(transModCount[code] < 0){
++ /*
++ * Usually this doesn't happen, but not never, either.
++ * Thus in fact this line is necessary.
++ */
++ transModCount[code] = 0;
++ }
++
++ }
++ }
++ pEvdev->lastValue = value;
++ ahmLastEventDevice = pInfo;
++}
++
++/* Handles reset and ahmDelay before AhmStep2 */
++static void
++AhmStep1(InputInfoPtr pInfo, struct input_event *ev, int value){
++ /*
++ * Meaning of ev->code is described in linux/input.h, "Keys and buttons"
++ * section.
++ * code + MIN_KEYCODE is the value used by X, listed in
++ * /usr/share/X11/xkb/keycodes/evdev.
++ *
++ * Meaning of value: 0: release, 1: press, 2: autorepeat.
++ * Notice that autorepeat is _sent by kernel input driver_. Don't
++ * confuse it with X server autorepeat which is set by xset command.
++ */
++ int code = ev->code + MIN_KEYCODE;
++ EvdevPtr pEvdev = pInfo->private;
++
++ int* ahmDelayedCode = pEvdev->ahmDelayedCode;
++
++ /*
++ * Autorepeat has to be filtered for ahm, too.
++ * See also the comment in EvdevQueueKbdEvent.
++ * Early return will also be implemented in upstream 2.7.0.
++ */
++ if(value == 2){
++ return;
++ }
++
++ /* Reset part */
++ if (pEvdev->ahmResetTime &&
++ (ev->time.tv_sec - pEvdev->lastEventTime.tv_sec >
++ pEvdev->ahmResetTime)){
++ /*
++ * (more than) ahmResetTime (sec) has elapsed since the last press event.
++ * Release all translated modifiers, and reset transModCount and
++ * freeze table.
++ */
++ int c;
++ for(c = MIN_KEYCODE; c < 256; c++){
++
++ if(pEvdev->transModTable[c]){
++ /*
++ * I think release of transModTable[c] suffices,
++ * and release of c is not necessary.
++ */
++ WrapEvdevQueueKbdEvent(pInfo, ev, 0, pEvdev->transModTable[c]);
++ }
++ pEvdev->transModCount[c] = 0;
++ pEvdev->transModFreeze[c] = 0;
++ }
++ pEvdev->ahmDelayedKeys = 0;
++ }
++
++ /* Delay part. */
++
++ /* How many keys are already delayed? */
++ switch(pEvdev->ahmDelayedKeys){
++ case 0:
++ if(pEvdev->ahmDelayTable[code] && value){
++ ahmDelayedCode[0] = code;
++ pEvdev->ahmDelayedKeys = 1;
++ }else{
++ AhmStep2(pInfo, ev, value, code);
++ }
++ break;
++ case 1:
++ if(value == 0){
++ /* Release. Replay it. */
++ AhmStep2(pInfo, ev, 1, ahmDelayedCode[0]);
++
++ AhmStep2(pInfo, ev, 0, code);
++ pEvdev->ahmDelayedKeys = 0;
++ }else{
++ /* Another key is pressed. Queue this second event, too.*/
++ ahmDelayedCode[1] = code;
++ pEvdev->ahmDelayedKeys = 2;
++ }
++ break;
++ case 2:
++ pEvdev->ahmDelayedKeys = 0;
++ if( (value == 0) && (code == ahmDelayedCode[0]) ){
++ /* Gist of ahmDelay. */
++ AhmStep2(pInfo, ev, 1, code);
++ AhmStep2(pInfo, ev, 0, code);
++ AhmStep2(pInfo, ev, 1, ahmDelayedCode[1]);
++ }else{
++ /* Nothing special. Replay all, and bye. */
++ AhmStep2(pInfo, ev, 1, ahmDelayedCode[0]);
++ AhmStep2(pInfo, ev, 1, ahmDelayedCode[1]);
++ AhmStep2(pInfo, ev, value, code);
++ }
++ break;
++ }
++ pEvdev->lastEventTime.tv_sec = ev->time.tv_sec;
++ pEvdev->lastEventTime.tv_usec = ev->time.tv_usec;
++}
++
++/*
++ * (ahm) I don't know the exact spec of RegisterBlockAndWakeupHandlers.
++ * I merely guessed it from emuMB.c which is also a part of
++ * xf86-input-evdev.
++ */
++
++/*
++ * Really send queued key events, implementing AhmPaddingInterval.
++ *
++ * This function is called using timer. If padding is necessary,
++ * postpone these events.
++ *
++ * Simple sleeping doesn't work; it simply blocks.
++ */
++static void AhmWakeupHandler(pointer data, __attribute__ ((unused)) int ii,
++ pointer __attribute__ ((unused)) LastSelectMask){
++ InputInfoPtr pInfo = (InputInfoPtr) data;
++ EvdevPtr pEvdev = (EvdevPtr) pInfo->private;
++ int ms;
++
++ if(pEvdev->ahmQueueTop != pEvdev->ahmQueueBottom){
++ ms = pEvdev->ahmTimerExpires - GetTimeInMillis();
++ if(ms <= 0){
++ int i, lim;
++ unsigned int lastKey = 0;
++
++ lim = (pEvdev->ahmQueueTop < pEvdev->ahmQueueBottom) ?
++ pEvdev->ahmQueueBottom : pEvdev->ahmQueueBottom + AHM_QUEUE_SIZE;
++
++ for (i = pEvdev->ahmQueueTop; i < lim; i++){
++ if((pEvdev->transModTable[pEvdev->ahmQueueKeys[i % AHM_QUEUE_SIZE]]
++ == lastKey) && lastKey){
++ pEvdev->ahmTimerExpires = GetTimeInMillis() +
++ pEvdev->ahmPaddingInterval;
++ break;
++ }else
++ xf86PostKeyboardEvent(pInfo->dev,
++ pEvdev->ahmQueueKeys[i % AHM_QUEUE_SIZE],
++ pEvdev->ahmQueueValues[i % AHM_QUEUE_SIZE]);
++ lastKey = pEvdev->ahmQueueKeys[i % AHM_QUEUE_SIZE];
++ }
++ pEvdev->ahmQueueTop = i % AHM_QUEUE_SIZE;
++ }
++ }
++}
++
++
++static void AhmBlockHandler(pointer data,
++ struct timeval **waitTime,
++ __attribute__ ((unused)) pointer LastSelectMask)
++{
++ InputInfoPtr pInfo = (InputInfoPtr) data;
++ EvdevPtr pEvdev= (EvdevPtr) pInfo->private;
++ int ms;
++
++ if(pEvdev->ahmQueueBottom != pEvdev->ahmQueueTop){
++ ms = pEvdev->ahmTimerExpires - GetTimeInMillis();
++ if(ms <= 0){
++ ms = 0;
++ }
++ AdjustWaitForDelay(waitTime, ms);
++ }
++}
++
++static void AhmRegisterTimers(InputInfoPtr pInfo){
++ EvdevPtr pEvdev= (EvdevPtr) pInfo->private;
++ if(!pEvdev->flags & EVDEV_KEYBOARD_EVENTS){
++ return;
++ }
++ RegisterBlockAndWakeupHandlers(AhmBlockHandler,
++ AhmWakeupHandler,
++ (pointer)pInfo);
++}
++
++static void AhmFinalise(InputInfoPtr pInfo){
++ EvdevPtr pEvdev= (EvdevPtr) pInfo->private;
++ if(!pEvdev->flags & EVDEV_KEYBOARD_EVENTS){
++ return;
++ }
++ RemoveBlockAndWakeupHandlers(AhmBlockHandler,
++ AhmWakeupHandler,
++ (pointer)pInfo);
+ }
+
+ void
+@@ -312,6 +650,7 @@
+ pQueue->detail.key = button;
+ pQueue->val = value;
+ }
++ ahmLastEventDevice = pInfo;
+ }
+
+ void
+@@ -628,7 +967,7 @@
+ if (button)
+ EvdevQueueButtonEvent(pInfo, button, value);
+ else
+- EvdevQueueKbdEvent(pInfo, ev, value);
++ AhmStep1(pInfo, ev, value);
+ }
+
+ /**
+@@ -930,13 +1269,24 @@
+ {
+ int i;
+ EvdevPtr pEvdev = pInfo->private;
++ int ind = pEvdev->ahmQueueBottom;
+
+ for (i = 0; i < pEvdev->num_queue; i++) {
+ switch (pEvdev->queue[i].type) {
+ case EV_QUEUE_KEY:
+- xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].detail.key,
+- pEvdev->queue[i].val);
+- break;
++ /*
++ * ahm:
++ * In the original code, these key events are
++ * dispatched with xf86PostKeyboardEvent here.
++ * In ahm, they're queued, and sent asynchronously using timer.
++ * Actual flushing is done in AhmWakeupHandler.
++ */
++ pEvdev->ahmQueueKeys[ind] = pEvdev->queue[i].detail.key;
++ pEvdev->ahmQueueValues[ind] = pEvdev->queue[i].val;
++ ind++;
++ ind %= AHM_QUEUE_SIZE;
++ break;
++
+ case EV_QUEUE_BTN:
+ if (Evdev3BEmuFilterEvent(pInfo,
+ pEvdev->queue[i].detail.key,
+@@ -963,6 +1313,10 @@
+ #endif
+ }
+ }
++ if(pEvdev->flags & EVDEV_KEYBOARD_EVENTS){
++ pEvdev->ahmTimerExpires = GetTimeInMillis();
++ pEvdev->ahmQueueBottom = ind;
++ }
+ }
+
+ /**
+@@ -1428,6 +1782,15 @@
+ }
+ }
+ }
++
++ /* device only has mt-axes. the kernel should give us ABS_X etc for
++ backwards compat but some devices don't have it. */
++ if (num_axes == 0 && num_mt_axes > 0) {
++ xf86IDrvMsg(pInfo, X_ERROR,
++ "found only multitouch-axes. That shouldn't happen.\n");
++ goto out;
++ }
++
+ #endif
+
+ for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
+@@ -1935,6 +2298,7 @@
+ xf86FlushInput(pInfo->fd);
+ xf86AddEnabledDevice(pInfo);
+ EvdevMBEmuOn(pInfo);
++ AhmRegisterTimers(pInfo);
+ Evdev3BEmuOn(pInfo);
+ pEvdev->flags |= EVDEV_INITIALIZED;
+ device->public.on = TRUE;
+@@ -1961,11 +2325,11 @@
+ return EvdevOn(device);
+
+ case DEVICE_OFF:
+- if (pEvdev->flags & EVDEV_INITIALIZED)
+- {
+- EvdevMBEmuFinalize(pInfo);
+- Evdev3BEmuFinalize(pInfo);
+- }
++ if (pEvdev->flags & EVDEV_INITIALIZED){
++ EvdevMBEmuFinalize(pInfo);
++ Evdev3BEmuFinalize(pInfo);
++ AhmFinalise(pInfo);
++ }
+ if (pInfo->fd != -1)
+ {
+ EvdevGrabDevice(pInfo, 0, 1);
+@@ -2560,6 +2924,8 @@
+
+ pEvdev->type_name = NULL;
+
++ pEvdev->type_name = NULL;
++
+ return pEvdev;
+ }
+
+@@ -2621,6 +2987,118 @@
+ EvdevDragLockPreInit(pInfo);
+ }
+
++ if (pEvdev->flags & EVDEV_KEYBOARD_EVENTS)
++ {
++ /* parse ahm options */
++ char *str, *toFree;
++ char *next = NULL;
++ char *end = NULL;
++ int fromCode = 0, toCode = 0;
++
++ pEvdev->ahmQueueTop = 0;
++ pEvdev->ahmQueueBottom = 0;
++
++ pEvdev->lastPressCode = 0;
++ pEvdev->lastValue = 0;
++
++ for(fromCode = 0; fromCode < 256; fromCode++){
++ pEvdev->transModCount[fromCode] = 0;
++ pEvdev->transModTable[fromCode] = 0;
++ pEvdev->transModFreeze[fromCode] = 0;
++ pEvdev->ahmDelayTable[fromCode] = 0;
++ }
++
++ /* set timeout for ahm */
++ pEvdev->ahmTimeout = xf86SetIntOption(pInfo->options, "AhmTimeout", 600);
++ pEvdev->lastEventTime.tv_sec = 0;
++ pEvdev->lastEventTime.tv_usec = 0;
++
++ pEvdev->ahmDelayedKeys = 0;
++
++ pEvdev->ahmPaddingInterval = xf86SetIntOption(pInfo->options, "AhmPaddingInterval", 10);
++ /* Negative padding doesn't harm. */
++ pEvdev->ahmFreezeTT = xf86SetBoolOption(pInfo->options, "AhmFreezeTT", 1);
++
++ pEvdev->ahmResetTime = xf86SetIntOption(pInfo->options, "AhmResetTime", 10);
++
++ /* parse "transMod" option */
++ str = xf86CheckStrOption(pInfo->options, "TransMod",NULL);
++ if(str){
++ xf86Msg(X_CONFIG, "Option \"TransMod\" \"%s\"\n", str);
++ toFree = str;
++ next = str;
++ while(next != NULL){
++ fromCode = strtol(next, &end, 10);
++ if (next == end){
++ break;
++ }
++ if (*end != ':'){
++ xf86IDrvMsg(pInfo, X_ERROR, "TransMod : "
++ "Dest keycode is lacking; colon expected: %s\n",
++ str);
++ break;
++ }
++ end++;
++ next = end;
++ toCode = strtol(next, &end, 10);
++ if(next == end){
++ xf86IDrvMsg(pInfo, X_ERROR, "TransMod : "
++ "Dest keycode is lacking: %s\n",
++ str);
++ }
++ next = end;
++ /* xxx do range check, and store */
++ xf86IDrvMsg(pInfo, X_CONFIG, "TransMod: %i -> %i\n",
++ fromCode, toCode);
++ if((fromCode < MIN_KEYCODE) || (fromCode > 255)){
++ xf86IDrvMsg(pInfo, X_ERROR, "TransMod : "
++ "Keycode out of range: %i\n",
++ fromCode);
++ continue;
++ }
++ /* dest keycode has to be <= 255, due to X limit. */
++ if((toCode < MIN_KEYCODE) || (toCode > 255)){
++ xf86IDrvMsg(pInfo, X_ERROR, "TransMod : "
++ "Keycode out of range: %i\n",
++ toCode);
++ continue;
++ }
++ pEvdev->transModTable[fromCode] = toCode;
++ }
++ free(toFree);
++ }
++
++ /* parse option "AhmDelay" */
++ str = xf86CheckStrOption(pInfo->options, "AhmDelay", NULL);
++ if(str){
++ xf86Msg(X_CONFIG, "Option \"AhmDelay\" \"%s\"\n", str);
++ toFree = str;
++ next = str;
++ while(next != NULL){
++ fromCode = strtol(next, &end, 10);
++ if (next == end){
++ break;
++ }
++ next = end;
++
++ /* do range check, and store */
++ if((fromCode < MIN_KEYCODE) || (fromCode > 255)){
++ xf86IDrvMsg(pInfo, X_ERROR, "AhmDelay : "
++ "Keycode out of range: %i\n",
++ fromCode);
++ continue;
++ }
++ if(pEvdev->transModTable[fromCode] == 0){
++ xf86IDrvMsg(pInfo, X_WARNING, "warning: Delay key %i is not a transmod.\n", fromCode);
++ }
++ pEvdev->ahmDelayTable[fromCode] = 1;
++ }
++ free(toFree);
++ }
++
++ /* end of parsing ahm options */
++ }
++
+ return Success;
+
+ error:
+diff -aur xf86-input-evdev-2.9.0.orig/src/evdev.h "xf86-input-evdev-2.9.0.fixed manually/src/evdev.h"
+--- xf86-input-evdev-2.9.0.orig/src/evdev.h 2014-05-20 15:41:26.000000000 +1000
++++ "xf86-input-evdev-2.9.0.fixed manually/src/evdev.h" 2014-06-08 15:05:42.566913609 +1000
+@@ -37,6 +37,7 @@
+
+ #include <linux/input.h>
+ #include <linux/types.h>
++#include <sys/time.h>
+
+ #include <xorg-server.h>
+ #include <xf86Xinput.h>
+@@ -94,6 +95,13 @@
+ #define MAX_VALUATORS 36
+ #endif
+
++#define AHM_QUEUE_SIZE 256
++
++/* If we're not using GNU C, nuke __attribute__ */
++#ifndef __GNUC__
++# define __attribute__(x) /*NOTHING*/
++#endif
++
+ #ifndef XI_PROP_DEVICE_NODE
+ #define XI_PROP_DEVICE_NODE "Device Node"
+ #endif
+@@ -183,6 +191,33 @@
+ int delta[REL_CNT];
+ unsigned int abs_queued, rel_queued, prox_queued;
+
++ /* ahm variables */
++ int lastPressCode;
++ int lastValue;
++ unsigned int transModTable[256]; /* [orig keycode] means translated keycode */
++ int transModCount[256]; /* records how many times fold the translated key is pressed */
++ unsigned int transModFreeze[256]; /* 1 means temporarily transmod is frozen. */
++
++ int ahmTimeout;
++ struct timeval lastEventTime;
++
++ int ahmDelayTable[256];
++ int ahmDelayedCode[2];
++ int ahmDelayedKeys;
++ int ahmResetTime;
++
++ int ahmFreezeTT;
++
++ /* queuing variables */
++ int ahmPaddingInterval;
++ Time ahmTimerExpires;
++ int ahmQueueKeys[AHM_QUEUE_SIZE];
++ int ahmQueueValues[AHM_QUEUE_SIZE];
++ int ahmQueueTop; /* Dispatch from here */
++ int ahmQueueBottom; /* Queue from here */
++
++ /* end of ahm variables */
++
+ /* Middle mouse button emulation */
+ struct {
+ BOOL enabled;
+@@ -253,7 +288,11 @@
+ } EvdevRec, *EvdevPtr;
+
+ /* Event posting functions */
+-void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
++/*
++ * ahm changed the type. originally:
++ * void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
++ */
++int EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
+ void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+ void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value);
+ #ifdef MULTITOUCH
diff --git a/ahm.install b/ahm.install
new file mode 100644
index 000000000000..6e140d7507d5
--- /dev/null
+++ b/ahm.install
@@ -0,0 +1,29 @@
+post_upgrade() {
+ cat << EOF
+
+https://gitorious.org/at-home-modifier/at-home-modifier/blobs/raw/master/README
+
+First, know the keycodes you need, which are numbers assigned to each
+physical key. It's easiest to install and invoke "xev" commands. It
+says space is 65, and left shift is 50. Ok. Then write your xorg.conf:
+
+ Section "InputClass"
+ Identifier "my keyboard"
+ Driver "evdev"
+ Option "XKBOptions" "terminate:ctrl_alt_bksp" # and so on
+
+ # If you save this file under xorg.conf.d/ :
+ Option "AutoServerLayout" "on"
+
+ MatchIsKeyboard "on"
+ Option "TransMod" "65:50" # *** Look here ***
+ EndSection
+
+
+NEWS: More mouse support, read more at History/News section.
+EOF
+}
+
+post_install() {
+ post_upgrade
+}