diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2007-10-19 02:39:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:33 -0400 |
commit | 41ab4396e19fba338baf28044d3e48385744b930 (patch) | |
tree | b817fc991bfef4b3d84e76f4793e1483ed4d4238 /drivers/char/keyboard.c | |
parent | c18479fe017b9d3b65b7682f2b9e711389441186 (diff) |
Console keyboard events and accessibility
Some blind people use a kernel engine called Speakup which uses hardware
synthesis to speak what gets displayed on the screen. They use the
PC keyboard to control this engine (start/stop, accelerate, ...) and
also need to get keyboard feedback (to make sure to know what they are
typing, the caps lock status, etc.)
Up to now, the way it was done was very ugly. Below is a patch to add a
notifier list for permitting a far better implementation, see ChangeLog
above for details.
You may wonder why this can't be done at the input layer. The problem
is that what people want to monitor is the console keyboard, i.e. all
input keyboards that got attached to the console, and with the currently
active keymap (i.e. keysyms, not only keycodes).
This adds a keyboard notifier that such modules can use to get the keyboard
events and possibly eat them, at several stages:
- keycodes: even before translation into keysym.
- unbound keycodes: when no keysym is bound.
- unicode: when the keycode would get translated into a unicode character.
- keysym: when the keycode would get translated into a keysym.
- post_keysym: after the keysym got interpreted, so as to see the result
(caps lock, etc.)
This also provides access to k_handler so as to permit simulation of
keypresses.
[akpm@linux-foundation.org: various fixes]
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r-- | drivers/char/keyboard.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 212276affa1f..d54f4a3ae340 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/sysrq.h> | 42 | #include <linux/sysrq.h> |
43 | #include <linux/input.h> | 43 | #include <linux/input.h> |
44 | #include <linux/reboot.h> | 44 | #include <linux/reboot.h> |
45 | #include <linux/notifier.h> | ||
45 | 46 | ||
46 | extern void ctrl_alt_del(void); | 47 | extern void ctrl_alt_del(void); |
47 | 48 | ||
@@ -81,7 +82,8 @@ void compute_shiftstate(void); | |||
81 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | 82 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, |
82 | char up_flag); | 83 | char up_flag); |
83 | static k_handler_fn K_HANDLERS; | 84 | static k_handler_fn K_HANDLERS; |
84 | static k_handler_fn *k_handler[16] = { K_HANDLERS }; | 85 | k_handler_fn *k_handler[16] = { K_HANDLERS }; |
86 | EXPORT_SYMBOL_GPL(k_handler); | ||
85 | 87 | ||
86 | #define FN_HANDLERS\ | 88 | #define FN_HANDLERS\ |
87 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ | 89 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ |
@@ -160,6 +162,23 @@ static int sysrq_alt_use; | |||
160 | static int sysrq_alt; | 162 | static int sysrq_alt; |
161 | 163 | ||
162 | /* | 164 | /* |
165 | * Notifier list for console keyboard events | ||
166 | */ | ||
167 | static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list); | ||
168 | |||
169 | int register_keyboard_notifier(struct notifier_block *nb) | ||
170 | { | ||
171 | return atomic_notifier_chain_register(&keyboard_notifier_list, nb); | ||
172 | } | ||
173 | EXPORT_SYMBOL_GPL(register_keyboard_notifier); | ||
174 | |||
175 | int unregister_keyboard_notifier(struct notifier_block *nb) | ||
176 | { | ||
177 | return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb); | ||
178 | } | ||
179 | EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); | ||
180 | |||
181 | /* | ||
163 | * Translation of scancodes to keycodes. We set them on only the first | 182 | * Translation of scancodes to keycodes. We set them on only the first |
164 | * keyboard in the list that accepts the scancode and keycode. | 183 | * keyboard in the list that accepts the scancode and keycode. |
165 | * Explanation for not choosing the first attached keyboard anymore: | 184 | * Explanation for not choosing the first attached keyboard anymore: |
@@ -1130,6 +1149,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1130 | unsigned char type, raw_mode; | 1149 | unsigned char type, raw_mode; |
1131 | struct tty_struct *tty; | 1150 | struct tty_struct *tty; |
1132 | int shift_final; | 1151 | int shift_final; |
1152 | struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; | ||
1133 | 1153 | ||
1134 | tty = vc->vc_tty; | 1154 | tty = vc->vc_tty; |
1135 | 1155 | ||
@@ -1217,10 +1237,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1217 | return; | 1237 | return; |
1218 | } | 1238 | } |
1219 | 1239 | ||
1220 | shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; | 1240 | param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; |
1221 | key_map = key_maps[shift_final]; | 1241 | key_map = key_maps[shift_final]; |
1222 | 1242 | ||
1223 | if (!key_map) { | 1243 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) { |
1244 | atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, ¶m); | ||
1224 | compute_shiftstate(); | 1245 | compute_shiftstate(); |
1225 | kbd->slockstate = 0; | 1246 | kbd->slockstate = 0; |
1226 | return; | 1247 | return; |
@@ -1237,6 +1258,9 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1237 | type = KTYP(keysym); | 1258 | type = KTYP(keysym); |
1238 | 1259 | ||
1239 | if (type < 0xf0) { | 1260 | if (type < 0xf0) { |
1261 | param.value = keysym; | ||
1262 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, ¶m) == NOTIFY_STOP) | ||
1263 | return; | ||
1240 | if (down && !raw_mode) | 1264 | if (down && !raw_mode) |
1241 | to_utf8(vc, keysym); | 1265 | to_utf8(vc, keysym); |
1242 | return; | 1266 | return; |
@@ -1244,9 +1268,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1244 | 1268 | ||
1245 | type -= 0xf0; | 1269 | type -= 0xf0; |
1246 | 1270 | ||
1247 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) | ||
1248 | return; | ||
1249 | |||
1250 | if (type == KT_LETTER) { | 1271 | if (type == KT_LETTER) { |
1251 | type = KT_LATIN; | 1272 | type = KT_LATIN; |
1252 | if (vc_kbd_led(kbd, VC_CAPSLOCK)) { | 1273 | if (vc_kbd_led(kbd, VC_CAPSLOCK)) { |
@@ -1255,9 +1276,18 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1255 | keysym = key_map[keycode]; | 1276 | keysym = key_map[keycode]; |
1256 | } | 1277 | } |
1257 | } | 1278 | } |
1279 | param.value = keysym; | ||
1280 | |||
1281 | if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, ¶m) == NOTIFY_STOP) | ||
1282 | return; | ||
1283 | |||
1284 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) | ||
1285 | return; | ||
1258 | 1286 | ||
1259 | (*k_handler[type])(vc, keysym & 0xff, !down); | 1287 | (*k_handler[type])(vc, keysym & 0xff, !down); |
1260 | 1288 | ||
1289 | atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); | ||
1290 | |||
1261 | if (type != KT_SLOCK) | 1291 | if (type != KT_SLOCK) |
1262 | kbd->slockstate = 0; | 1292 | kbd->slockstate = 0; |
1263 | } | 1293 | } |