Is it possible to use QShortcut in a console QCoreApplication? I don't have any QWidget objects to pass to QShortcut's constructor, I want the signal to be emitted when the user presses a key and the console window has focus.
If such approach is not possible what (prefferably portable) alternatives do I have?
Thank you in advance!
I'm not sure this is at all possible, because keyboard events in the sense usually used in Qt are delivered to windows/widgets, by the underlying OS windowing system. There's a reason why QShortcut requires a widget parent.
When you're in the terminal, you have to explicitly read the terminal to get keys.
Fortunately, that's easy to do. Use QTextStream to read from stdin in a separate thread, and translate interesting keystrokes to signals or events.
Do note, however, that in consoles some special keystrokes won't be delivered to you as-is. It depends a lot on the console, of course.
Related
I have an application which receives input from a serial port and interprets them as key events. The key events are created in C++ and sent to QGuiApplication::focusWindow() with qApp->sendEvent.
The GUI is implemented in QML and has been handling input through key event handlers. I would like to start using the Shortcut QML class to handle cases where I want behavior regardless of which object has focus.
I've discovered that Shortcuts which respond to a real keyboard will not respond to qApp->sendEvent, nor do they respond to qApp->postEvent.
Getting the behavior I want to reliably occur without Shortcut would be a real pain - is there I way I can handle my synthetic events which will make them visible to Shortcut?
Qt shortcut objects work through parts of the Qt system which are not part of the regular API, but are exposed to QPA. Specifically, QWindowSystemInterface::handleShortcutEvent, which takes as arguments the current focus window and most of the information encapsulated in a QKeyEvent.
// A helper to send a QKeyEvent to shortcuts
bool handleShortcutEvent(const QKeyEvent &ev, QWindow *focusWindow) {
return QWindowSystemInterface::handleShortcutEvent(focusWindow, ev.timestamp(), ev.key(), ev.modifiers(), ev.nativeScanCode(), ev.nativeVirtualKey(), ev.nativeModifiers(), ev.text(), ev.isAutoRepeat(), ev.count());
}
// in my key event generating function
if(!handleShortcutEvent(event, focusWindow))
qApp->sendEvent(focusWindow, &event);
Let me explain my question with an example. In my app, I need to provide a way to automatically close it from within "itself." (An example of such function is when an installer/updater of my app needs it to close before installing an update. Another example is when my app performs actions on schedule and needs to automatically close once it's done.)
I picture that in the simplest situation posting the WM_CLOSE message to the own window will accomplish this task, but there're the following cases that will not work with just that:
My app may be displaying an arbitrary number of child dialog windows.
My app may be displaying a common control window, such as Open File dialog:
or this one, but there could be others:
And lastly what could one do if the close button is not even available:
At the current point, I simply resort to terminating my process (either with the exit() method from within, or with TerminateProcess from outside.)
But I'm curious, if there's a more graceful way of closing my GUI app (from within)?
There is no single answer, it depends on your app's architecture and what it's doing. I don't quite understand why you would want to force close your application while it is in a common dialog, but if you do, then exit() is safe. In that case the process is actually shutdown from the operating system's perspective as opposed to a forced termination (TerminateProcess). In theory TerminateProcess might leave objects in the OS (DLL global data and such) in an inconsistent state, and exit() will be cleaner in that regard.
Generally though I'd avoid having visible UI that is up for the user just disappear and instead close the windows in reaction to some user choice.
But, exit() will work.
You can use exit() but a safer way to close the window would be:
SomewWindow->ShowWindow(SW_HIDE);
You could then destroy the window object or show the window later.
As we all know, EVT_CHAR is a basic event which don't propagate to wxTopLevelWindow(wxFrame and wxDialog).
But I have a wxDialog without any wxWidgets controls on it, and need to handle user keyboard input (handle EVT_CHAR event).
I saw the wiki about catch key events globally, but it's not work on EVT_CHAR event as EVT_CHAR event need to be translated to get user input
And I have try to have wxDialog a hided children wxWindow which foward EVT_CHAR to its parent wxDialog. It works on Windows platform, and not on OSX which is my target platform.
Is there a way to implement it ?
Why do you need to handle all keyboard entry in the dialog itself? There are two typical cases for this that I know of: either you want to handle the key presses in several different controls in the same way, or you need to handle some particular key press (e.g. WXK_F1) in all controls. The former can be done by binding the same event handler to several controls. The latter -- by using accelerator table with an entry for the key that you want to handle specially.
Finally, I implemented what I want according to this:
http://trac.wxwidgets.org/ticket/15345
In wxWidgets 3.0, wxNSView implementes NSTextInputClient protocol, which makes every widgets can handle EVT_CHAR correctly.
But EVT_CHAR still cannnot be handle by wxDialog or wxFrame, because of some call of IsUserPanel() function. So I commented some call of IsUserPanel to make it work for me.
Or to clarify this question, how can I make Windows think I hit a key, when I really didn't? I know I could possibly use SendMessage and specify the input there, but then wouldn't only my application receive it? I'd like control to the extent of all applications receiving the "fake" input. Any advice?
What you describe, faking input, is implemented by the SendInput function. Input goes to the thread which has input focus.
You can SendMessage to whatever window you want, even on other processes. You can even use HWND_BROADCAST to send it to every to-level window on the system. But is that what you really want? If you're only interested in a specific program, you can get its window's handle using FindWindow, and then send the message only to that window.
Note that if all you want to do is a simple keystrokes injection into another process, then SendInput is indeed the way to go. If you'd like to send some global keyboard shortcut it doesn't matter who has the focus. If you'd like to send the same input to more than one window using SendInput, you'll have to loop over the list of windows, and for each window first set the focus and then send the input.
Here is the situation:
1) I have two toplevel windows, A and B
2) A is in front of B
How can I send to keyboard focus to the window B while keeping the window A in front of B ?
I'm assuming you control both windows, and this is on an X11 system like Linux. If not, it's much more challenging. I've done things like this within a single app, and here are some recollections.
You've probably figured out you can't just use gtk_widget_grab_focus() to do it. That only works for determining which widget within a window has focus when the window itself has focus.
It's X11 that determines which window gets a keyboard event, based on the window hierarchy, info from the window manager, etc. However, you can monkey around with that via GDK to get the result you want.
You'll have to learn about GDK event propagation, and probably read some of the GDK sources. But I believe that, generally, what you'll need to do is this:
Use gdk_event_handler_set() to install your own event handler. You'll need to do this after GTK+ is initialized, and chain to gtk_main_do_event().
When you get a keyboard event (GdkEventKey), look at the X event structure. If it has the XID for window A, replace that with the XID for window B, and pass it on to GTK+. You might need to duplicate the event, and not modify the original one.
If the windows belong to different apps, you can look at gdk_event_send_client_message(), but I've never used it.
If you don't mind that it's not direct, you could send the keyboard events from the top level window to the one behind it. Of course that assumes that both windows are created by you rather than writing a program to hover in the background and read keyboard input being used on a separate program.
gtk_window_set_keep_above(a) followed by gtk_window_present(b)?