As long as I understand it, the X11 FocusIn event is triggered whenever the window comes into focused. It the the window that the keyboard input is sent to. I am having trouble triggering this event. I have made sure to give it the FocusChangeMask when creating the window. I have created a breakpoint inside my event handler where the FocusIn event is supposed to happen and it is not stopping.
I have 2 separate window, a transparent one and one non-transparent. Currently I have it so the transparent window is always on top of the non transparent window. Whenever I switch focus and then switch back to the transparent window, the non-transparent window is directly underneath. This causes other windows to be stuck in 'between' the transparent and non-transparent window.
I have noticed that whenever I focus on the non-transparent window that is underneath that triggers the FocusIn event. I can not get the transparent window to trigger the event. Does this have something to do with the window being in 32-bit color?
What am I missing?
while(!renderer->stop)
{
XNextEvent(renderer->x_display, &event);
switch(event.type)
{
case Expose:
if (event.xexpose.window == gstreamer_window)
{
XRaiseWindow(renderer->x_display, renderer->opengl_window);
}
break;
case FocusIn:
if (event.xfocus.window == renderer->opengl_window)
{
XRaiseWindow(renderer->x_display, gstreamer_window);
}
break;
case ConfigureNotify:
if (event.xconfigure.window == renderer->opengl_window)
{
XMoveWindow(renderer->x_display, gstreamer_window,
event.xconfigure.x, event.xconfigure.y - top_border_offset);
}
break;
}
}
Here is how I created the window.
XSetWindowAttributes swa;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | FocusChangeMask;
swa.colormap = XCreateColormap(x_display, XDefaultRootWindow(x_display), visual, AllocNone);
swa.background_pixel = 0;
swa.border_pixel = 0;
/* Create a window */
opengl_window = XCreateWindow (
x_display, parent,
0, 0, m_plane_width, m_plane_height, 0,
depth, InputOutput,
visual, CWEventMask | CWBackPixel | CWColormap | CWBorderPixel,
&swa );
It appears as though I set the FocusChangeMask at the wrong place. By adding the line XSelectInput(x_display, opengl_window, FocusChangeMask)
, it now triggers the FocusIn event. It was triggering the other display because it had the mask but this one didn't.
It's not clear from your question whether the windows referenced in your question are top level application windows, or secondary, ancillary windows that are child windows of your top level application windows.
But in all cases, proper input focus handling requires you to inform the window manager exactly how your application expects to handle input focus.
See section 4.1.7 of the ICCCM specification for more information. Unfortunately, it's not enough just to code an event loop that handles FocusIn messages, and expect them to fall out of the sky. First, you need to tell your window manager how exactly you are going to handle input focus switching, then respond to the window manager's messages, as explained in the ICCCM specification; perhaps by explicitly sending the SetInputFocus requests for your own application windows.
See my post under OP's self accepted answer for background
I had the same problem and it seems if you use XSelectInput it overrides the event mask for a window, instead of adding to it. You need to either:
skip adding XSelectInput and set the event masks on the window when created
or add all of the masks for the window to the XSelectInput command
Here's my similar setup which worked before I added the XSelectInput line:
swa.event_mask = StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | ExposureMask | KeyPressMask;
wnd = XCreateWindow(disp, wndRoot, left, top, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
XMapWindow(disp, wnd);
When I added this for capturing key input:
XSelectInput(disp, wnd, KeyPressMask | KeyReleaseMask);
everything else stopped working, which I didn't realize for a while, until now, because I was just testing keys.
I have a single window application with no controls in the client area, so I don't know what else XSelectInput does for a window that already has the masks, but I do get key up and down messages without it. In the OP's self accepted answer he just goes the other way and adds 'FocusChangeMask' to XSelectInput instead.
The documentation for a lot of X11 is, in my opinion, a lot like the standard Apple documentation where it has the affliction of never saying what the function really actually does or affects, but tells you all about everything else. (See bottom snippet here) To be fair a good portion of the Cocoa docs are pretty decent, but maybe half are not. That goes for many or most of the parameters as well.
From Linux man page which I think is the maybe verbatim the same as the Xlib manual here https://tronche.com/gui/x/xlib/
The XSelectInput function requests that the X server report the events associated with the specified event mask.
Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients.
(Below is my own perhaps incorrect rewording of the XInputSelect docs)
This can be interpreted as perhaps:
XSelectInput sets the event-mask on a window for a display for events reported to the client. Each client can set its own independent mask for events it wants to receive with the following exceptions (skipping the exceptions).
Now the critical part:
XInputSelect will override and replace for a client any previous event-mask settings for a window on a display, including any event-mask set when creating the window.
And what I wish it was written as to make sure its understood, if true, that the XInputSelect does nothing else like enable key to character interpretation and what not, because I believe the core confusion is that people from all the various examples out there get the impression that there is some other magic besides setting mask. I'm assuming there's not, and the docs speak of no other magic besides the mask.
XInputSelect sets the event-mask for a window and allows for setting an event mask after a window is created.
And my opinion is that that line should have been first.
Related
I know there has been a few of these, but a lot of the answers always to have a lot of buts, ifs, and you shouldn't do that.
What I'm trying to do is have a background program that can monitor the keyboard events from X11. This is on an embedded device, and it will have a main app basically running in something like a kiosk mode. We want to have a background app that manages a few things, and probably a back doors hook. But this app generally will not have focus.
I can't use the main app, because its partially there for a fail safe if the main app ever fails, or to do some dev type things to bypass the main app.
The best question I found is a few years old, so I'm not sure how up to date it is. This was extremely easy to do with windows.
X KeyPress/Release events capturing irrespective of Window in focus
The correct way for doing that is using Xlib. Using this library you can write code like this:
while (1) {
XNextEvent(display, &report);
switch (report.type) {
case KeyPress:
if (XLookupKeysym(&report.xkey, 0) == XK_space) {
fprintf (stdout, "The space bar was pressed.\n");
}
break;
}
}
// This event loop is rather simple. It only checks for an expose event.
// XNextEvent waits for an event to occur. You can use other methods to get events,
// which are documented in the manual page for XNextEvent.
// Now you will learn how to check if an event is a certain key being pressed.
// The first step is to put case KeyPress: in your switch for report.type.
// Place it in a similar manner as case Expose.
Also you could use poll or select on the special device file that is mapped to your keyboard. In my case is /dev/input/event1.
If you have doubts about what's the special file mapped to your keyborad, read the file /var/log/Xorg.0.log (search for the word keyboard).
Here you have another link of interest: Linux keyboard event capturing /dev/inputX
I am writing a program which need to listen the user keyboard stroks.
I use function XGrabKeyboard() and this is my code:
XGrabKeyboard(pDisplay, DefaultRootWindow(pDisplay), True, GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent event;
while (true)
{
XNextEvent(pDisplay, &event);
switch (event.type)
{
...
}
}
But it causes the keyboard and cursor to be frozen.
I looked up the man page, it only says: "The third parameter specifies a Boolean value that indicates whether the keyboard events are to be reported as usual."
I tried both true or false or the 3rd param, both GrabModeAsync and GrabModeSync for the 4th and 5th param, but it doesn't work.
After calling XGrabKeyboard(), the keyboard is frozen and mouse click doesn't response.
Any ideas?
XGrabKeyboard() (if successful - be sure to check the return value), redirects all key events to your client.
So if your "..." inside the while(true) does not properly handle those key events, or does not ever ungrab (XUngrabKeyboard) or release sync events (XAllowEvents, only applies to GrabModeSync), then the keyboard would appear to lock up.
The boolean parameter is owner_events which indicates whether to report key events always to the window provided to XGrabKeyboard, or report them to the window they normally would have gone to without the grab. Typically you want False (report to the grab window).
For typical uses of XGrabKeyboard (I don't know your use-case) the parameters you would want are:
grab window = some window in your app that relates to the reason for the grab
owner_events=False to send all events to that window
pointer_mode=Async to not screw with the pointer
keyboard_mode=Async to just redirect all key events and avoid need for AllowEvents
time=the timestamp from the event triggering the grab, ideally, or one generated by changing a property and grabbing the timestamp off the PropertyNotify
But, it depends. To give any definitive answer you'd probably need to post a compilable program, I think the bug is likely in the "..." part of your code. Try narrowing your app down to a single-file test case that can be run by others perhaps. Or explain more why you are grabbing and what you're trying to accomplish in the big picture.
I cant help with the XGrabKeyboard function - I havent used it before and dont know how it works - but I can suggest another way of getting the keyboard events.
When creating my window using XCreateWindow, the last argument is a XSetWindowAttributes object. This object has a member event_mask, which you can use to choose which events your window will receive.
I set mine like this:
XSetWindowAttributes setWindAttrs
setWindAttrs.event_mask = ExposureMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask;
That will mean you receive events for keyboard key presses and mouse button clicks if you pass this object to XCreateWindow on window creation.
Also another note you can use XPending(pDisplay) to check if there are still events waiting to be handled - so it could replace true in your while(true) line.
Edit: Also your freezing issue could be that you dont return false anywhere in your while loop? It may be stuck in an infinite loop, unless you just removed that bit for the post. Try replacing true with xpending as I suggested above and it may fix the issue, or just returning false after handling the event, but this would only handle one event per frame rather than handling all the currently pending events like XPending would do, and I assume that is what you want to do.
Background: I am using OmniThreadLibrary to load batch mode ADO stored procedures in the background. I am doing some slightly dodgy stuff by swapping the connection after opening the SP but that seems to be quite reliable. I'm using PostMessage to send messages back to the calling form and that works in my test applications. Primoz' comms channels work for me, I'm using those for inter-thread comms but for our main application I'm trying to avoid that dependency by using standard PostMessage calls as we do elsewhere in the app.
Problem: Unfortunately when I put this into our main application the PostMessage calls in the thread start failing with 1400:invalid window handle.
I have liberally added extra PostMessage calls and logging code to try to locate the problem, but I'm out of ideas now. The code is boilerplate:
const WM_PW_ADLQUEUEEMPTY = WM_USER + 11;
...
if PostMessage (OwnerHandle, WM_PW_ADLPROGRESS, QueueID, 10) then
pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+') OK for Queue ' + IntToStr (QueueID))
else
pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+') failed for Queue ' + IntToStr (QueueID));
But the log for a series of calls is not very revealing to me. note that the four hex digits after the time is the thread id from GetCurrentThreadID.
15:41:53.221 1614 TpwAsyncDataLoader.RunQueue WM_PW_ADLPROGRESS send to 00A5110C (IsWindow True) OK for Queue -6
15:41:53.265 13B4 TADLQueue.Run WM_PW_ADLPROGRESS send to 00A5110C (IsWindow True) OK for Queue -6
15:41:53.554 13B4 TADLQueueManager.WriteSysErrorMessageToDatabase Postmessage 00A5110C (IsWindow False) failed with 1400 Invalid window handle
Can anyone shed some light on this? I'm confused at how a window handle can become invalid while I'm looking at it, but that's what it looks like to me.
The one thing I can think of is that the form I'm showing here isn't processing messages and I'm seeing a "message queue full" failure rather than the IsWindow(handle) failure that it looks like. How can I test for that?
There are cases where a handle gets recreated, most notably when you change window flags. This might be what's happening in your application.
All I found so far about recreating windows handle is this post from Allen Bauer but I'm certain reading a more detailed one written by Peter Below. Unfortunatly I can't seem to find that one.
Finally, you need to be aware of cases
where your handle may need to get
recreated. This can happen if the
surrounding form or the parent
component's handle goes through a
recreate process. Up until more recent
releases of Windows, the only way to
change some window flags was to
destroy the handle and recreate with
new flags in the CreateWindowEx()
call. There are many components that
still do this. You know if you're in a
recreate situation by checking
(csRecreating in ControlState).
Edit
Not actually the posts from Peter I had in mind but it might give you some fresh ideas.
The form will not have a handle until
you show it the first time (unless
something in the form load sequence
request the handle) but the handle is
not destroyed when you hide the form
and unless you do something that
forces the form to recreate the
handle, e.g. change its border style
or border icons, or call RecreateWnd
yourself the handle will stay the
same.
It may not be desirable but it cannot
be avoided, at least not the way
Delphi drag&dock is currently
implemented. When you dock the dragged
form to another form it becomes a
control (with WS_CHILD window style)
and that means that its window handle
has to be destroyed and recreated with
the new style. And destroying the
window handle of a container control
automatically destroys the handles for
all child controls as well.
and
There is also the fact that the forms
window handle is destroyed and
recreated when you assign to its
Parent property. This also destroys
and recreates the handles for all
controls on the form.
I had a similar issue (but in VC++2010), and I did not find the solution on any forum, so I post it here, hope this will help:
Issue:
Creating a thread,
Passing the HWnd handle
In the thread, PostMessage
throws a 1400 error (invalid handle), although the pointer was equal
with the handle as seen from UI thread (with GetSafeHWnd()).
Solution:
Do not pass the handle, but the parent CDialog(Ex) class
This class has a m_hWnd member that will do the job
Here is a (Cpp) example, sorry for the cast mess.
// In the worker thread
ThreadParam *threadParam = (ThreadParam*)param
// This is ugly because my pointer is a void *, to avoid one more forward declaration
CCoreGenDlg *dlg = static_cast<CCoreGenDlg *>(threadParam->ptr);
// Post
bool b = PostMessage(dlg->m_hWnd ,1221,0,(LPARAM)message);
Cheers'
In an embedded Linux system, I'm trying to show a shutdown notification that should override any other windows when shutting down. Now creating the window isn't a problem, but showing the window reliably is. The X server or WM is somehow too busy to draw the notification every time. Considering the limited CPU power we have, its not surprising.
So, I figured I will make it easy to the WM/X by grabbing the X server using gdk_x11_grab_server() (which calls XGrabServer on default display). But when should I call the grab func? If I call it before building my window, prior showing my window or event in expose-event of my window, nothing is drawn to the screen (even in no-load test)!
The documentation says:
The XGrabServer function disables
processing of requests and close downs
on all other connections than the one
this request arrived on.
I suppose that would mean that only requests from my app should be processed, but it seems that is not the case, since nothing is drawn if X is grabbed by my app.
So, how and when should grabbing the X server be used to achieve wanted outcome, or is it totally a wrong tool and I've misunderstood the use (or trying to use it too high level for it to work really).
I'd guess that nothing is being drawn because you're opening a normal top level window, in which case the window manager needs to operate on it before it'll be visible; however you've locked out the window manager by calling XGrabServer().
You could try setting OverrideRedirect on the window, which tells the X server that the window manager shouldn't be involved with this window at all. This also has the effect of removing any decorations (title bar, close button, etc) from the window, which could well be what you want for a shutdown notification.
You may need to follow the call with XSync/XFlush.
Shouldn't you follow up with a call to XUngrabServer so that the X server resumes processing requests? All other connections have already been closed because you called XGrabServer, but you obviously need request handling to resume because you want to make requests on your connection.
There seems to be some confusing as to what XGrabServer actually does precisely, and not just on this question. The man pages are pretty ambiguous about this. We can easily verify though that the server indeed still processes requests from our connection:
// cc grab-test.c `pkg-config --cflags --libs x11`
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
int main(void)
{
// Initialize
Display* dpy = XOpenDisplay(NULL);
assert(dpy != NULL);
int s = DefaultScreen(dpy);
// Grab the Server
XGrabServer(dpy); // XFlush(dpy);
// Create some stuffs
Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 10, 10, 640, 480, 1, BlackPixel(dpy, s), WhitePixel(dpy, s));
XSelectInput(dpy, win, ExposureMask);
XMapWindow(dpy, win);
XStoreName(dpy, win, "An X11 window");
// Notice we can query the attributes BEFORE ungrabbing the server
XWindowAttributes wa;
XGetWindowAttributes(dpy, win, &wa);
int width = wa.width;
int height = wa.height;
printf("Current window size: %dx%d\n", width, height);
sleep(2); // Give some time to see the window
XDestroyWindow(dpy, win); XFlush(dpy);
sleep(2); // Give some time to NOT see the window
// Ungrab the server
XUngrabServer(dpy); // XFlush(dpy);
// Shutdown
XCloseDisplay(dpy);
return 0;
}
There is probably a window manager or composite manager preventing the window from being displayed, if I run the above program in Xephyr (without a window manager or composite manager), I can see a white window for 2 seconds followed by a black screen for 2 seconds, after which all other windows are redrawn again.
Is there a good library to use for gathering user input in Linux from the mouse/keyboard/joystick that doesn't force you to create a visible window to do so? SDL lets you get user input in a reasonable way, but seems to force you to create a window, which is troublesome if you have abstracted control so the control machine doesn't have to be the same as the render machine. However, if the control and render machines are the same, this results in an ugly little SDL window on top of your display.
Edit To Clarify:
The renderer has an output window, in its normal use case, that window is full screen, except when they are both running on the same computer, just so it is possible to give the controller focus. There can actually be multiple renderers displaying a different view of the same data on different computers all controlled by the same controller, hence the total decoupling of the input from the output (Making taking advantage of the built in X11 client/server stuff for display less useable) Also, multiple controller applications for one renderer is also possible. Communication between the controllers and renderers is via sockets.
OK, if you're under X11 and you want to get the kbd, you need to do a grab.
If you're not, my only good answer is ncurses from a terminal.
Here's how you grab everything from the keyboard and release again:
/* Demo code, needs more error checking, compile
* with "gcc nameofthisfile.c -lX11".
/* weird formatting for markdown follows. argh! */
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
Display *dpy;
XEvent ev;
char *s;
unsigned int kc;
int quit = 0;
if (NULL==(dpy=XOpenDisplay(NULL))) {
perror(argv[0]);
exit(1);
}
/*
* You might want to warp the pointer to somewhere that you know
* is not associated with anything that will drain events.
* (void)XWarpPointer(dpy, None, DefaultRootWindow(dpy), 0, 0, 0, 0, x, y);
*/
XGrabKeyboard(dpy, DefaultRootWindow(dpy),
True, GrabModeAsync, GrabModeAsync, CurrentTime);
printf("KEYBOARD GRABBED! Hit 'q' to quit!\n"
"If this job is killed or you get stuck, use Ctrl-Alt-F1\n"
"to switch to a console (if possible) and run something that\n"
"ungrabs the keyboard.\n");
/* A very simple event loop: start at "man XEvent" for more info. */
/* Also see "apropos XGrab" for various ways to lock down access to
* certain types of info. coming out of or going into the server */
for (;!quit;) {
XNextEvent(dpy, &ev);
switch (ev.type) {
case KeyPress:
kc = ((XKeyPressedEvent*)&ev)->keycode;
s = XKeysymToString(XKeycodeToKeysym(dpy, kc, 0));
/* s is NULL or a static no-touchy return string. */
if (s) printf("KEY:%s\n", s);
if (!strcmp(s, "q")) quit=~0;
break;
case Expose:
/* Often, it's a good idea to drain residual exposes to
* avoid visiting Blinky's Fun Club. */
while (XCheckTypedEvent(dpy, Expose, &ev)) /* empty body */ ;
break;
case ButtonPress:
case ButtonRelease:
case KeyRelease:
case MotionNotify:
case ConfigureNotify:
default:
break;
}
}
XUngrabKeyboard(dpy, CurrentTime);
if (XCloseDisplay(dpy)) {
perror(argv[0]);
exit(1);
}
return 0;
}
Run this from a terminal and all kbd events should hit it. I'm testing it under Xorg
but it uses venerable, stable Xlib mechanisms.
Hope this helps.
BE CAREFUL with grabs under X. When you're new to them, sometimes it's a good
idea to start a time delay process that will ungrab the server when you're
testing code and let it sit and run and ungrab every couple of minutes.
It saves having to kill or switch away from the server to externally reset state.
From here, I'll leave it to you to decide how to multiplex renderes. Read
the XGrabKeyboard docs and XEvent docs to get started.
If you have small windows exposed at the screen corners, you could jam
the pointer into one corner to select a controller. XWarpPointer can
shove the pointer to one of them as well from code.
One more point: you can grab the pointer as well, and other resources. If you had one controller running on the box in front of which you sit, you could use keyboard and mouse input to switch it between open sockets with different renderers. You shouldn't need to resize the output window to less than full screen anymore with this approach, ever. With more work, you could actually drop alpha-blended overlays on top using the SHAPE and COMPOSITE extensions to get a nice overlay feature in response to user input (which might count as gilding the lily).
For the mouse you can use GPM.
I'm not sure off the top of my head for keyboard or joystick.
It probably wouldn't be too bad to read directly off there /dev files if need be.
Hope it helps