aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/keyboard.c
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2007-10-19 02:39:12 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-19 14:53:33 -0400
commit41ab4396e19fba338baf28044d3e48385744b930 (patch)
treeb817fc991bfef4b3d84e76f4793e1483ed4d4238 /drivers/char/keyboard.c
parentc18479fe017b9d3b65b7682f2b9e711389441186 (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.c42
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
46extern void ctrl_alt_del(void); 47extern void ctrl_alt_del(void);
47 48
@@ -81,7 +82,8 @@ void compute_shiftstate(void);
81typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, 82typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
82 char up_flag); 83 char up_flag);
83static k_handler_fn K_HANDLERS; 84static k_handler_fn K_HANDLERS;
84static k_handler_fn *k_handler[16] = { K_HANDLERS }; 85k_handler_fn *k_handler[16] = { K_HANDLERS };
86EXPORT_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;
160static int sysrq_alt; 162static int sysrq_alt;
161 163
162/* 164/*
165 * Notifier list for console keyboard events
166 */
167static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
168
169int register_keyboard_notifier(struct notifier_block *nb)
170{
171 return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
172}
173EXPORT_SYMBOL_GPL(register_keyboard_notifier);
174
175int unregister_keyboard_notifier(struct notifier_block *nb)
176{
177 return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
178}
179EXPORT_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, &param) == NOTIFY_STOP || !key_map) {
1244 atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, &param);
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, &param) == 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, &param) == 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, &param);
1290
1261 if (type != KT_SLOCK) 1291 if (type != KT_SLOCK)
1262 kbd->slockstate = 0; 1292 kbd->slockstate = 0;
1263} 1293}