Some external modules like Speakup need to use the PC keyboard to control
them and also need to get keyboard feedback (caps lock status, etc.)
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.
Signed-off-by: Samuel Thibault <[email protected]>
---
Hi,
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).
Samuel
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 2ce0af1..55646de 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,6 +41,7 @@
#include <linux/sysrq.h>
#include <linux/input.h>
#include <linux/reboot.h>
+#include <linux/notifier.h>
extern void ctrl_alt_del(void);
@@ -80,7 +81,8 @@
typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
char up_flag);
static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
+k_handler_fn *k_handler[16] = { K_HANDLERS };
+EXPORT_SYMBOL(k_handler);
#define FN_HANDLERS\
fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\
@@ -159,6 +161,23 @@
static int sysrq_alt;
/*
+ * Notifier list for console keyboard events
+ */
+static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
+
+int register_keyboard_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL(register_keyboard_notifier);
+
+int unregister_keyboard_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL(unregister_keyboard_notifier);
+
+/*
* Translation of scancodes to keycodes. We set them on only the first
* keyboard in the list that accepts the scancode and keycode.
* Explanation for not choosing the first attached keyboard anymore:
@@ -1119,6 +1138,7 @@
unsigned char type, raw_mode;
struct tty_struct *tty;
int shift_final;
+ struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
tty = vc->vc_tty;
@@ -1206,10 +1226,11 @@
return;
}
- shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+ param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
key_map = key_maps[shift_final];
- if (!key_map) {
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) {
+ atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, ¶m);
compute_shiftstate();
kbd->slockstate = 0;
return;
@@ -1226,6 +1247,9 @@
type = KTYP(keysym);
if (type < 0xf0) {
+ param.value = keysym;
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, ¶m) == NOTIFY_STOP)
+ return;
if (down && !raw_mode)
to_utf8(vc, keysym);
return;
@@ -1233,9 +1257,6 @@
type -= 0xf0;
- if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
- return;
-
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
@@ -1244,9 +1265,18 @@
keysym = key_map[keycode];
}
}
+ param.value = keysym;
+
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, ¶m) == NOTIFY_STOP)
+ return;
+
+ if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+ return;
(*k_handler[type])(vc, keysym & 0xff, !down);
+ atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m);
+
if (type != KT_SLOCK)
kbd->slockstate = 0;
}
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -2,6 +2,7 @@
#define __LINUX_KEYBOARD_H
#include <linux/wait.h>
+#include <linux/notifier.h>
#define KG_SHIFT 0
#define KG_CTRL 2
@@ -27,6 +28,16 @@
extern const int max_vals[];
extern unsigned short *key_maps[MAX_NR_KEYMAPS];
extern unsigned short plain_map[NR_KEYS];
+
+struct keyboard_notifier_param {
+ struct vc_data *vc; /* VC on which the keyboard press was done */
+ int down; /* Pressure of the key? */
+ int shift; /* Current shift mask */
+ unsigned int value; /* keycode, unicode value or keysym */
+};
+
+extern int register_keyboard_notifier(struct notifier_block *nb);
+extern int unregister_keyboard_notifier(struct notifier_block *nb);
#endif
#define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -231,5 +231,14 @@
#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */
#define PM_POST_SUSPEND 0x0004 /* Suspend finished */
+/* Console keyboard events.
+ * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
+ * KBD_KEYSYM. */
+#define KBD_KEYCODE 0x0001 /* Keyboard keycode, called before any other */
+#define KBD_UNBOUND_KEYCODE 0x0002 /* Keyboard keycode which is not bound to any other */
+#define KBD_UNICODE 0x0003 /* Keyboard unicode */
+#define KBD_KEYSYM 0x0004 /* Keyboard keysym */
+#define KBD_POST_KEYSYM 0x0005 /* Called after keyboard keysym interpretation */
+
#endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */
On Tue, 21 Aug 2007 02:57:18 +0200
Samuel Thibault <[email protected]> wrote:
> Some external modules like Speakup need to use the PC keyboard to control
> them and also need to get keyboard feedback (caps lock status, etc.)
>
> This adds a keyboard notifier that such modules can use to get the keyboard
> events and possibly eat them, at several stages:
Adding hooks for non-merged modules is considered sinful. Making these new
exports EXPORT_SYMBOL_GPL might ease the pain.
Is there any prospect of getting at least one of these "external modules
like Speakup" merged into mainline?
Hi,
Andrew Morton, le Tue 21 Aug 2007 13:02:33 -0700, a ?crit :
> On Tue, 21 Aug 2007 02:57:18 +0200
> Samuel Thibault <[email protected]> wrote:
>
> > Some external modules like Speakup need to use the PC keyboard to control
> > them and also need to get keyboard feedback (caps lock status, etc.)
> >
> > This adds a keyboard notifier that such modules can use to get the keyboard
> > events and possibly eat them, at several stages:
>
> Adding hooks for non-merged modules is considered sinful. Making these new
> exports EXPORT_SYMBOL_GPL might ease the pain.
That should be fine.
I'll soon propose a notifier for the console writes too, same story.
> Is there any prospect of getting at least one of these "external modules
> like Speakup" merged into mainline?
I'm working on it. The problem is that the current code quality is
still far from mainline requirements (though improving over time). This
hook (and the other one I'll post) is a step toward merging. If these
hooks can go mainline, then great, that will make life easier for the
few distributions that want to provide speakup as modules. If they
remain in -mm for some time and people don't complain, well that's good
too: at least we know how speakup may hook into the kernel when it gets
merged.
Working on braille support is also in my plan BTW.
Samuel
On Aug 21 2007 02:57, Samuel Thibault wrote:
>
>Some external modules like Speakup need to use the PC keyboard to control
>them and also need to get keyboard feedback (caps lock status, etc.)
>
>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.
They can use the raw xlation for that. The "showkeys" utility and Xorg are
likely to do that. (In fact, there is a helping sysrq called Unraw in case
there are problems.)
>- 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.)
For all these, I think new xlats should be added that have the desired
behavior.
>+ int shift; /* Current shift mask */
>+ unsigned int value; /* keycode, unicode value or keysym */
>+};
>+
>+extern int register_keyboard_notifier(struct notifier_block *nb);
>+extern int unregister_keyboard_notifier(struct notifier_block *nb);
> #endif
>
Hi,
Jan Engelhardt, le Tue 21 Aug 2007 22:42:24 +0200, a ?crit :
> >- keycodes: even before translation into keysym.
>
> They can use the raw xlation for that.
For userland, yes. This is for kernel modules.
Samuel
On Tue, Aug 21, 2007 at 10:22:51PM +0200, Samuel Thibault wrote:
> Hi,
>
> Andrew Morton, le Tue 21 Aug 2007 13:02:33 -0700, a écrit :
> > On Tue, 21 Aug 2007 02:57:18 +0200
> > Samuel Thibault <[email protected]> wrote:
> >
> > > Some external modules like Speakup need to use the PC keyboard to control
> > > them and also need to get keyboard feedback (caps lock status, etc.)
> > >
> > > This adds a keyboard notifier that such modules can use to get the keyboard
> > > events and possibly eat them, at several stages:
> >
> > Adding hooks for non-merged modules is considered sinful. Making these new
> > exports EXPORT_SYMBOL_GPL might ease the pain.
>
> That should be fine.
>
> I'll soon propose a notifier for the console writes too, same story.
>
> > Is there any prospect of getting at least one of these "external modules
> > like Speakup" merged into mainline?
>
> I'm working on it. The problem is that the current code quality is
> still far from mainline requirements (though improving over time). This
> hook (and the other one I'll post) is a step toward merging. If these
> hooks can go mainline, then great, that will make life easier for the
> few distributions that want to provide speakup as modules.
How long does it take you for getting the first users submitted for
review? If you are working on it it should be in the order of "a few
months", and earlier merging would anyway gain you only one or two
kernel releases.
> If they
> remain in -mm for some time and people don't complain, well that's good
> too: at least we know how speakup may hook into the kernel when it gets
> merged.
>...
Without any users it's dead code noone uses, and complaints will most
likely not occur until you submit the first users for review...
> Samuel
cu
Adrian
BTW: Are these the speakup patches that were in -ac five years ago?
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
Hi,
Adrian Bunk, le Sat 25 Aug 2007 03:07:04 +0200, a ?crit :
> > If they
> > remain in -mm for some time and people don't complain, well that's good
> > too: at least we know how speakup may hook into the kernel when it gets
> > merged.
> >...
>
> Without any users it's dead code noone uses,
Not so much dead: the notify chain will get called anyway, taking
spinlocks, etc. even if nothing is really called. And people can see
the patches and complain if they think they're bad.
> BTW: Are these the speakup patches that were in -ac five years ago?
No, they are some rework of the way Speakup glues into the kernel.
Samuel
On Tue 2007-08-21 22:49:51, Samuel Thibault wrote:
> Hi,
>
> Jan Engelhardt, le Tue 21 Aug 2007 22:42:24 +0200, a ?crit :
> > >- keycodes: even before translation into keysym.
> >
> > They can use the raw xlation for that.
>
> For userland, yes. This is for kernel modules.
And should speakup be a kernel module? Why?
It looks doable from userland:
/dev/vcsa tells you what is on screen. Maybe you need to add poll()
support?
/dev/input allows you to get keys pressed.
What is missing? Yes, you may want to do a small kernel module to read
kernel bootup messages. Anything more?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Pavel Machek, le Thu 12 Jul 2007 19:19:32 +0000, a ?crit :
> On Tue 2007-08-21 22:49:51, Samuel Thibault wrote:
> > Hi,
> >
> > Jan Engelhardt, le Tue 21 Aug 2007 22:42:24 +0200, a ?crit :
> > > >- keycodes: even before translation into keysym.
> > >
> > > They can use the raw xlation for that.
> >
> > For userland, yes. This is for kernel modules.
>
> And should speakup be a kernel module? Why?
Because userland only begins quite late in the boot process, and
userland may hang.
> What is missing? Yes, you may want to do a small kernel module to read
> kernel bootup messages.
That's what it's all about.
Samuel
> > > > They can use the raw xlation for that.
> > >
> > > For userland, yes. This is for kernel modules.
> >
> > And should speakup be a kernel module? Why?
>
> Because userland only begins quite late in the boot process, and
> userland may hang.
Initrd means userland is started very early on most machines these
days, and kernel may hang, too.
> > What is missing? Yes, you may want to do a small kernel module to read
> > kernel bootup messages.
>
> That's what it's all about.
But this small module should not need keyboard leds support, as those are not used during
boot. If all you want is to read kernel bootup messages, you should
just register a special console. Actually serial console should do.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi,
Pavel Machek, le Sat 01 Sep 2007 12:32:58 +0000, a ?crit :
> > > > > They can use the raw xlation for that.
> > > >
> > > > For userland, yes. This is for kernel modules.
> > >
> > > And should speakup be a kernel module? Why?
> >
> > Because userland only begins quite late in the boot process, and
> > userland may hang.
>
> Initrd means userland is started very early on most machines these
> days, and kernel may hang, too.
Very early is not so early, and loading initrd itself may actually fail.
The kernel may indeed hang, but there are more chances to get some
messages before the hang. Don't _you_ have a VGA screen for getting
earliest failure messages from the kernel?
> > > What is missing? Yes, you may want to do a small kernel module to read
> > > kernel bootup messages.
> >
> > That's what it's all about.
>
> But this small module should not need keyboard leds support, as those are not used during
> boot. If all you want is to read kernel bootup messages, you should
> just register a special console. Actually serial console should do.
The problem is that using both a tool for early message and for later
messages is not particularly handy, that's why speakup is actually
used by people both for boot time and afterwards. People are indeed
considering moving speakup into userland, but some people still _need_
speakup in the kernel for their everyday work. Having two versions of
speakup (user and kernel) is just asking for more maintain work, and it
happens that speakup already doesn't have many people involved...
Samuel
Hi!
> > > Because userland only begins quite late in the boot process, and
> > > userland may hang.
> >
> > Initrd means userland is started very early on most machines these
> > days, and kernel may hang, too.
>
> Very early is not so early, and loading initrd itself may actually fail.
> The kernel may indeed hang, but there are more chances to get some
> messages before the hang. Don't _you_ have a VGA screen for getting
> earliest failure messages from the kernel?
No. I'm using framebuffer, that's initialized quite late in boot
process. Plus many users just use bootsplash. I do use vga mode for
heavy debugging, but that's quite unusual.
So... you actually have speech-enabled grub/lilo/something?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi,
Pavel Machek, le Sat 01 Sep 2007 17:23:02 +0000, a ?crit :
> Hi!
>
> > > > Because userland only begins quite late in the boot process, and
> > > > userland may hang.
> > >
> > > Initrd means userland is started very early on most machines these
> > > days, and kernel may hang, too.
> >
> > Very early is not so early, and loading initrd itself may actually fail.
> > The kernel may indeed hang, but there are more chances to get some
> > messages before the hang. Don't _you_ have a VGA screen for getting
> > earliest failure messages from the kernel?
>
> No. I'm using framebuffer, that's initialized quite late in boot
> process. Plus many users just use bootsplash. I do use vga mode for
> heavy debugging, but that's quite unusual.
But that's what some people do for their work, so they need it.
> So... you actually have speech-enabled grub/lilo/something?
That's in project too (and there's no reason it shouldn't be done).
Samuel
Hi!
> > > Very early is not so early, and loading initrd itself may actually fail.
> > > The kernel may indeed hang, but there are more chances to get some
> > > messages before the hang. Don't _you_ have a VGA screen for getting
> > > earliest failure messages from the kernel?
> >
> > No. I'm using framebuffer, that's initialized quite late in boot
> > process. Plus many users just use bootsplash. I do use vga mode for
> > heavy debugging, but that's quite unusual.
>
> But that's what some people do for their work, so they need it.
How many such users are out there?
> > So... you actually have speech-enabled grub/lilo/something?
>
> That's in project too (and there's no reason it shouldn't be done).
I'd say kernel debugging is hard without accessible bootloader, so I'd
hope number of such users is very low.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Pavel Machek, le Sat 01 Sep 2007 18:18:45 +0000, a ?crit :
> > > > Very early is not so early, and loading initrd itself may actually fail.
> > > > The kernel may indeed hang, but there are more chances to get some
> > > > messages before the hang. Don't _you_ have a VGA screen for getting
> > > > earliest failure messages from the kernel?
> > >
> > > No. I'm using framebuffer, that's initialized quite late in boot
> > > process. Plus many users just use bootsplash. I do use vga mode for
> > > heavy debugging, but that's quite unusual.
> >
> > But that's what some people do for their work, so they need it.
>
> How many such users are out there?
You know that it's a question that just can't be answered. There are
such people, and their employment depend on this.
> > > So... you actually have speech-enabled grub/lilo/something?
> >
> > That's in project too (and there's no reason it shouldn't be done).
>
> I'd say kernel debugging is hard without accessible bootloader
A bootloader with only two entries is not so difficult to use blindly.
Samuel