9 years agoAdding specific support for Cintiq 21UX master
Aristeu Rozanski [Thu, 18 Nov 2010 15:40:29 +0000 (10:40 -0500)]
Adding specific support for Cintiq 21UX

Signed-off-by: Aristeu Rozanski <>
9 years agoadd support for Cintiq 21UX2
Aristeu Rozanski [Tue, 12 Oct 2010 21:01:43 +0000 (17:01 -0400)]
add support for Cintiq 21UX2

Signed-off-by: Aristeu Rozanski <>
10 years agoMerge branch 'master' of
Aristeu Rozanski [Thu, 5 Feb 2009 19:32:21 +0000 (14:32 -0500)]
Merge branch 'master' of

10 years ago* fix default button values for graphire
Aristeu Rozanski [Thu, 5 Feb 2009 19:31:51 +0000 (14:31 -0500)]
* fix default button values for graphire

10 years ago* added support for Bamboo tablets
Aristeu Rozanski [Mon, 26 Jan 2009 16:26:41 +0000 (11:26 -0500)]
* added support for Bamboo tablets
  Patch by: Karsten Festag

10 years ago* if linuxwacom 0.8.0 or newer is detected, clear the TouchStrips and Wheels assignments
Aristeu Rozanski [Mon, 26 Jan 2009 16:09:41 +0000 (11:09 -0500)]
* if linuxwacom 0.8.0 or newer is detected, clear the TouchStrips and Wheels assignments

10 years ago* newer Xorg servers changed 'use' field on the input devices struct
Aristeu Rozanski [Mon, 26 Jan 2009 15:29:20 +0000 (10:29 -0500)]
* newer Xorg servers changed 'use' field on the input devices struct
  Found by Fulup Ar Foll

11 years ago* updating Changelog
Aristeu Rozanski [Tue, 30 Sep 2008 21:40:31 +0000 (17:40 -0400)]
* updating Changelog

11 years ago* graphire 4 currently sends the events on buttons 9 and 13
Aristeu Rozanski [Tue, 30 Sep 2008 21:36:40 +0000 (17:36 -0400)]
* graphire 4 currently sends the events on buttons 9 and 13

11 years ago* make g4_internal_list[] more maintainable
Aristeu Rozanski [Tue, 30 Sep 2008 18:27:35 +0000 (14:27 -0400)]
* make g4_internal_list[] more maintainable

11 years ago* moving the xsetwacom version determination to a external function
Aristeu Rozanski [Wed, 3 Sep 2008 15:54:30 +0000 (11:54 -0400)]
* moving the xsetwacom version determination to a external function

11 years ago* bumping version to 0.4.2 v0.4.2
Aristeu Rozanski [Thu, 26 Jun 2008 19:40:54 +0000 (15:40 -0400)]
* bumping version to 0.4.2

11 years ago* updating Changelog
Aristeu Rozanski [Thu, 26 Jun 2008 19:38:37 +0000 (15:38 -0400)]
* updating Changelog

11 years ago* add support to Wacom Cintiq 20WSX
Aristeu Rozanski [Thu, 26 Jun 2008 19:07:59 +0000 (15:07 -0400)]
* add support to Wacom Cintiq 20WSX

11 years agoversion 0.4.1 v0.4.1
Mats Johannesson [Thu, 26 Jun 2008 18:52:34 +0000 (14:52 -0400)]
version 0.4.1
* Implemented a slightly better logic for Touch Strip movement detection.
This cuts down on "false positives" that can happen when the user lifts a
finger and places it on another spot, instead of dragging the finger there.

But even with this improved logic, false positives still happen if the touched
spots are too close to each other (one position up/down), and at the same time
have been recorded as being in the same "direction" in relation to the previous

To make it perfect we would have to examine Proximity Out events as well as
finger position. But that is not feasible - from what I've seen - since both
buttons and strips generate identical out of proximity events, coming from the
same "pad" device.

* With linuxwacom-0.7.7-3, xsetwacom got a parametre named TabletID (as a
synonym for GetTabletID). Since we base our whole tablet identification routine
on a correct return from that program, and don't know if the old form will
disappear in the future, TabletID henceforth is our first choice - with
GetTabletID as a backup.

This means that users with an older linuxwacom package will see a harmless
message from xsetwacom, for each detected device, when running directly in a
console: "Get: Unknown parameter 'TabletID'".

* Bugfix: While looking for a daemon instance of expresskeys, we parse the file
/proc/[PID-nr]/status and compare the program name there with the one read from
our own status.log. Unfortunately, the /proc file truncates program names to
15 chars, so an executable named eg expresskeys-0.4.0 would not be seen as
running even when it was.

We now also examine /proc/[PID-nr]/cmdline to catch such long names.

* The xerror_handler() in on_error.c used static numbers when checking
error_event->error_code Not good... Now changed to a better approach. And
having searched the net _extensively_ for solutions to this elusive X
programming problem, coming up with precious little, I've decided to quote
myself right here. Perhaps some search engine will index it for other hunters:

#include <X11/Xlib.h> /* XErrorEvent also pulls in X11/X.h with BadWindow def.*/
#include <X11/extensions/XIproto.h> /* Minor opcode error: X_OpenDevice */
int xerror_handler(Display* display, XErrorEvent* error_event)
/* There seems to be no standard way to catch an "BadDevice, invalid or
 uninitialized input device" error when trying to open devices which aren't
 plugged in. The extension error code varies (I've seen 169 and 170 myself)
 and the message string could be localized as well. Therefore we take a
 two-pronged approach here: Just return if the error code falls within the
 extension error range (>= 128) and at the same time is a X_OpenDevice
 "Minor opcode" as defined in X11/extensions/XIproto.h
   Also, in rare cases we might hit "BadWindow (invalid Window parameter)"
 (code 3) when looking for the present focus-window. I've only seen it with
 the "Firefox Preferences" window, but we better ignore any such case
 (standard error code from X11/X.h pulled in through X11/Xlib.h): */
if (((error_event->error_code >= 128)
&& (error_event->minor_code == X_OpenDevice))
|| (error_event->error_code == BadWindow)) {
return 0;

11 years agoversion 0.4.0 v0.4.0
Mats Johannesson [Thu, 26 Jun 2008 18:52:03 +0000 (14:52 -0400)]
version 0.4.0
OBSERVE: linuxwacom-0.7.5-2 or greater is now required for ALL tablets!

I would most prominently like to thank Magnus Vigerlof. His initial code
review of expresskeys 0.3.0 sparked an interest in refactoring. When Graphire4
was tacked on in 0.3.1 it became obvious that the code needed a total rewrite.
Since then I've forced myself on Magnus whenever a bit of guidance has been
sought. His suggestions, always technically sound and never patronizing, have
influenced my decisions to quite a degree. The resulting code however, can not
be blamed on anyone but me. The Sorcerer's Apprentice from Fantasia conveys a
proper guilt dispersion...

* A maximum of fifteen tablets (three of each model), and two styli per tablet,
are now handled concurrently.

'Models': nopad, Graphire4 BlueTooth, Graphire4, Intuos3 small, Intuos3/Cintiq

Corresponding configuration files, for each connected tablet, are differentiated
through their suffixes (.conf1 .conf2 .conf3): padless.conf1/2/3,
graphire4bt.conf1/2/3, graphire4.conf1/2/3, intuos3s.conf1/2/3 and

Observe that the files _not_ are locked to specific tablets. On program start
the first found tablet of a certain model gets to use the .conf1 file, etc.

To aid in configuration/debugging and possibly help external programs to
make an educated guess about the current connections, we print out easily
parsed lines in the status.log (and to the screen in -v[erbose] mode) Eg:


OUR CNFFILE = /home/loke/.expresskeys/intuos3.conf1
ConfigVersion-user = 4
ConfigVersion-ours = 4
CurrentPad  = pad1i3
CurrentSty1 = stylus1i3
CurrentSty2 = LACKING

OUR CNFFILE = /home/loke/.expresskeys/graphire4.conf1
ConfigVersion-user = 4
ConfigVersion-ours = 4
CurrentPad  = pad1g4
CurrentSty1 = stylus1g4
CurrentSty2 = LACKING

* A maximum of 32 keycodes can now be sent with each tablet button press
(Touch Strip movement/Scroll Wheel up-down). Because of this, all the "Plus"
fields from prior configuration file versions have been eliminated in
ConfigVersion 4.

Since a ConfigVersion 3 only will be correctly parsed on the first read,
not on re-reads, we do not support that version at all. Sorry, it became too
convoluted a code to retain backwards compatibility.

* Control of button auto-repeat has been implemented. No longer is X in charge,
wildly spewing out keycodes at the merest hint of a lingering button press.
Henceforth each and every button can have auto-repeat turned off or on,
depending on taste and target window (program). Also, as a sanity measure, the
auto-repeat will teminate on a focus-window change:

RepeatButton9/etc (I3), RepeatLeft/RepeatRight (G4) - Switch 1/0

Furthermore, we now have configurable delays:

ButtonRepeatAfter (wait before starting auto-repeat) - 0.01 to 10 seconds
DelayButtonRepeat (wait between each repetition) - 0.01 to 10 seconds

* Touch Strip auto-repeat has been implemented for the top and bottom positions:

RepeatLeftUp/RepeatLeftDown/etc - Switch 1/0
TouchRepeatAfter (wait before starting auto-repeat) - 0.01 to 10 seconds
DelayTouchRepeat (wait between each repetition) - 0.01 to 10 seconds

* To finalize the control aspect, a delay between each keycode sent can be
added. While reading a Wacom support forum (Windows/Mac only) I saw a
user asking for this feature. A target program of his would choke on the
keys coming in, since they came too fast. He had tried delaying by the use of
'dummy' keys like Escape and Space, but that could not rectify the problem.

So here we have a feature not (yet) available in the Win/Mac experience:

DelayEachKeycode (wait between sending of each keycode) - 0.01 to 10 seconds

* More fake keycodes. This time to implement tablet rotation from a button.
And, as I've gradually have seen a benefit to changing the stylus PressCurve
interactively from a button, make the user aware of that option by writing
it out in a first-time created configuration file (and in the USAGE file).
The implementation has been available ever since version 0.2.2, but the
documentation only in that ChangeLog entry - which nobody reads...

Here is a verbatim quote from the USAGE file:

+ Fake keycodes: 1001, 1002, 1003 +
Instead of defining a fixed stylus PressCurve for different program blocks,
you can use three values as keycodes to alter the curve interactively. 1001
will decrease the PressCurve, while 1003 will increase it. 1002 restores the
curve to its default state: "0 0 100 100". Both the upward and downward curve
changes flip over in a carousel fashion at the top and bottom values.

+ Fake keycodes: 1004, 1005, 1006, 1007, 1008, 1009 +
Use the value 1004 to return from a tablet rotation (NONE), 1005 to flip a
tablet 180 degrees (HALF), 1006 to rotate 90 degrees clock-wise (CW) and
1007 to rotate 90 degrees counter-clock-wise (CCW). By using 1008 you can
rotate the tablet endlessly in a clock-wise manner (CW-HALF-CCW-NONE-CW-)
and 1009 does the same motion counter-clock-wise (CCW-HALF-CW-NONE-CCW-).
Looking down on the tablet and tilting the head '90' degrees to the right
would simulate a CW operation.

* The code refactoring has of course enhanced the quality in many ways not
immediately obvious to the user. For example: We now filter out any illegal
keycode already at the configuration read stage; there is a more accurate
detection of whether a PID-file is 'live' or not; tablets defined in xorg.conf
but not plugged in at program start will not cause a termination with
"BadDevice, invalid or uninitialized input device" (though at least ONE
tablet must be connected at program start, otherwise we exit).

If I've forgotten to mention anything new in 0.4.0 you can always read the
code. It is very easy nowadays since no line stretches beyond column 80 (with
a tab-size of 8), and a lot of other coding conventions are followed as well.

Important: If you use the linuxwacom-0.6.7-beta or in the future
released versions you must change the pad statement in X config
file to:

Section "ServerLayout"
InputDevice "pad" # Intuos3 or Cintiq 21UX. It must NOT send core event


If you use the old pad statement, any pad button press will jump the
mouse cursor to the upper left corner (0,0) when another tool isn't
in proximity.

Run example: expresskeys pad &
Which will push it into the background. It is safe to close the terminal
afterwards. Oh, and X _must_ be running... The name, "pad" here, is
how it's called in xorg.conf (the "Identifier" option).

Update example 17 March 2005: Myself I've put it in the .xinitrc as
"exec /usr/local/bin/expresskeys pad &" (without quotes) right before
the window manager is started.

Key configuration is easy to change in the "user config area" below.
Use the "xev" program to find keycodes or look them up somewhere...
I've set the Wacom Intuos3 defaults on both sides, which is:
Shift, Alt, Control and Space. Touch strips are mildly supported.

Note 2 April 2005: Sometimes desktops or window managers "steal"
certain keypresses/combinations. If you experience that, look for
a way to change the keybindings of your environment.

11 years agoversion 0.3.2 v0.3.2
Mats Johannesson [Thu, 26 Jun 2008 18:50:19 +0000 (14:50 -0400)]
version 0.3.2
* Graphire4 button ordering was changed in linuxwacom-0.7.5-2 so that
Left Button sends a 9 and Right Button a 10 internally, instead of the
9 and 13 in previous drivers. Expresskeys has been updated accordingly.
This is the only change in 0.3.2! I'm still busy with the large refactoring
of a new codebase.

11 years agoversion 0.3.1 v0.3.1
Mats Johannesson [Thu, 26 Jun 2008 18:49:53 +0000 (14:49 -0400)]
version 0.3.1
* Graphire4 support. And what a chore it was! The task has revealed
weaknesses in the overall code structuring which _must_ be attended to.
So, a long time will pass on this end doing nothing but code refactoring.
Graphire4 got hacked in by some serious "spaghetti"...

OBSERVE: linuxwacom-0.7.5-2 or greater is _required_ for Graphire4 support!

In that release an option called GetTabletID was introduced (in xsetwacom
version 0.0.7), which gives us a reliable and future proof way of identifying
the tablet model any device belongs to (pad, stylus etc).

The function identify_device can be found in the exec_shell.c file, where
presently only Graphire4 as a family is registered. A finer grained division
is planned so that correct configuration files can be written out for the
Graphire4 BlueTooth, which lacks a Scroll Wheel, and the Intuos3 4x5 with
its single Touch Strip and 4 buttons.

Thanks go to Carsten Schurig for e-mail access to a real Graphire4.
Imagination and deducing can only produce the code, not verify it.

And, as a sidenote to the verifying part, the Scroll Wheel of a Graphire4
triggers button press/release events, (up = button 4, down = button 5) not
axis motion events as has been stated on the linuxwacom web pages.

* The -s switch to get status from a running program was added in the last
24 hours before the 0.3.0 release, without much thought. It turns out not
to be particularly useful in the intended manner. Standard error (stderr)
where it prints the report is private to each shell session. So if the
program already has been launched by one process, the next one who queries
from another shell will see nothing.

Therefore we now save a copy of the status output as a file as well in:
~/.expresskeys/status.log The file gets created automatically at a daemon
launch (updated with each -s query) and is deleted by a normal program exit.

* Inform the user about the different values for a PressCurve, as chosen by
the wacomcpl program, already in the initial _configuration_ file. Nice to
have a copy nearby when doing manual editing.

* Implemented a rudimentary error handler (xerror_handler in on_error.c) for
Xserver error returns. It is mostly a cosmetic thing, but now we can save the
message in error.log as well. The downside is that some of the informative
text from an unhandled X 'crash' is lost, like exactly which function call
that was involved. This can of course be rectified with a more complete handler,
but then the exit_on_error function needs additional parametres, and all the
calls to it need adjustments... Some other day.

* Discover the real mode of a stylus at program start, instead of assuming it
to be Absolute.

* Fixed a bug where -d together with any of -h, -s, -r and -k would delete a
live PID-file.

11 years agoversion 0.3.0 v0.3.0
Mats Johannesson [Thu, 26 Jun 2008 18:48:59 +0000 (14:48 -0400)]
version 0.3.0
* Finally and totally obliterated the src-expresskeysconf directory.
Such a tool will never be written by me. But there is hope balancing
on the horizon! At you'll find
"wacom-config", which is a pygtk (2.8+) point-and-click program for
configuration of the linuxwacom driver (through "xsetwacom") and
expresskeys version 0.2.x config file editing.

No more manual wrangling with "xprop" and "xev"! A future version
will support expresskeys 0.3.x (I've been assured).

* New configuration file (version 3), incompatible with version 2. The
reasoning around this switch can be read about in the USAGE file, ca
2/3 down under the heading "NEW in expresskeys version 0.3.0".

This will hopefully be the _last_ config file change that impacts the
user in a negative way. Future changes can be done non-destructively.

* New configuration _file name_. Depending on devices identified, either
a "padless.conf1" or an "intuos3.conf1" file is written out. Apart from
only containing relevant record fields, the headers of these files are
tagged with device "Identifier" strings from xorg.conf, like:

_intuos3.conf1_                         _padless.conf1_

ConfigVersion 3                         ConfigVersion 3
Identifier1Pad 1stIntuos3Pad            Identifier1Pad LACKING
Identifier1Sty 1stIntuos3Stylus1        Identifier1Sty Stylus1

The TODO file - better known as the "Wish-list" - hints towards why this
filename change has become desirable...

* Automatic detection and use of the first 'pad' and/or 'stylus' device found
through the XListInputDevices call. This happens unconditionally, but can be
overridden by specifically naming a device on the command line.

We still only allow one device of each kind (for now) so eg an automatically
picked stylus, say 1stIntuos3Stylus1, gets dropped if the user specifies the
1stIntuos3Stylus2 or a 2ndIntuos3Stylus1.

Anyone with a little programming understanding can change a copy of the code
in globals.c and alter the config_dir string to eg "/.expresskeys2". Then
that program copy can support another set of pad/stylus (until expresskeys
properly handles multi-devices).

* Expresskeys can now trace the stylus usage and automatically change
the pressure sensitivity (PressCurve) depending on which program window
that has focus. We call "xsetwacom" for the actual change, but the
implementation has minimal overhead - can't be felt or seen on my machine:

NOTE: To partially overcome a limitation in any Qt3 program (see the BUGS
file; they swallow all stylus button presses) we also have to judge the
state _every time_ the pen comes within operational height of the tablet,
aka ProximityIn.

1a) Stylusbutton - tip or rocker - pressed (doesn't matter which),
1b) or stylus reports itself as having entered proximity of the tablet.
2) Is the current focuswindow in our program list (plus "default")? = True.
3) Does the program name differ from the name in a historybuffer (1 back)?
4) Does the program presscurve differ from a historybuffer curve (1 back)?
5) Call xsetwacom only if these are true.

The above mentioned USAGE entry has all the important details.

So... now the program enters a more generic stage where it's beneficial
to any Wacom tablet user. Though, the name will remain expresskeys ;-)

* Deleted the old-extra directory with the small scripts for re-reading the
configuration file or terminating the program.

It is actually quite embarrassing, but the two options have been available
from _within_ the main_setup.c file since... forever. We already did a signal
send to check for a running daemon, so all it took was a slight rearrangement
and a few extra code lines. I _am_ myopic, but this oversight borders on

It is now possible to do an "expresskeys -r" or "expresskeys -k" against
a daemon instance. (BLUSH)!

* A few more command line switches have been introduced:

-x sets -v and exits after some important info blocks.
-s tells a daemon instance to report status (info block).

The 'status' signal is triggered through SIGUSR2 (re-read of the config file
has always been linked with SIGUSR1). The information printed out by -s
is almost exactly how -x displays it during a non-daemon run. Difference
being that -s also gives the "OUR RUN-PID" field.

OBSERVE: If expresskeys is started from the "outside" by use of .xinitrc or
similar methods, the output of -s will be seen on that first text terminal
(most often back at "Ctrl-Alt-F1" when in X). To get visibility from a terminal
_inside_ X, first do an "expresskeys -k" then "expresskeys -d" and THEN the
"expresskeys -s" ;-)

* Finally remembered to give a warning about Gimp and the pad device.
The USAGE file has it as a top item, and I'll copy the text here:

"Important: Gimp doesn't know _anything_ about a "pad" device, so the option
File --> Preferences --> Input Devices --> Configure Extended Input Devices...
--> [Device: pad  Mode: Disabled] is how it should be set. If you change it
to Sceen or Window, pressing pad buttons or using touch strips will NOT work."

* Updated to a working email address in the AUTHORS file and removed the
obsolete private project page from README. The canonical page now is:

It has been so since version 0.2.1, I just never got around to mentioning it.

11 years agoversion 0.2.6 v0.2.6
Mats Johannesson [Thu, 26 Jun 2008 18:47:28 +0000 (14:47 -0400)]
version 0.2.6
* Continuation of the maintenance by future proofing the ./configure phase
of the program compilation. We now examine what is returned from the commands
"pkg-config --variable=libdir x11" and "pkg-config --variable=includedir x11"
which is used to identify a modular X11R7 release. If that fails, we fall
back on a hardcoded /usr/X11R6/lib[64] and /usr/X11R6/include path for the
monolithic X11R6 releases. Failing that... the users can specify their own
paths through the "--with-xlib=" and/or "--with-xinc=" options. ".

11 years agoversion 0.2.5 v0.2.5
Mats Johannesson [Thu, 26 Jun 2008 18:45:35 +0000 (14:45 -0400)]
version 0.2.5
[Absolutely no new functionality! A pure maintenance release to prevent
trouble. Ticked off a todo-list based on user experiences and their snafus]

* Erased the useless code in the src-expresskeysconf directory. When or
if a graphical utility is written it should have a fresh start.

* Populated the auto-generated Gimp section of the configuration file
with a more complete set of keycodes (a collection which I use myself).
This was done in order to help people's understanding of the fields.

Updated the USAGE file with this Gimp information, close to the bottom,
since there was no easy way to auto-write a description in the configuration
file itself.

* Changed the and scripts
in the old-extra directory so they won't use any hardcoded program paths,
except for the #!/bin/sh trigger. I thought that I had used the canonical
paths, but distributions apparently shuffle stuff around willy-nilly.

* Threw in a basic trap/filtering routine in config_read.c which silently
swallows illegal keycodes from the low region - below 9 [Escape] - unless
the program is run in verbose (-v) mode. Then it spits out a "keycode IGNORED"
message when the configuration file is read. Xlib crashes the program when
fed unsavory keycodes, so more work can be done in this area.

* Implemented a ./configure discovery section where a dummy file is
compiled and linked for each of
X11/Xlib.h X11/Xutil.h X11/extensions/XInput.h and X11/extensions/XTest.h
Missing dependencies are thus quickly spotted and a comprehensible error
message delivered. A section dealing with dependencies has also been added
at the end of the INSTALL file.

The discovery section can be ogled in the file of the
root directory. I almost went mad before nailing a working piece like:

echo $'#include <X11/Xlib.h>\nmain(){}'|$CC -L$XLIBDIR -xc - -o dum 2>/dev/null
if test $? != 0 ; then
   echo "Can not include <X11/Xlib.h> header file!"
   echo "Xlib.h OK"

So simple looking and yet so hard to produce...

* Included the following text block in the runtime help, the README and
the USAGE file (and now here ;-)

"Please direct any bug reports or questions to the top address in
the AUTHORS file. This program is _not_ a linuxwacom project."

11 years agoversion 0.2.4
Mats Johannesson [Thu, 26 Jun 2008 18:41:33 +0000 (14:41 -0400)]
version 0.2.4
* Began code transfer/reuse from src-expresskeys to src-expresskeysconf
as a scaffold for some kind of graphical utility. Long way to go...

* Explained the X "xev" program and keycodes a little better in
the USAGE file.

* Put a warning regarding the X program "xmodmap" in the BUGS and
in the USAGE file.

* Cleaned up gcc warnings on a x86_64 system.

_Data Type Sizes (for my own reference)_

Type x86 x86_64

char 8 8
short 16 16
int 32 32
long 32 64
long long 64 64
float 32 32
double 64 64
long double 96 128
void* 32 64

In short, a programmer should NOT assume that:
sizeof(int) == sizeof(long) == sizeof(void*)

11 years agoversion 0.2.3 v0.2.3
Mats Johannesson [Thu, 26 Jun 2008 18:39:27 +0000 (14:39 -0400)]
version 0.2.3
* The project now uses the GNU Autotools to:
"./configure", "make" and "make install".

* Print out a version number with the "Usage" info if the program is
run with an empty command line.

* Corrected the Blender entry (undo/redo in both edit and object mode).
Yes, that's a cryptic line ;-) Try Blender for yourself. Next version,
(2.37) due this month or so, will be something extra.

11 years agoversion 0.2.2 v0.2.2
Mats Johannesson [Thu, 26 Jun 2008 18:16:28 +0000 (14:16 -0400)]
version 0.2.2
* Included an example of how to use an external program through
the simple "system" command (see exec_shell.c). The sample
"xsetwacom" utilization (pen pressure sensitivity) is not particularly
exciting as a new feature, but nevertheless an opening for future

It's hard to imagine someone wasting three full expresskeys to get
a comfortable workflow, but here you are:

Keycode field value (regular button only, not touch strips or Plus)
1001 <-- Pen sensitivity gets lower with each press, until roll over.
1002 <-- Pen sensitivity is set to wacom default, a middle curve.
1003 <-- Pen sensitivity gets higher with each press, until roll over.

A pen name must be specified on the command line, of course.

Since both the 1001 and 1003 flip over in a carousel fashion at the
top and bottom values, you could manage the operation with only one
button. But if you go too far, there are 6 presses to be made until
next rendezvous in the 7 state circle. Not good.

The curve values are picked from how the "wacomcpl" program sets them
(the tcl utility) in Feel -> Sensitivity [1 to 7].

I've refrained from documenting the 1001 - 1003 in the USAGE file, and
a new configuration file won't have them listed in the header. The real
world usability is too limited, I feel. Better things will hopefully
come in the future.

The old pen mode toggle code could be rewritten so it was handled by
this external xsetwacom functionality, in good *nix tradition of reuse.
But what if the user environment doesn't have the xsetwacom program
installed? Better leave the code as is, I think.

Speaking of the future, this 0.2.2 version will be the last one (from me
at least) for quite some time. When I began the project, more than 1 1/2
months ago, it was out of pure necessity. I had a brand new (expensive)
Wacom tablet with semi functional hardware. Extensive web searches didn't
reveal any program to unlock the enticing ExpressKeys and Touch Strips,
so I reluctantly opened a C language book and set to work.

I never planned to enter the "programmer" domain in earnest. Neither
did I anticipate a perpetual development. When the job was done, it
would be done...

And now it's done, from my point of view. Core functions are rather
complete, and the program runs without hiccups. Ideas have dried up
and I am frankly getting bored with code hacking. Now I want to USE
the tablet, finally.

The code is free as in beer and freedom. If anyone feels like expanding
or even forking it, just do so (according to the GPL). There's the whole
bag of internationalization, installation and graphical configuration
left to a fresh mind. I'm too tired right now.

Though, I'll dive in again if a pressing issue turns up ;-)

Bye for now,

11 years agoversion 0.2.1 v0.2.1
Mats Johannesson [Thu, 26 Jun 2008 18:15:20 +0000 (14:15 -0400)]
version 0.2.1
* Added support for faking mouse button events. Denis DerSarkisian
sent a function called "fake_event" (top of event_loop.c) which
in essence acts like a traffic cop, steering true keycodes to
XTestFakeKeyEvent and a set of false ones to XTestFakeButtonEvent.
The fake codes can be entered as 991 to 997 in the configuration
file, simulating mouse buttons 1 to 7.

Only existing mouse buttons, defined through the driver of the
active core pointer, can be simulated. I added discovery code to
prevent a crash if someone tries to use a nonexistent mouse button
in the range 1 to 7.

The code author wanted his touch strips to act like a mouse's scroll
wheel through the use of mouse buttons 4 - 5 (Up/Down) and 6 - 7
(Left/Right). I only have a three button mouse, the Wacom puck is
not a core pointer, but can make good use of the new functionality
in eg the web browser Opera:

20 Right Pad - Button 14: 993 # Button 14
21 Right Pad - Button 14 Plus: 991 # Extra key
24 Right Pad - Button 16: 991 # Button 16
25 Right Pad - Button 16 Plus: 993 # Extra key

With those definitions I step backwards (14) and forwards (16) in
the visited page history. Opera's "forward" can also take me to
the "Next" linked page, so it's very convenient when having a long
reading session.

* Expanded the "-v" (verbose mode) printing to cover more execution
points and be a lot more detailed.

* Racked my brain and added some more knowledge to the BUGS file.

11 years agoversion 0.2.0 v0.2.0
Mats Johannesson [Thu, 26 Jun 2008 18:13:37 +0000 (14:13 -0400)]
version 0.2.0
(NOTE: A version of this archive was pulled from the website after a
few hours of exposure on April 28, based on the suspicion that it
contained a corrupt file due to some file system issues on my machine.
Both fears were unfounded. I've spent this interim on further
restructuring of the text files outside of the code directories)

* New configuration file format. Incompatible with the old one, hence
the version bump from 0.1 to 0.2

Move/rename the old file and run the program to get a new. Then edit...

The old format was basically just a transcript of how a C structure
is initialized. It had nothing in common with how a configuration
file in *nix should be construed.

Rules for the new configuration file is: Blank lines and everything
after a "#" is discarded. Full program records begin and end with
a double percentage sign "%%". A program field begins after a colon ":".
The program names must be within two double quotes "". Like so:

"A ProgramName" <-- OK
" A ProgramName" or "A ProgramName " <-- NOT-OK

This is in accordance with the old rule about how to deal with spaces
in that field.

I can only vouch for parsing sanity if each line in the file is kept
below 160 bytes in length (see the BUGS file). That's the equiv of
two old style terminal lines. If you want more, change the MAXBUFFER
value in globals.h

* Another command line option: "-v". Will turn on the be_verbose flag
which prints info to the screen from plenty of program execution points.
An aid for debugging, or just checking out the runtime state.

* Got rid of the ugly switch routines in event_loop.c and config_read.c.
I've done extensive benchmarking and see no difference in code speed.
Advantage, apart from code simplicity, is that the compiled program
size was reduced by ca 4000 bytes - before the 0.2.0 additions.

11 years agoversion 0.1.4 v0.1.4
Mats Johannesson [Thu, 26 Jun 2008 18:06:46 +0000 (14:06 -0400)]
version 0.1.4
* Memory bugfix. Running the program under Valgrind to catch memory
leaks and other errors I finally saw the reason for me needing
heap_protect kludges. Doing XFreeDeviceList on a structure and then
reading data from the freed memory only works through luck...

* Took the opportunity to free lingering memory allocations at program
exit. It's not strictly necessary since the OS should reclaim it all,
but looks nice in the Valgrind summary. There's still one left that
I can't find the souce of. It belongs to XextCreateExtension apparently.

* Bugfix: Had forgotten to close the error.log after writing to it in
the exit_on_error function. Also, that function shouldn't do a final
exit(EXIT_KO) but instead jump to clean_up_exit(SIGTERM). However,
doing that it won't return the EXIT_KO to any parent. I'd have to
change the signal handling to achieve this.

* Bugfix: The config file version tag was meant to look like:

Version: 1

and nothing else, for now... The confusion and uncertainty stems from
doing this before a final format has been chosen. There are many factors
to consider, so bear with me.

* Reverted to the "expresskeys" base name on compile output and shell
files. When writing code it's more convenient with a short name, but
any final product should have a consistent naming.

11 years agoversion 0.1.3 v0.1.3
Mats Johannesson [Thu, 26 Jun 2008 17:50:51 +0000 (13:50 -0400)]
version 0.1.3
* Just internal code cleanup/restructuring after having begun reading
"The Art of Unix Programming" by Eric Steven Raymond:

* Now tags a new configuration file with a version number according to
his advice: "Always, _always_ either include a version number, or ...".
Expect more internal changes when I'm done reading. In an already
existing configuration file you'll have to add it manually. Put a:

Config File Version 1:

on a line by itself at the very top.

11 years agoversion 0.1.2 v0.1.2
Mats Johannesson [Thu, 26 Jun 2008 17:49:18 +0000 (13:49 -0400)]
version 0.1.2
* Signal handling in place. Not much in itself, but:

* Re-reads the configuration file upon receipt of the signal SIGUSR1.
Do a "kill -USR1 <pid-of-ekeys>" after a config file edit. That's USR
and the digit 1. I've also modified USR2 to do the same thing, for
now at least.

Included is a shell script called which does it for you
if ekeys is running in daemon mode. Also included is
which replaces the former (a bit smarter).

* The program will now refuse to start if it detects another instance
running. Only works if there is a pid-file to examine of course.
A pid-file left by a crash (will never happen...) and not connected
with any process by that number is ignored, and the program continues.

* A properly terminated program deletes the pid-file upon exit. Proper
means a normal "kill <pid>", "killall ekeys", "kill -TERM <pid>" etc.
Doing a brutal "kill -9 <pid>" or if the program crashes (cough, cough)
will leave the pid-file undeleted.

* Any error, encountered by the code, which terminates the program is
written to the file "error.log" as well as to the screen. A restart
truncates the file (it becomes size 0). This means that there always
will be an error.log present, but empty in normal cases.

11 years agoversion 0.1.1 v0.1.1
Mats Johannesson [Thu, 26 Jun 2008 15:29:14 +0000 (11:29 -0400)]
version 0.1.1
* Now reads an external configuration file at program launch. It
searches in the user home directory under the hidden "/.expresskeys"
directory. File is called "expresskeys.conf". If none is found, or
the directory doesn't exist yet, it makes the dir, then creates and
populates a minimal file from an internal list. The original "default",
"Gimp", "Blender" and "XTerm" entries. It then goes on and reads in
that file immediately. A limit of 64 different program definitions
has been set (easily altered in the code). It's way more than most
would need, since the "default" is fine for a huge group of programs.

Rules for the configuration file is: Don't use { or } in comments,
and preferably keep comments outside of program definitions. The
comma (,) inside a definition is still used to separate all the
fields. Program names don't need the embracing quotes "" but I
kept the default list using them. Since spaces are accepted as part
of a class name, make sure there are no space _before or after_ the
name, prior to the terminating field comma:

{"A ProgramName", or {A ProgramName,    <-- OK
{"A ProgramName" , or { A ProgramName,  <-- NOT-OK

The extra space/s would become part of the class name. Not what you want.
If you absolutely must put some space before the comma, use TAB instead.
Those are discarded while parsing the string.

* Pen handling is now specified on the command line, eg:

ekeys pad stylus

The value for pen mode switch in the configuration file is still 999.

Yes, "ekeys" :-) I changed the compile output to that name. The code
tarball will still be named expresskeys though. Doing a web search
revealed it to be rather unique to the Intuos3, while ekeys turned
up music hardware and relatives. But, naturally, feel free to name it
badzilla or VincentVanGogh instead. Program behaviour is not dependent
on the file name.

* Another command line change, to make it run in the background:

ekeys pad stylus -d

It then runs in "daemon" mode. The difference between pushing it
with a terminating & or letting internal code "fork" it is beyond
most peoples interest. I can already hear the snores building up...
But in terms of how I've coded stuff it still matters.

If the program is launched into daemon mode, it writes out another
file in the configuration directory: "". A
process identification (PID) is a unique number, separating the
program from all the other stuff you have running. The number can
be used, for example, to do an easy kill.

I've included a simple shell script (called which reads the and tries to kill whatever process that has the pid,
so do a "ps aux | grep ekeys" beforehand to be sure it's running
(and don't confuse your "grep ekeys" with an actual "ekeys" instance).
Add a line to start ekeys directly after a kill and you have an easy
path when doing config file changes. The pid file is not automatically
deleted by internal code on exit (yet).

* For any programmer out there, or curious user, I've now filled the
code with comments. It had to be done at some point...

11 years agoversion 0.1.0 v0.1.0
Mats Johannesson [Thu, 26 Jun 2008 14:31:46 +0000 (10:31 -0400)]
version 0.1.0
Just internal changes. A massive rewrite to get rid of cruft, and
put my own stink on the whole code structure. Ah yes, I then GPL-d
the result...

11 years agoversion 0.09 v0.09
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.09
Bugfix to handle some weird windows who don't set the "class",
and even their parents lack it (like the "xev" program...). I
won't go further back in a hierarchy, so these weirdos get the
"default" keyset.

Note: Without this fix expresskeys will crash in such cases.

11 years agoversion 0.08 v0.08
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.08
When I was customizing the keyboard shortcuts within Gimp itself
(I wanted Alt + and Alt - to do Next Brush and Previous Brush) it
became obvious that I couldn't assign these brush steppings to any
touch strip, due to my shortsightedness.

Now touch strips can send two keys at a time, just like the pad
buttons: l_touch_up, l_touch_up_plus etc. All of the "_plus" touch
strip definitions are set to 0 (nothing) per default.

Being able to use the touch strips for things like this is really
neat. Look in Gimp's File -> Preferences -> Interface -> Configure
Keyboard Shortcuts -> Context for some good touch strip candidates.

Bugfix: Would crash if _no_ window had focus (except the root win).

11 years agoversion 0.07 v0.07
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.07
Multiple configurations to rule them all... Yes, we now send
keypresses intelligently based on several configurations. I've
included a "default" catch all type, one for Gimp, for Blender
and for XTerm. Observe the spelling! It is case sensitive.

To create a new definition, just copy a full block and alter the
Name and the keycodes. To find the proper name of a program/window
fire up "xprop". It should be included with your X. xprop without
any arguments expects you to then click on the target window.
What comes out is a flood of information in the terminal window
you used to run xprop from. What we're after is something called
WM_CLASS. And within that, only one string. Let me show you:

$ xprop | grep WM_CLASS
WM_CLASS(STRING) = "<unknown>", "Eclipse"

It's the last string we would use, the "Eclipse" part. That is,
if we were doing a definition for this program, an IDE ;-)

You can see above why I use the last part. Program windows do not
always set their "name" (the first string). But they should
absolutely set the "class" they belong to, which often coincides
with the name.

So non-technically, this is how expresskeys works now:

1) Pad button pressed or Touch strips touched.
2) Examine which window is the current active one (has focus).
3) Get the "class" name of the window.
4) Compare that name with an internal list of program names.
5) If a match is found, use those keydefinitions.
6) If no match is found, use a "default" set of definitions.
7) Send the keypress to the specified window.

In order to achieve this functionality I had to change the
"user config area" somewhat. I've done my very best to retain
a simple design, and at the same time keep it compact. But
success is in the eye of the beholder... Cut out example:

/*  key_9 */ <-- A visual reminder of which pad button it is.
50, <-- The actual keycode and a COMMA (don't erase it).

Otherwise all the keys and options from past versions are, almost,
the same. End Version Note Rant.

11 years agoversion 0.06 v0.06
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.06
Comment 2 April 2005: This is default only in Gimp. Basic defaults
are now Arrow-keys Up/Down/Right/Left. End comment.

Touch Strip simple implementation. Default, if turned on, sends plus
(+) and minus (-) key presses based on finger/stylus up/down motion.
This was chosen for Gimp Zoom In/Out functionality. It must be turned
on by setting a value in the "user config area", just as for pen mode
handling. Default is off, don't handle the touch strips.

It turns out that with linuxwacom-0.6.7 (beta is out) this program
works better than ever! The blender "confusion" I talked about in
the previous version note has vanished completely. Also blender
zoom, translation and rotation work flawlessly with the pad buttons
and pen middle button (was half-working in linuxwacom-0.6.6). So the
XTestFakeKeyEvent was no bad choice at all. I'm very pleased :-)

11 years agoversion 0.05 v0.05
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.05
Bugfix. My key scan "case:, if, else, break" flow was somewhat borked.
Ugly function but does the right thing now. There are still issues
with (I believe) the timing of the XTestFakeKeyEvent of the XTest
extension. Using the "u" and "Shift-u" for undo and redo in blender
works, but sometimes blender gets confused. Waiting some seconds and
doing a "slow-push-release" of the key can fix the issue. Ah well,
this simulates keypresses, it's not the real thing... I'll look into
using another extension for the simulation.

11 years agoversion 0.04 v0.04
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.04
Bugfix to handle certain key combinations better. Not perfect though.
Will debug further.

11 years agoversion 0.03 v0.03
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.03
Handle a pen from the pad keys (toggle between absolute and relative mode).
See the new "user config area" for details. Observe: Whatever pen mode
you are in when exiting or killing this program, that's the pen mode
you have... So if wrong, fire up the program again and toggle until it's
the right mode. Default is off, don't handle a pen.

Clearly marked and cleaned up a "user config area" at the very beginning
of the code.

11 years agoversion 0.02 v0.02
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.02
Comment 2 April 2005: These instructions are dated. #define
for the keycodes are not used anymore. End comment.

Added the option to specify an extra key for each pad key.
"#define KEY_xx_PLUS yy". By setting yy of KEY_11_PLUS to 57 you'd get
the famous Ctrl-n ;-). I needed this for undo and redo in blender.

11 years agoversion 0.01 v0.01
Mats Johannesson [Wed, 25 Jun 2008 19:29:09 +0000 (15:29 -0400)]
version 0.01
Original release

Have fun,