summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2006-03-23 21:54:27 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2006-03-23 21:54:27 +0000
commit2e2523f866435a0a3c6fa35848139715f6b36436 (patch)
tree381d6a94a48e2dfad828c89099323a3775fe9d4f /sys
parente4be1232ac7a784d146103174bad92dc8e1c51bc (diff)
Previous state machine for caps lock would prove ineffective if caps lock
was remapped to a dead key (such as control). Fortunately (?), accounting power key transitions can help reconstructing the exact caps lock key behaviour - this state machine is still flawed, and one can make it go wrong by hitting one of the caps lock and power keys while the other is held, but for now we'll assume people who do this are smart enough to be able to put the state machine in the correct state back, while mere mortals will never do such things anyway. Spotted by Matthias Kilian, ok itojun@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/adb/akbd.c70
-rw-r--r--sys/dev/adb/akbdvar.h5
2 files changed, 53 insertions, 22 deletions
diff --git a/sys/dev/adb/akbd.c b/sys/dev/adb/akbd.c
index 5c7023bfac1..a685b775d90 100644
--- a/sys/dev/adb/akbd.c
+++ b/sys/dev/adb/akbd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: akbd.c,v 1.4 2006/02/12 21:49:08 miod Exp $ */
+/* $OpenBSD: akbd.c,v 1.5 2006/03/23 21:54:26 miod Exp $ */
/* $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $ */
/*
@@ -128,6 +128,7 @@ akbdattach(struct device *parent, struct device *self, void *aux)
sc->handler_id = aa_args->handler_id;
sc->sc_leds = (u_int8_t)0x00; /* initially off */
+ sc->sc_caps = 0;
adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
adbinfo.siDataAreaAddr = (caddr_t)sc;
@@ -453,6 +454,30 @@ akbd_rawrepeat(void *v)
#endif
/*
+ * The ``caps lock'' key is special: since on earlier keyboards, the physical
+ * key stays down when pressed, we will get a notification of the key press,
+ * but not of the key release. Then, when it is pressed again, we will not get
+ * a notification of the key press, but will see the key release.
+ *
+ * This is not exactly true. We see the missing release and press events both
+ * as the release of the power (reset) key.
+ *
+ * To avoid confusing them with real power key presses, we maintain two
+ * states for the caps lock key: logically down (from wscons' point of view),
+ * and ``physically'' down (from the adb messages point of view), to ignore
+ * the power key. But since one may press the power key while the caps lock
+ * is held down, we also have to remember the state of the power key... this
+ * is quite messy.
+ */
+
+/*
+ * Values for caps lock state machine
+ */
+#define CL_DOWN_ADB 0x01
+#define CL_DOWN_LOGICAL 0x02
+#define CL_DOWN_RESET 0x04
+
+/*
* Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
*/
void
@@ -468,10 +493,24 @@ akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
* 0xffff on release, and we ignore it.
*/
if (event->bytes[0] == event->bytes[1] &&
- ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET)
- break;
- akbd_capslockwrapper(sc, event->bytes[0]);
- akbd_capslockwrapper(sc, event->bytes[1]);
+ ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
+ if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET))
+ SET(sc->sc_caps, CL_DOWN_RESET);
+ else {
+ if (ISSET(sc->sc_caps, CL_DOWN_RESET))
+ CLR(sc->sc_caps, CL_DOWN_RESET);
+ else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
+ akbd_input(sc, ISSET(sc->sc_caps,
+ CL_DOWN_LOGICAL) ?
+ ADBK_KEYDOWN(ADBK_CAPSLOCK) :
+ ADBK_KEYUP(ADBK_CAPSLOCK));
+ sc->sc_caps ^= CL_DOWN_LOGICAL;
+ }
+ }
+ } else {
+ akbd_capslockwrapper(sc, event->bytes[0]);
+ akbd_capslockwrapper(sc, event->bytes[1]);
+ }
break;
default:
#ifdef DIAGNOSTIC
@@ -486,22 +525,11 @@ akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
void
akbd_capslockwrapper(struct akbd_softc *sc, int key)
{
- /*
- * Caps lock is special: since on earlier keyboards, the physical
- * key stays down when pressed, we will get a notification of the
- * key press, but not of the key release. Then, when it is pressed
- * again, we will not get a notification of the key press, but will
- * see the key release.
- * For proper wskbd operation, we should report each capslock
- * notification as both events (press and release).
- */
- if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK) {
- akbd_input(sc, ADBK_KEYDOWN(ADBK_CAPSLOCK));
- akbd_input(sc, ADBK_KEYUP(ADBK_CAPSLOCK));
- } else {
- if (key != 0xff)
- akbd_input(sc, key);
- }
+ if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
+ sc->sc_caps ^= CL_DOWN_ADB;
+
+ if (key != 0xff)
+ akbd_input(sc, key);
}
int adb_polledkey;
diff --git a/sys/dev/adb/akbdvar.h b/sys/dev/adb/akbdvar.h
index d3c2db3bb2b..7fefdb98075 100644
--- a/sys/dev/adb/akbdvar.h
+++ b/sys/dev/adb/akbdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: akbdvar.h,v 1.1 2006/01/18 23:21:17 miod Exp $ */
+/* $OpenBSD: akbdvar.h,v 1.2 2006/03/23 21:54:26 miod Exp $ */
/* $NetBSD: akbdvar.h,v 1.4 1999/02/17 14:56:56 tsubai Exp $ */
/*
@@ -46,7 +46,10 @@ struct akbd_softc {
int handler_id; /* type of keyboard */
u_int8_t sc_leds; /* current LED state */
+
+ int sc_caps; /* capslock key state */
struct device *sc_wskbddev;
+
#ifdef WSDISPLAY_COMPAT_RAWKBD
#define MAXKEYS 20
#define REP_DELAY1 400