PATCH: sticky shift keys: bug fix and more intuitive behaviour

Werner Almesberger (almesber@lrc.di.epfl.ch)
Sat, 15 May 1999 06:38:49 +0200 (MET DST)


[ Copied to linux-kernel, in case there are objections. ]

Hi Linus,

I've just spotted the 2.3 release announcement. There doesn't seem to be
a maintainer for keyboard.c, so I'm sending this directly to you. It's
something from the Linux-7k project, which may also be useful for other
Linux-on-PDA projects:

This patch adds a compile-time option CONFIG_SMART_SLOCK to improve the
behaviour of "sticky" shift/ctrl/alt/etc. keys in virtual terminals. The
current behaviour for the sticky keys is that they change the next key,
and only that one. If CONFIG_SMART_SLOCK is enabled, they still change
the next key, but they also continue changing while held down, i.e. like
shift and friends do in normal (non-"sticky") operation.

Example: when pressing A, pressing (and releasing) Shift, pressing B,
then holding down Shift, pressing C, pressing D, and then releasing
Shift, we get:

Without sticky keys: a b C D
With sticky keys, without CONFIG_SMART_SLOCK: a B C d
With sticky keys, with CONFIG_SMART_SLOCK: a B C D

This is likely to be more intuitive than the current sticky behaviour on
machines which are sometimes operated single-handedly, e.g. PDAs. I've
introduced this extension at the beginning of March in the Linux-7k
project and used it quite extensively on my Psion. I've tested the 2.3.2
version briefly on my PC without noticing any problems.

The patch also adds conflict resolution if a keypress doesn't yield a
valid code. (The second change in do_slock.) This is a bug fix which you
may want to add to 2.2 too. E.g. the keyboard currently locks up if you
use the US layout, make Shift, Ctrl, and Alt "sticky", and then press
each of them. Reason: there is no valid map for Shift+Ctrl+Alt, so all
further keys are ignored.

Furthermore, the patch prevents sticky keys from being used to compose
the boot sequence. (I've added this after noticing that I had a tendency
of trying to "correct" typos in the Ctrl and Alt region by pressing Del
... ;-)

I've made this change a compile-time option because current users of
sticky keys may need the traditional behaviour for some reason (e.g.
special hardware). It would be good if current users of the sticky keys
could comment on the change, so that it may perhaps become the standard
behaviour in the future.

This extension was inspired by the way shift keys work on HP100/200LX
palmtops.

Cheers, Werner

---------------------------------- cut here -----------------------------------

--- linux.orig/Documentation/Configure.help Fri May 14 17:59:54 1999
+++ linux/Documentation/Configure.help Sat May 15 06:05:20 1999
@@ -8111,6 +8111,11 @@

If unsure, say Y.

+Smart "sticky" shifted keys
+CONFIG_SMART_SLOCK
+ Make "sticky" shifted keys more similar to normal, non-sticky keys.
+ This is mainly useful for devices which are operated with one hand.
+
Software generated cursor
CONFIG_SOFTCURSOR
If you say Y here, you'll be able to do lots of nice things with the
--- linux.orig/drivers/char/Config.in Fri May 7 20:05:30 1999
+++ linux/drivers/char/Config.in Sat May 15 05:51:37 1999
@@ -7,6 +7,7 @@
bool 'Virtual terminal' CONFIG_VT
if [ "$CONFIG_VT" = "y" ]; then
bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+ bool 'Smart "sticky" shifted keys' CONFIG_SMART_SLOCK
fi
tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
if [ "$CONFIG_SERIAL" = "y" ]; then
--- linux.orig/drivers/char/keyboard.c Tue May 11 23:37:40 1999
+++ linux/drivers/char/keyboard.c Sat May 15 06:22:12 1999
@@ -278,8 +278,13 @@
u_short keysym;
u_char type;

+#ifndef CONFIG_SMART_SLOCK
/* the XOR below used to be an OR */
int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
+#else
+ int shift_final = (shift_state | kbd->slockstate) ^
+ kbd->lockstate;
+#endif
ushort *key_map = key_maps[shift_final];

if (key_map != NULL) {
@@ -311,6 +316,7 @@
/* we have at least to update shift_state */
#if 1 /* how? two almost equivalent choices follow */
compute_shiftstate();
+ kbd->slockstate = 0; /* play it safe */
#else
keysym = U(plain_map[keycode]);
type = KTYP(keysym);
@@ -472,6 +478,7 @@

static void boot_it(void)
{
+ if (kbd->slockstate & ~shift_state) return;
ctrl_alt_del();
}

@@ -741,7 +748,11 @@
for(j=0; j<BITS_PER_LONG; j++,k++)
if(test_bit(k, key_down)) {
sym = U(plain_map[k]);
+#ifndef CONFIG_SMART_SLOCK
if(KTYP(sym) == KT_SHIFT) {
+#else
+ if(KTYP(sym) == KT_SHIFT || KTYP(sym) == KT_SLOCK) {
+#endif
val = KVAL(sym);
if (val == KVAL(K_CAPSSHIFT))
val = KVAL(K_SHIFT);
@@ -793,9 +804,17 @@

static void do_slock(unsigned char value, char up_flag)
{
+#ifdef CONFIG_SMART_SLOCK
+ do_shift(value,up_flag);
+#endif
if (up_flag || rep)
return;
chg_vc_kbd_slock(kbd, value);
+ /* try to make Alt, oops, AltGr and such work */
+ if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
+ kbd->slockstate = 0;
+ chg_vc_kbd_slock(kbd, value);
+ }
}

/*

-- 
  _________________________________________________________________________
 / Werner Almesberger, DI-ICA,EPFL,CH   werner.almesberger@lrc.di.epfl.ch /
/_IN_R_131__Tel_+41_21_693_6621__Fax_+41_21_693_6610_____________________/

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/