Discussion:
Caps Lock detection
Albrecht Schlosser
2013-04-06 00:16:04 UTC
Permalink
Correction:

On 06.04.2013 02:10, Albrecht Schlosser wrote:

[... about compiling and running program #1]
...
event = FL_KEYDOWN ... caps lock 9
event = FL_KEYUP ... caps lock 10
event = FL_KEYDOWN ... caps lock 11
event = FL_KEYUP ... caps unlock 12
You can see (or guess) that the CAPS LOCK state is updated *before*
the handle message is called on FL_KEYDOWN events, if CAPS LOCK is
being turned ON, but *after* the FL_KEYDOWN event, if it is turned
OFF. That's why the program shows the "caps unlock" message only on
FL_KEYDOWN events.
The last line should read: "FL_KEYUP events.", of course.

Albrecht
Howard Rubin
2013-04-05 20:02:40 UTC
Permalink
Thanks for the quick reply. Here's what I have now. It's reporting the
opposite of of the Caps Lock state. In other words, (Fl::event_state() &
FL_CAPS_LOCK) is zero when Caps Lock is on, and nonzero when it's off.

Is that what you meant in your last message?

I'm less than enthusiastic about displaying the 'Caps Lock is on'
message when the test in the code says it's off.

Is there really no alternative?

Thanks,
Howard Rubin

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Secret_Input.H>
#include <iostream>

class myWindow : public Fl_Window {
public:
myWindow(int x, int y, const char* l) : Fl_Window(x, y, l) { }

virtual int handle(int event) {
if (event== FL_SHORTCUT && Fl::event_key() == FL_Caps_Lock) {
static int n = 0;
if (Fl::event_state() & FL_CAPS_LOCK) {
std::cout << "caps lock" << " " << ++n << std::endl;
} else {
std::cout << "caps unlock" << " " << ++n << std::endl;
}
return 1;
} else
return Fl_Window::handle(event);
}
};

int main(int argc, char* argv[]) {
myWindow* win = new myWindow(300, 200, "");

new Fl_Secret_Input(20, 20, 100, 15, "");

win->end();
win->show();

return Fl::run();
}
Greg Ercolano
2013-04-05 16:49:18 UTC
Permalink
I need to immediately detect when Caps Lock is turned on or off in our
login screen, so I can alert the user. Neither of the approaches I've
tried works.
Do you see the same problem when using the fltk
test/keyboard application?
Greg Ercolano
2013-04-06 06:39:28 UTC
Permalink
It seems, that caps-lock handling starts to work after key handling and
I think there might be other problems, like switching caps lock, when
there is another window in focus. I think a better way is, to use a
timer and to check for change of state e.g. all 0.25 seconds. For humans
this is fast enought to appear as "instantly".
Perhaps this problem is perceived in test/keyboard as well
by the 'LOCK' state flag staying set while the caps lock key
is toggled repeatedly.

I found it updates correctly if I just resize the window,
so I was thinking the same thing, Fl::event_state() might
not have valid state info for the caps lock key at that
point in time in the handle() function, and that indeed
an fltk timer would probably be needed to get the correct
state info shown reliably.
Edzard Egberts
2013-04-05 17:51:55 UTC
Permalink
Post by Howard Rubin
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Secret_Input.H>
#include <iostream>
class myWindow : public Fl_Window {
myWindow(int x, int y, const char* l) : Fl_Window(x, y, l) { }
virtual int handle(int event) {
if (event== FL_SHORTCUT)
{
Post by Howard Rubin
static int n = 0;
if (Fl::event_state() & FL_CAPS_LOCK) {
std::cout << "caps lock" << " " << ++n << std::endl;
} else {
std::cout << "caps unlock" << " " << ++n << std::endl;
}
return 1;
}
else
Post by Howard Rubin
return Fl_Window::handle(event);
}
};
int main(int argc, char* argv[]) {
myWindow* win = new myWindow(300, 200, "");
new Fl_SecretInput(20, 20, 100, 15, "");
Post by Howard Rubin
win->end();
win->show();
return Fl::run();
}
Edzard Egberts
2013-04-05 18:43:13 UTC
Permalink
Post by Edzard Egberts
Post by Howard Rubin
virtual int handle(int event) {
if (event== FL_SHORTCUT)
if (event== FL_SHORTCUT && Fl::event_key()== 65509)

Without check of key every shortcut signals caps lock, thats wrong. And
it seems, the real state establishs after the events had run through,
but because of binary state it's no problem.
Edzard Egberts
2013-04-06 05:58:22 UTC
Permalink
Post by Howard Rubin
Thanks for the quick reply. Here's what I have now. It's reporting the
opposite of of the Caps Lock state. In other words, (Fl::event_state() &
FL_CAPS_LOCK) is zero when Caps Lock is on, and nonzero when it's off.
Is that what you meant in your last message?
Yes, it shows every time the wrong of of two states, so you know for
sure the right one - it's !state.
Post by Howard Rubin
I'm less than enthusiastic about displaying the 'Caps Lock is on'
message when the test in the code says it's off.
Is there really no alternative?
It seems, that caps-lock handling starts to work after key handling and
I think there might be other problems, like switching caps lock, when
there is another window in focus. I think a better way is, to use a
timer and to check for change of state e.g. all 0.25 seconds. For humans
this is fast enought to appear as "instantly".
Albrecht Schlosser
2013-04-06 00:10:57 UTC
Permalink
Post by Howard Rubin
Thanks for the quick reply. Here's what I have now. It's reporting the
opposite of of the Caps Lock state. In other words, (Fl::event_state() &
FL_CAPS_LOCK) is zero when Caps Lock is on, and nonzero when it's off.
Is that what you meant in your last message?
I'm less than enthusiastic about displaying the 'Caps Lock is on'
message when the test in the code says it's off.
Is there really no alternative?
Well, there should be a better way, but it looks like you found a bug
or at least some inconsistency. I'll post two different modified test
programs (derived from yours) that do unfortunately show inconsistent
behavior on Windows and Linux on my test systems, i.e. Windows 7 and
Linux Ubuntu 12.04 an a Virtualbox VM. Maybe someone can test it on
a real Linux box and on Mac OS X ?

Howard, what's your environment ?

Here's #1 that shows more events and gives a clue how to handle the
key, and it works well on Windows, but doesn't on my Linux VM:

$ cat capslock.cxx
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Secret_Input.H>
#include <FL/names.h>
#include <iostream>

class myWindow : public Fl_Window {
public:
myWindow(int x, int y, const char* l) : Fl_Window(x, y, l) { }

virtual int handle(int event) {
if (event == FL_FOCUS) {
std::cout << "event = " << fl_eventnames[event] << " ... ";
if (Fl::event_state() & FL_CAPS_LOCK)
std::cout << "WARNING: CAPS LOCK is set";
std::cout << std::endl;
return 1;
}

if ((event == FL_SHORTCUT || event == FL_KEYDOWN || event ==
FL_KEYUP)
&& Fl::event_key() == FL_Caps_Lock) {
std::cout << "event = " << fl_eventnames[event] << " ... ";
static int n = 0;
if (Fl::event_state() & FL_CAPS_LOCK) {
std::cout << "caps lock" << " " << ++n << std::endl;
} else {
std::cout << "caps unlock" << " " << ++n << std::endl
<< std::endl;
}
return 1;
} else
return Fl_Window::handle(event);
}
};

int main(int argc, char* argv[]) {
myWindow* win = new myWindow(300, 200, "");

new Fl_Secret_Input(20, 20, 100, 20, "");

new Fl_Button(20, 120, 100, 20, "Test");

win->end();
win->show();

return Fl::run();
}
// end of file

Compilation and output on Windows:

$ fltk-config --compile capslock.cxx && ./capslock.exe
g++ -I/fltk/svn/fltk-1.3 -I/fltk/svn/fltk-1.3/png
-I/fltk/svn/fltk-1.3/zlib -I/fltk/svn/fltk-1.3/jpeg -mwindows -DWIN32
-DUSE_OPENGL32 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -o 'capslock'
'capslock.cxx' -mwindows -static-libgcc -static-libstdc++
/fltk/svn/fltk-1.3/lib/libfltk.a -lole32 -luuid -lcomctl32
event = FL_FOCUS ...
event = FL_KEYDOWN ... caps lock 1
event = FL_KEYUP ... caps lock 2
event = FL_KEYDOWN ... caps lock 3
event = FL_KEYUP ... caps unlock 4

event = FL_KEYDOWN ... caps lock 5
event = FL_KEYUP ... caps lock 6
event = FL_KEYDOWN ... caps lock 7
event = FL_KEYUP ... caps unlock 8

event = FL_KEYDOWN ... caps lock 9
event = FL_KEYUP ... caps lock 10
event = FL_KEYDOWN ... caps lock 11
event = FL_KEYUP ... caps unlock 12

You can see (or guess) that the CAPS LOCK state is updated *before*
the handle message is called on FL_KEYDOWN events, if CAPS LOCK is
being turned ON, but *after* the FL_KEYDOWN event, if it is turned
OFF. That's why the program shows the "caps unlock" message only on
FL_KEYDOWN events.

Obviously it's a little difficult to get the state of these toggle
keys in a platform independent way, and hence this doesn't seem to
work well on my Linux VM:

$ fltk-config --compile capslock.cxx && ./capslock
g++ -I/home/albrecht/svn/fltk-1.3 -I/home/albrecht/svn/fltk-1.3/png
-I/home/albrecht/svn/fltk-1.3/zlib -I/home/albrecht/svn/fltk-1.3/jpeg
-I/usr/include/freetype2 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
-D_FILE_OFFSET_BITS=64 -D_THREAD_SAFE -D_REENTRANT -o 'capslock'
'capslock.cxx' -static-libgcc -static-libstdc++
/home/albrecht/svn/fltk-1.3/lib/libfltk.a -lXext -lfontconfig -lXinerama
-lpthread -ldl -lm -lX11
event = FL_FOCUS ...
event = FL_KEYDOWN ... caps unlock 1

event = FL_KEYDOWN ... caps lock 2
event = FL_KEYUP ... caps lock 3
event = FL_KEYDOWN ... caps unlock 4

event = FL_KEYDOWN ... caps lock 5
event = FL_KEYDOWN ... caps lock 6
event = FL_KEYUP ... caps lock 7
event = FL_KEYDOWN ... caps lock 8
event = FL_KEYUP ... caps lock 9
event = FL_KEYDOWN ... caps unlock 10

event = FL_KEYUP ... caps lock 11
event = FL_KEYDOWN ... caps lock 12
event = FL_KEYUP ... caps lock 13
event = FL_KEYDOWN ... caps unlock 14

event = FL_KEYDOWN ... caps lock 15
event = FL_KEYUP ... caps lock 16
event = FL_KEYDOWN ... caps unlock 17

event = FL_KEYDOWN ... caps lock 18
event = FL_KEYDOWN ... caps lock 19
event = FL_KEYUP ... caps lock 20
event = FL_KEYDOWN ... caps lock 21
event = FL_KEYUP ... caps lock 22
event = FL_KEYDOWN ... caps unlock 23

event = FL_KEYUP ... caps lock 24
event = FL_KEYDOWN ... caps lock 25
event = FL_KEYUP ... caps lock 26
event = FL_KEYDOWN ... caps unlock 27

event = FL_KEYDOWN ... caps lock 28
event = FL_KEYUP ... caps lock 29
event = FL_FOCUS ...
event = FL_KEYDOWN ... caps unlock 30

event = FL_KEYUP ... caps lock 31


You can see an irregular pattern of messages, although I did
exactly the same: press CAPS LOCK and release it regularly,
with a small delay between two press/release cycles.


Greg, regarding your question about test/keyboard: I can also see
different (and wrong) behavior with ALL OF shift/ctrl/alt/caps-lock
keys on Linux: if I only press and release one of these modifier
keys, then the yellow light on this key stays ON (on Linux), but
goes OFF on Windows. Can anybody confirm this ? Is it maybe something
on my Linux VM ?

Note that the key flags mentioned above *are* turned off as expected
whenever a text inserting key is pressed, as opposed to modifier keys
only.


Now to my 2nd modified test. This works so far okay on Win 7, but
does not at all give the expected results on my Ubuntu VM:

$ cat capslock2.cxx
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Secret_Input.H>
#include <FL/names.h>
#include <iostream>

class myWindow : public Fl_Window {
public:
myWindow(int x, int y, const char* l) : Fl_Window(x, y, l) { }

virtual int handle(int event) {
if (event == FL_FOCUS) {
std::cout << "event = " << fl_eventnames[event] << " ... ";
if (Fl::event_state() & FL_CAPS_LOCK)
std::cout << "WARNING: CAPS LOCK is set";
std::cout << std::endl;
return 1;
}

if ((event == FL_KEYUP)
&& Fl::event_key() == FL_Caps_Lock) {
std::cout << "event = " << fl_eventnames[event] << " ... ";
static int n = 0;
if (Fl::event_state() & FL_CAPS_LOCK) {
std::cout << "caps lock" << " " << ++n << std::endl;
} else {
std::cout << "caps unlock" << " " << ++n << std::endl
<< std::endl;
}
return 1;
} else
return Fl_Window::handle(event);
}
};

int main(int argc, char* argv[]) {
myWindow* win = new myWindow(300, 200, "");

new Fl_Secret_Input(20, 20, 100, 20, "");

new Fl_Button(20, 120, 100, 20, "Test");

win->end();
win->show();

return Fl::run();
}

This one is simplified so that it does only outputs the key state
on FL_KEYUP events, and it looks like this on Windows:

$ fltk-config --compile capslock2.cxx && ./capslock2.exe
g++ -I/fltk/svn/fltk-1.3 -I/fltk/svn/fltk-1.3/png
-I/fltk/svn/fltk-1.3/zlib -I/fltk/svn/fltk-1.3/jpeg -mwindows -DWIN32
-DUSE_OPENGL32 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -o 'capslock2'
'capslock2.cxx' -mwindows -static-libgcc -static-libstdc++
/fltk/svn/fltk-1.3/lib/libfltk.a -lole32 -luuid -lcomctl32
event = FL_FOCUS ...
event = FL_KEYUP ... caps lock 1
event = FL_KEYUP ... caps unlock 2

event = FL_KEYUP ... caps lock 3
event = FL_KEYUP ... caps unlock 4

event = FL_KEYUP ... caps lock 5
event = FL_KEYUP ... caps unlock 6

event = FL_KEYUP ... caps lock 7
event = FL_KEYUP ... caps unlock 8


This is what I expected, and this is probably what Howard would like
to achieve.

Same on my Ubuntu VM:

$ cat x.tmp
***@ubuntu-test:/transfer/fltk/test$ fltk-config --compile
capslock2.cxx && ./capslock2
g++ -I/home/albrecht/svn/fltk-1.3 -I/home/albrecht/svn/fltk-1.3/png
-I/home/albrecht/svn/fltk-1.3/zlib -I/home/albrecht/svn/fltk-1.3/jpeg
-I/usr/include/freetype2 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
-D_FILE_OFFSET_BITS=64 -D_THREAD_SAFE -D_REENTRANT -o 'capslock2'
'capslock2.cxx' -static-libgcc -static-libstdc++
/home/albrecht/svn/fltk-1.3/lib/libfltk.a -lXext -lfontconfig -lXinerama
-lpthread -ldl -lm -lX11
event = FL_FOCUS ...
event = FL_KEYUP ... caps lock 1
event = FL_KEYUP ... caps lock 2
event = FL_KEYUP ... caps lock 3
event = FL_KEYUP ... caps lock 4
event = FL_KEYUP ... caps lock 5
event = FL_KEYUP ... caps lock 6
event = FL_KEYUP ... caps lock 7
event = FL_KEYUP ... caps lock 8
event = FL_KEYUP ... caps lock 9

Note that I pressed and released CAPS LOCK exactly 7 times. I saw two
messages (3 and 4) on key press #3 and again 2 (8 and 9) on key press
and release #7.

That's something that needs to be fixed, if possible. :-(

---

That said, you can always detect the state of modifier keys correctly
(AFAICT) if you check them in the handle() method on FL_KEYDOWN events
of other (text) keys, i.e. not on modifier keys only, particularly not
when testing the state of a key that is handled in this event.
I'd recommend to derive an own input class (as you did in your first
example) from Fl_Secret_Input and handle the key press of every key.
Then you can pop up a warning message whenever the caps lock state is
on for each character typed. If you don't want to annoy the user, you
can set a state variable to suppress follow-up warnings, until the caps
lock state has been turned off. Or similar...

Albrecht
Howard Rubin
2013-04-08 17:35:29 UTC
Permalink
Post by Greg Ercolano
an fltk timer would probably be needed to get the correct
state info shown reliably.
Thanks for the replies.

No luck with an fltk timer, on Ubuntu Linux 10.04. Test program below.

In the console we can see that (Fl::event_state() & FL_CAPS_LOCK)
correctly changes to nonzero as soon as you press Caps Lock.

But it doesn't change back to 0 when you press Caps Lock again
until e.g. you move the mouse over the window.

Howard Rubin

------------------------

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>
#include <iostream>

void TimerProc(void* p) {
Fl_Output* pOutput = static_cast<Fl_Output*>(p);

if (Fl::event_state() & FL_CAPS_LOCK) {
pOutput->show();
std::cerr << 1;
} else {
pOutput->hide();
std::cerr << 0;
}
pOutput->damage(~0); pOutput->redraw(); Fl::check(); Fl::wait(.1);

Fl::repeat_timeout(0.25, TimerProc, p);
}

int main(int argc, char* argv[]) {
Fl_Window* win = new Fl_Window(300, 200, "");
Fl_Output* pOutput = new Fl_Output(120, 50, 0, 15, "Caps Lock");

win->end();
win->show();

Fl::add_timeout(0.25, TimerProc, pOutput);

return Fl::run();
}
Greg Ercolano
2013-04-09 01:46:13 UTC
Permalink
Post by Howard Rubin
Post by Greg Ercolano
an fltk timer would probably be needed to get the correct
state info shown reliably.
Thanks for the replies.
No luck with an fltk timer, on Ubuntu Linux 10.04. Test program below.
In the console we can see that (Fl::event_state() & FL_CAPS_LOCK)
correctly changes to nonzero as soon as you press Caps Lock.
But it doesn't change back to 0 when you press Caps Lock again
until e.g. you move the mouse over the window.
I'm not sure if this is a bug in X11 or not.. kinda seems so.

X11's own "KeyRelease" events seem to behave similarly;
in my tests with the pure X11 code below, when X11 sends
a KeyRelease event for the capslock key, the "event.xkey.state"
shows accurate info when capslock is ENABLED, but INACCURATE INFO
when capslock is disabled.

You have to hit some other key to get the accurate state of
capslock after lock release.

So I think FLTK is simply passing this X11 behavior on to the app.
Not really sure if FLTK can fix this if X11 gives similar info.

My X11's a bit rusty, but there might be a way to acquire the realtime
capslock state by a different X library call -- if there is, you should
probably #ifdef that into your code.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

//
// Slightly modified X windows hello world
//
// ref: http://www.cuillin.demon.co.uk/nazz/trivia/hw/hw_c.html
// compile: g++ hello.c -o hello -lXtst -lX11 -lXext
//

int main(int argc, char *argv[])
{
Display *dpy; /* X server connection */
Window win; /* Window ID */
GC gc; /* GC to draw with */
XFontStruct *fontstruct; /* Font descriptor */
XGCValues gcv; /* Struct for creating GC */
XEvent event; /* Event received */
XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */

// OPEN DISPLAY
if ((dpy = XOpenDisplay(NULL)) == NULL) {
fprintf(stderr, "%s: can't open %s\n", argv[0], XDisplayName(NULL));
exit(1);
}

// CREATE 500x500 WINDOW
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
50,50,500,500, // x,y,w,h
0, // border width
0,0); // border color, bg color

XSelectInput(dpy, win, ExposureMask|KeyPressMask|KeyReleaseMask);

// MAP WINDOW
XMapWindow(dpy, win);

// EVENT LOOP
while (1) {
XNextEvent(dpy, &event);
switch ( event.type ) {
case Expose:
fprintf(stderr, "* Expose event\n");
if ( event.xexpose.count == 0) {
while (XCheckTypedEvent(dpy, Expose, &event));

// GET CURRENT WINDOW SIZE (FOR TEXT CENTERING)
XWindowAttributes xwa;
if (XGetWindowAttributes(dpy, win, &xwa) == 0)
break;
XClearWindow(dpy, win);
}
break;
case KeyPress:
case KeyRelease: {
const char *ename = (event.type==KeyPress) ? " Press" : "Release";
printf("%s keycode=0X%04x, state=0X%04x\n", ename, event.xkey.keycode, event.xkey.state);
break;
}
default:
fprintf(stderr, "* Ignored event '%d'\n", (int)event.type);
break;
}
}
return(1);
}
Greg Ercolano
2013-04-09 03:17:31 UTC
Permalink
Post by Greg Ercolano
My X11's a bit rusty, but there might be a way to acquire the realtime
capslock state by a different X library call
FWIW, 'xset q' will tell you the state of the keyboard LEDs, eg:

$ xset q | grep LED
auto repeat: on key click percent: 0 LED mask: 00000002

On my system, toggling capslock alternates between 00000002 / 00000003,
so I think bit 0 is the capslock key

So you could look at the source for xset to see what it's doing for that.

Also, xkbvleds(1) accurately shows the state of the capslock LED,
and like all things in X, there's quite a bit of complexity getting this info.
It's maybe something to do with XkbGetIndicatorState(3). eg.

unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;

..where d is the X11 Display*, ie. fl_display

I tried the following FLTK code with the above X11 only code
and it seemed to work more reliably.

#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/x.H>
#include <X11/XKBlib.h>
//
// demonstrate how to read the realtime capslock state in FLTK under X windows -erco 4/8/13
// Reads capslock state on KEYUP and also with an FLTK timer.
//
class MyWindow : public Fl_Window {
public:
MyWindow(int W,int H) : Fl_Window(W,H,"Watch CAPSLOCK") { }
int handle(int e) {
switch (e) {
case FL_KEYUP:
unsigned n;
XkbGetIndicatorState(fl_display, XkbUseCoreKbd, &n);
printf("KEYHIT: Capslock is %s\n", (n & 1) ? "on" : "off");
break;
}
return(Fl_Window::handle(e));
}
};
void Timer_CB(void*) {
unsigned n;
XkbGetIndicatorState(fl_display, XkbUseCoreKbd, &n);
printf(" TIMER: Capslock is %s\n", (n & 1) ? "on" : "off");
Fl::repeat_timeout(1.0, Timer_CB);
}

int main() {
MyWindow *win = new MyWindow(256,256);
win->show();
Fl::add_timeout(1.0, Timer_CB);
return(Fl::run());
}
MacArthur, Ian (Selex ES, UK)
2013-04-09 10:43:41 UTC
Permalink
Post by Greg Ercolano
I tried the following FLTK code with the above X11 only code
and it seemed to work more reliably.
Not so much for me - though that may be an issue with the VM rather than a "real" problem.

I find that, with this code, if I toggle Caps Lock on/off a few times, I can easily get to a state where the test code is resolutely reporting Caps Lock OFF, but the keybd LED is ON.

Hitting any key (focus to any window) then seems to fix it up...


Also, I tweaked the Tiiner_CB to show what fltk's event_state shows for FL_CAPS_LOCK, and it is not always (at least for me) the same as the X11 XkbGetIndicatorState seems to be showing...

Which seems... odd...





Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Greg Ercolano
2013-04-09 22:20:37 UTC
Permalink
Post by MacArthur, Ian (Selex ES, UK)
Post by Greg Ercolano
I tried the following FLTK code with the above X11 only code
and it seemed to work more reliably.
Not so much for me - though that may be an issue with the VM rather than
a "real" problem.
I find that, with this code, if I toggle Caps Lock on/off a few times,
I can easily get to a state where the test code is resolutely reporting
Caps Lock OFF, but the keybd LED is ON.
Try the xkbvled(1) application.

Do you find it too doesn't properly represent the shift lock LED?

If so, I'd suggest a problem with the VM or X or both; perhaps report
to the VM guys, as it sounds like an emulation issue. Or, it might be
the VM is exposing a problem with the one of the two OS's interface
to reading the keyboard LEDs..
Ian MacArthur
2013-04-09 22:59:18 UTC
Permalink
Post by Greg Ercolano
Post by MacArthur, Ian (Selex ES, UK)
Post by Greg Ercolano
I tried the following FLTK code with the above X11 only code
and it seemed to work more reliably.
Not so much for me - though that may be an issue with the VM rather than
a "real" problem.
I find that, with this code, if I toggle Caps Lock on/off a few times,
I can easily get to a state where the test code is resolutely reporting
Caps Lock OFF, but the keybd LED is ON.
Try the xkbvled(1) application.
Do you find it too doesn't properly represent the shift lock LED?
It also fails.
I've tried this now with F17 and Ubuntu-12.10, hosted on Win7 and OSX 10.6.8, though in VirtualBox VM's in each case.
I don't have ready access to another "brand" of VM to try at present.
If anything, the Win7 hosted version might have been slightly better, but none worked "right".
MacArthur, Ian (Selex ES, UK)
2013-04-10 10:31:37 UTC
Permalink
Post by Ian MacArthur
Post by Greg Ercolano
Try the xkbvled(1) application.
Do you find it too doesn't properly represent the shift lock LED?
It also fails.
I've tried this now with F17 and Ubuntu-12.10, hosted on Win7 and OSX
10.6.8, though in VirtualBox VM's in each case.
I don't have ready access to another "brand" of VM to try at present.
If anything, the Win7 hosted version might have been slightly better,
but none worked "right".
Well, in passing, I poked at the VM's a bit more, though nothing useful arises...

In summary, it looks as if the Caps Lock key is subject to "special" handling, probably both in X11 itself *and* by the VM.

For comparison, the Num Lock key appears to map straight through to xkbvleds (and my own test code) entirely "unmolested" and can be read reliably within the VM.

But the Caps Lock shows some unusual features.

- With the VBox VM hosted on Win7:

I can read the keyboard in "real time" with XQueryKeymap and see the Caps Lock key being pressed and released. I take this to mean that the VM is passing the key stokes through pretty much unmolested on Win7.
However, the state reported for Caps Lock (either by X11 or by fltk) does not reliably reflect the "true" state until after the *next* key is pressed (sometimes it is OK, but not often enough to be considered reliable!) This, I *assume* is special handling within X11 in some way.
Num Lock is always fine, AFAICT.



- With the VBox VM hosted on OSX:

When I read the keyboard in "real time" with XQueryKeymap I *never* see the Caps Lock key being pressed and released. It just never seems to get flagged, ever.
I take this to mean that the VM is NOT passing the Caps Lock key stokes through at all. I think the Caps Lock state is somehow only coming through to the VM on the next key stroke.
As a result, the state reported for Caps Lock (either by X11 or by fltk) does not reliably reflect the "true" state until the *next* key is pressed.
So in this case, it would appear there is "special" handling of the Caps Lock key by *both* the VM and by X11.
Num Lock is always fine, AFAICT.

The end.


Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Greg Ercolano
2013-04-10 15:48:35 UTC
Permalink
Wow, quite a variety of behavior.. VMs have a lot of work to do
to emulate the entire OS hardware, translating it from API to another.
I'd sure hate that job, as there are so many dark corners of undocumented
behavior in various OS calls.

It's also rare apps try to do anything with the capslock state.

Also: in my case I often forget I have a KVM, which might be having its
way with my keyboard. I've had to switch kvms a few times now because
of wak behavior with handling of special keys, screen sleeping, etc.
Settled on a Master View for now..
MacArthur, Ian (Selex ES, UK)
2013-04-09 10:26:09 UTC
Permalink
Post by Greg Ercolano
X11's own "KeyRelease" events seem to behave similarly;
in my tests with the pure X11 code below, when X11 sends
a KeyRelease event for the capslock key, the "event.xkey.state"
shows accurate info when capslock is ENABLED, but INACCURATE INFO
when capslock is disabled.
You have to hit some other key to get the accurate state of
capslock after lock release.
Yes - though with Howard's example I find (on a F17 VM, not a "real" computer) that (as Howard said) quite often (not always!) just wiggling the mouse about in the window gets the state to update correctly...

(Or, hitting the space bar always seems to!)

So, something in the state is getting updated by other events, and perhaps not just the X11 KeyRelease ones?

Or I'm missing the point again...





Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Howard Rubin
2013-04-09 19:18:48 UTC
Permalink
Post by Greg Ercolano
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
That works perfectly, and even better, needs no timer. Test program below.

Will this be fixed in a future release of FLTK?

- Howard Rubin

======================

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Secret_Input.H>
#include <iostream>
#include <X11/XKBlib.h>

bool isCapsLock() {
Display* d = XOpenDisplay(NULL);
if (!d)
return false;
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
return (n & 0x01) == 1;
}

class myWindow : public Fl_Window {
public:
myWindow(int x, int y, const char* l) : Fl_Window(x, y, l),
pOutput(NULL) {
}
Fl_Output* pOutput;

virtual int handle(int event) {
static bool haveDoneOnce = false;
if (!haveDoneOnce || (event== FL_SHORTCUT && Fl::event_key() ==
FL_Caps_Lock)) {
haveDoneOnce = true;

if (isCapsLock()) {
pOutput->show();
} else {
pOutput->hide();
}
}
return Fl_Window::handle(event);
}
};

int main(int argc, char* argv[]) {
myWindow* win = new myWindow(300, 200, "");

new Fl_Secret_Input(20, 20, 100, 15, "");

win->pOutput = new Fl_Output(120, 50, 0, 15, "Caps Lock");

win->end();
win->show();

return Fl::run();
}
Ian MacArthur
2013-04-09 21:09:16 UTC
Permalink
Post by Howard Rubin
Post by Greg Ercolano
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
That works perfectly, and even better, needs no timer. Test program below.
Hmm - might need to be careful though: didn't really work reliably for me, at least not in a F17 VM.

I'm entirely prepared to believe that the VM is exacerbating the problem, of course, but it does suggest that this might not be a 100% reliable fix, or that at least some users will get caught out... Maybe...
Greg Ercolano
2013-04-09 19:29:04 UTC
Permalink
This post might be inappropriate. Click to display it.
Greg Ercolano
2013-04-09 21:02:19 UTC
Permalink
Post by Greg Ercolano
we could perhaps provide a wrapper to get the
state of the keyboard LEDs (for operating systems that provide this)
e.g. fl_get_indicators() or some such that returns flags.
Maybe fl_get_keyboard_leds() and fl_set_keyboard_leds() would be better.

There might be some resistance to adding this though, since FLTK
is primarily a GUI toolkit trying to "stay light" on its API,
its intention to abstract GUI related features, and not abstract
all features of the window manager.

Guess I'd be curious what other devs have to say.
Ian MacArthur
2013-04-09 21:39:27 UTC
Permalink
Post by Greg Ercolano
Post by Greg Ercolano
we could perhaps provide a wrapper to get the
state of the keyboard LEDs (for operating systems that provide this)
e.g. fl_get_indicators() or some such that returns flags.
Maybe fl_get_keyboard_leds() and fl_set_keyboard_leds() would be better.
There might be some resistance to adding this though, since FLTK
is primarily a GUI toolkit trying to "stay light" on its API,
its intention to abstract GUI related features, and not abstract
all features of the window manager.
Guess I'd be curious what other devs have to say.
I'm not opposed per se, though I do woory about clutter...

However, as I said to Howard earlier; for me, on F17 (and now also Ubuntu 12.10) I find that it doesn't actually work, with the linux image in a VirtualBox VM.

I *assume* this is some VM weirdness, but am not sure...
Howard Rubin
2013-04-10 16:25:06 UTC
Permalink
Post by Greg Ercolano
It's also rare apps try to do anything with the capslock state.
I don't agree. Most login screens warn immediately if capslock is on
because their password fields don't echo input.

Howard Rubin
Ian MacArthur
2013-04-10 21:56:39 UTC
Permalink
Post by Howard Rubin
I don't agree. Most login screens warn immediately if capslock is on
because their password fields don't echo input.
Though it does appear that, at least if there is any prospect that your users will be running Linux in a VBox VM, that we may have to embrace the possibility that the very best we can do is detect the Caps Lock state when the user starts typing - reliably detecting Caps Lock otherwise seems... fraught...
Greg Ercolano
2013-04-10 23:15:11 UTC
Permalink
Post by Ian MacArthur
Post by Howard Rubin
I don't agree. Most login screens warn immediately if capslock is on
because their password fields don't echo input.
Though it does appear that, at least if there is any prospect that your users will be running Linux in a VBox VM, that we may have to embrace the possibility that the very best we can do is detect the Caps Lock state when the user starts typing - reliably detecting Caps Lock otherwise seems... fraught...
Right, that's probably the best case for the OP is to detect
if the capslock state is enabled /while/ the person is typing
their password. ie. pseudocode:

case FL_KEYDOWN: {
static int warn = 0;
if ( event_state & capslock )
{ if ( !warn ) { warn = 1; show_capslock_warning_in_status_bar(); } }
else
{ if ( warn ) { warn = 0; clear_status_bar(); } }

If I understand correctly, the capslock state info is correct during
regular keypresses, just not when the capslock key is hit.
MacArthur, Ian (Selex ES, UK)
2013-04-11 09:18:15 UTC
Permalink
Post by Greg Ercolano
If I understand correctly, the capslock state info is correct
during
regular keypresses, just not when the capslock key is hit.
Yes - in all the tests I tried, the Caps Lock state was always "correct" during (and after) regular key presses.

However, any attempt to discern the Caps Lock state immediately after the Caps Lock key was pressed / released a few times, with no other key pressed since, was "unreliable".

(For X11 on Linux, in a VBox VM... "real" systems may be more consistent!)



As a rider, I suggested in an earlier post that the OSX hosted VM was not even delivering the Caps Lock key down/up events to the hosted OS until the next "regular" key was pressed.

However, subsequent testing using xev shows this is not strictly true; however, the keyboard state in the VM is so messed up by the flurry of events that are delivered (for a single Caps Lock key transition, I see half a dozen events, where a normal key sends 1...) that any attempt to discern the Caps Lock state (e.g. via XQueryKeymap or otherwise) returns unreliable status...



Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Greg Ercolano
2013-04-11 17:34:41 UTC
Permalink
Post by MacArthur, Ian (Selex ES, UK)
Post by Greg Ercolano
If I understand correctly, the capslock state info is correct during
regular keypresses, just not when the capslock key is hit.
Yes - in all the tests I tried, the Caps Lock state was always "correct"
during (and after) regular key presses.
Yes.
Post by MacArthur, Ian (Selex ES, UK)
However, any attempt to discern the Caps Lock state immediately after
the Caps Lock key was pressed / released a few times, with no other
key pressed since, was "unreliable".
Right, though this seems to be specific to your VM.

Originally I thought the behavior was random, but looking closer,
it's actually predictable and reliable (just not what I'd expect).

Digging deeper, I found that the behavior across all versions of X
I currently have access to (Irix/redhat9/centos5.6) is /consistent/
and /predictable/ across all of them for this, with both X11 and FLTK code.

I rewrote the two programs (see below) to show clearer output,
including some fflush()s so that they would pipe correctly through grep(1).

When capslock is toggled, the state info in the xevent and Fl::event_state()
for the CapsLock key Press/Release and FL_PUSH/FL_RELEASE events is:

KeyPress: what the state was BEFORE the key was pressed
KeyRelease event: state is *always* 1.

So the reliable info is on KeyPress, it tells you what the state of capslock
WAS, and not what it will become.

Ditto for FLTK.

So if I pipe both programs thru "grep Press", I see the capslock state flag toggle
"reliably", the state being what the key WAS before the key was hit, no matter how
fast I toggle the key (And if I "grep Release", the flag is always "on")

Here's the output of the below "X11" and "FLTK" programs piped through
"grep Press" while I toggle capslock:

$ ./test-capslock-x11 | grep Press
X11 Press: off
X11 Press: on
X11 Press: off
X11 Press: on
X11 Press: off
X11 Press: on
..
$ ./test-capslock-fltk | grep Press
FLTK Press: off
FLTK Press: on
FLTK Press: off
FLTK Press: on
FLTK Press: off
FLTK Press: on

Consistent and reliable behavior.

I guess we should see how Win32 and OSX behave, and if they're "reliable"
as well, we should either:

1) Document the OS specific behavior, whether different or same, and leave the code alone
2) Pick one behavior, and modify the code to enforce it, and document it

In a perfect world I'd say (2), though if we start fiddling around with the
FLTK event structure's state info, we might be asking for trouble, not sure..
at very least we could do (1) for the short term.

Anyway, here's the two test apps, X11 and FLTK, which basically do the
exact same thing, but with clearer messages that are grep(1) friendly:

--- snip: start ------------------------------------------------------------------------
//
// X11 CAPSLOCK TEST
// Slightly modified X windows hello world
// ref: http://www.cuillin.demon.co.uk/nazz/trivia/hw/hw_c.html
// compile: g++ test-capslock-x11.c -o test-capslock-x11 -lXtst -lX11 -lXext

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main(int argc, char *argv[]) {
Display *dpy; /* X server connection */
Window win; /* Window ID */
XEvent event; /* Event received */

// OPEN DISPLAY
if ((dpy = XOpenDisplay(NULL)) == NULL) {
fprintf(stderr, "%s: can't open %s\n", argv[0], XDisplayName(NULL));
exit(1);
}

// CREATE WINDOW, SELECT EVENTS WE WANT, MAP WINDOW
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), // create 500x500 window
50,50,500,500, // x,y,w,h
0, // border width
0,0); // border color, bg color
XSelectInput(dpy, win, KeyPressMask|KeyReleaseMask); // select input events we want
XMapWindow(dpy, win); // map window

// EVENT LOOP
while (1) {
XNextEvent(dpy, &event); // get the event
switch ( event.type ) { // event received?
case KeyPress:
case KeyRelease: {
const char *emsg = (event.type==KeyPress) ? " Press" : "Release";
const char *lmsg = (event.xkey.state&2) ? "on" : "off";
printf("X11 %s: %s\n", emsg, lmsg); fflush(stdout);
break;
}
default:
fprintf(stderr, "* Ignored event '%d'\n", (int)event.type);
break;
}
}
return(0);
}
--- snip:end ------------------------------------------------------------------------


--- snip:start ------------------------------------------------------------------------
//
// FLTK CAPSLOCK TEST
// compile: fltk-config --compile test-capslock-fltk.cxx
//
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>

class MyWindow : public Fl_Window {
public:
MyWindow(int W,int H) : Fl_Window(W,H) { }
int handle(int e) {
switch (e) {
case FL_KEYDOWN:
case FL_KEYUP: {
const char *emsg = (e==FL_KEYDOWN) ? " Press" : "Release";
const char *lmsg = (Fl::event_state()&FL_CAPS_LOCK)?"on":"off";
printf("FLTK %s: %s\n", emsg, lmsg); fflush(stdout);
break;
}
}
return(Fl_Window::handle(e));
}
};
int main() {
MyWindow *win = new MyWindow(500,500);
win->show();
return(Fl::run());
}
--- snip:end ------------------------------------------------------------------------
Ian MacArthur
2013-04-11 22:46:21 UTC
Permalink
Post by Greg Ercolano
I guess we should see how Win32 and OSX behave, and if they're "reliable"
1) Document the OS specific behavior, whether different or same, and leave the code alone
2) Pick one behavior, and modify the code to enforce it, and document it
Can. Of. Worms.

Attached below, my take on this. It's messy...

However, the code given returns the "correct" state on OSX 10.6.8, Linux-in-a-VM, and WinXP.

What I find (at least on my systems...)

- On Linux, ONLY look at the FL_KEYDOWN events

- On WIN32, ONLY look at the FL_KEYUP events (and the sense is maybe inverted wrt the linux case)

- On OSX, I need to process both up and down events, because it looks (and I may be really losing the plot here) as if I only get keydown events when the Caps Lock is going on, and I only get keyrelease events if the Caps Lock is going off...

So... The code works, but it is not nice:
--------------
//
// FLTK CAPSLOCK TEST
// compile: fltk-config --compile test-capslock-fltk.cxx
//
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>

static Fl_Box *state_box = 0;
static unsigned updn = 0;
static unsigned updn_old = 0;

static void change_state_box(void) {
if(updn != updn_old) {
updn_old = updn;
if(updn) {
state_box->color(FL_RED);
state_box->label("ON");
}
else {
state_box->color(FL_BLACK);
state_box->label("OFF");
}
state_box->redraw();
}
} // change_state_box

class MyWindow : public Fl_Window {
public:
MyWindow(int W,int H) : Fl_Window(W,H) { }
int handle(int e) {
switch (e) {
case FL_KEYUP:
#ifdef __APPLE__
if ((Fl::event_state() & FL_CAPS_LOCK) != 0) {
updn = 999;
}
else {
updn = 0;
}
change_state_box();
#endif // __APPLE__
#ifdef WIN32
if ((Fl::event_state() & FL_CAPS_LOCK) != 0) {
updn = 0;
}
else {
updn = 999;
}
change_state_box();
#endif // WIN32
break;

case FL_KEYDOWN:
#ifndef WIN32
if ((Fl::event_state() & FL_CAPS_LOCK) != 0) {
updn = 999;
}
else {
updn = 0;
}
change_state_box();
#endif // !WIN32
break;

default:
break;
}
return(Fl_Window::handle(e));
} // handle
};

static MyWindow *win = 0;

int main(int argc, char **argv) {
win = new MyWindow(500,500);
win->begin();

state_box = new Fl_Box(10, 10, 80, 40, "OFF");
state_box->color(FL_BLACK);
state_box->box(FL_FLAT_BOX);
state_box->labelcolor(FL_WHITE);

win->end();
win->show(argc, argv);
return Fl::run();
} // main

// end of file
MacArthur, Ian (Selex ES, UK)
2013-04-12 08:36:21 UTC
Permalink
Post by Greg Ercolano
Post by Greg Ercolano
I guess we should see how Win32 and OSX behave, and if they're
"reliable"
Post by Greg Ercolano
1) Document the OS specific behavior, whether different or
same, and leave the code alone
Post by Greg Ercolano
2) Pick one behavior, and modify the code to enforce it, and
document it
Can. Of. Worms.
Attached below, my take on this. It's messy...
However, the code given returns the "correct" state on OSX 10.6.8,
Linux-in-a-VM, and WinXP.
What I find (at least on my systems...)
- On Linux, ONLY look at the FL_KEYDOWN events
- On WIN32, ONLY look at the FL_KEYUP events (and the sense is maybe
inverted wrt the linux case)
- On OSX, I need to process both up and down events, because it looks
(and I may be really losing the plot here) as if I only get keydown
events when the Caps Lock is going on, and I only get keyrelease events
if the Caps Lock is going off...
Argh! No it does not.

Just tested this on Win7, and it doesn't work...

To make this work on Win7, I took the code "as is" and inverted the state in the WIN32 only section of FL_KEYUP (i.e. make it the same as the APPLE FL_KEYUP code) and *then* the Win7 version works correctly.

WTF.



Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Greg Ercolano
2013-04-10 17:05:04 UTC
Permalink
This post might be inappropriate. Click to display it.
Richard Sanders
2013-04-10 20:55:49 UTC
Permalink
Post by Greg Ercolano
Post by Howard Rubin
Post by Greg Ercolano
It's also rare apps try to do anything with the capslock state.
I don't agree. Most login screens warn immediately if capslock is on
because their password fields don't echo input.
Right, though login screens have quite a few oddities about them
that are unlike regular GUIs.. inability to be 'stowed', fullscreen
with no docks/taskbars, running without a window manager (to prevent
window manager hotkey backdoors).
I imagine there's a bit of Xlib coding needed on top of fltk to pull off
a secure login screen, flwm being one example.
If you wrote the code in pure Xlib, you'd still encounter this problem,
the workaround apparently being to access the LEDs directly I think.
Anyway, not sure if hacking X11's event structure in the case of capslock
is a good idea or not -- seems like an X11 bug to me, and not sure if it's
appropriate for FLTK to try to cover that up with a hack.
Would like to hear what other devs say.
Out of curiosity I did a bit of googling and found this.

http://www.jveweb.net/en/archives/2010/11/making-better-use-of-the-caps-lock-key-in-linux.html

It would seem that trying to trap cap locks could be fruitless because
of key re mapping.
Cheers Richard
Ian MacArthur
2013-04-10 21:50:38 UTC
Permalink
Post by Richard Sanders
Out of curiosity I did a bit of googling and found this.
http://www.jveweb.net/en/archives/2010/11/making-better-use-of-the-caps-lock-key-in-linux.html
It would seem that trying to trap cap locks could be fruitless because
of key re mapping.
That's quite an interesting article, and mercifully short given the subject matter...

It had never occurred to me to fire up xev and see what the Mac hosted VM was actually seeing, so I just spent a little time staring at that. It's not pretty...

It's also clear that there's *a lot* of "manipulation" of kbd events going on "under the covers" for the Caps Lock key - if I press a regular key (say "a") I get one press event and one release event, on the "a" key. Fine.

If I press and release Caps Lock, I get a veritable flurry or key press/release events (for the Caps Lock key), many with the same time stamp (and interleaved with events for the Shift_L, which of course I'm *not* pressing at all.)
The *next* key I press, after releasing the Caps Lock key, is *also* associated with a series of Caps Lock and Shift_L events, before the key I actually pressed appears... With the correct CAPS/lower state applied.

However, Num Lock; which to me seems conceptually similar, just delivers nice, clean key press/release events. (And updates the keyboard state.)

I have no idea why Caps Lock doesn't just do that too. Complicated stuff is happening under the covers...

However, for Howard's needs, it possibly does not matter - even key remapping may not really matter; I guess that he does not care which physical key is acting as Caps Lock, so long as he can detect whether the current keyboard state has Caps Lock on or off.

The difficulty is that, at least in my VM's, the keyboard state is not resolved fully until the next key after the Caps Lock toggle.

I assume, from the tests reported by others, that "real" PC's return less convoluted state and it more or less works?
Albrecht Schlosser
2013-04-10 21:53:31 UTC
Permalink
Post by Greg Ercolano
If you wrote the code in pure Xlib, you'd still encounter this problem,
the workaround apparently being to access the LEDs directly I think.
Anyway, not sure if hacking X11's event structure in the case of capslock
is a good idea or not -- seems like an X11 bug to me, and not sure if it's
appropriate for FLTK to try to cover that up with a hack.
Would like to hear what other devs say.
There's a (big?) warning that using another Xlib call to get the key
state has at least two drawbacks:
(1) Speed. It's slow because it needs another client/server roundtrip.
(2) AFAIK all you can get is the CURRENT keyboard state. This can
differ from the state as seen (or should be seen) when processing
events, since this is an asynchronous call. I.e. event handling can be
three key presses and two releases "behind", and calling for the current
state would give you no better values. Note that speed may not be so
problematic, if you're working with X on a local machine, but X is
designed to be a remote protocol over tcp/ip.

This is all off the top of my head, and ISTR that I read such a warning
in the FLTK code somewhere, but I don't have personal experience with
native X11/Xlib calls. The same problem arises with Windows, BTW,
although tests showed in this case that it seemed to work.

So, if there is not an OBVIOUS bug in the FLTK code WRT direct event
handling, I'd recommend leaving it as-is. We should not try to fix one
bug and get another unpredictable behavior.

The intended behavior (warning about CapsLock in password entry fields)
can be achieved even when the warning is issued when a real key press
arrives, so it's usually not too late - and this works reliably, as my
tests and Ian's tests seem to show.
--
Albrecht
Continue reading on narkive:
Loading...