Qt: monitor global cursor click event with X11? - qt

I want to capture global mouse click event in X11 , now
I tried to install a x11event filter , but it just doesn't work globally.
class XApplication: public QApplication
{
public:
XApplication (int & argc, char **argv):
QApplication (argc , argv)
{
}
protected:
bool x11EventFilter (XEvent *e)
{
qDebug() << "X11 Event: " << e->type;
return QApplication::x11EventFilter(e);
}
};
UPDATE
I mean outside the window , the code above works when I click on the window.

You can query X11 info from Qt using the QX11Info class. See its documentation. Then you can use raw Xlib from it.
You can use XGrabPointer(). If you use it, other apps won't receive the pointer events while the pointer is grabbed. man XGrabPointer will help you.
The "normal" way of subscribing for events is to use XSelectInput() on a window, but the problem is that you'll have to call XSelectInput on every single existing window. See its man page...
I know the xxf86dga extension has some calls related to mouse, but I'm not sure what they do.
XQueryPointer() is another way to query the pointer state without stealing events from other windows.
The only other place I can think of is the XInput extension, but I'm not sure it will help you either.
See the xev source code for a good reference on handling X11 events: http://cgit.freedesktop.org/xorg/app/xev
Sample code using XGrabPointer:
#include <stdio.h>
#include <assert.h>
#include <X11/Xlib.h>
int main(void)
{
Display *d;
Window root;
d = XOpenDisplay(NULL);
assert(d);
root = DefaultRootWindow(d);
XGrabPointer(d, root, False, ButtonPressMask | ButtonReleaseMask |
PointerMotionMask, GrabModeAsync, GrabModeAsync, None,
None, CurrentTime);
XEvent ev;
while (1) {
XNextEvent(d, &ev);
switch (ev.type) {
case ButtonPress:
printf("Button press event!\n");
break;
case ButtonRelease:
printf("Button release event!\n");
break;
case MotionNotify:
printf("Motion notify event!\n");
break;
default:
printf("Unknown event...\n");
}
}
XCloseDisplay(d);
return 0;
}
Compiled using: gcc x11mouse.c -o x11mouse -lX11

Related

How do I disable special handling of & on Qt button labels?

I have inherited a virtual keyboard system with an array of buttons, one for each key. The label for each button is a single QChar. When showing the "symbols" keyboard, the code uses an '&' QChar for a key label, but the key shows as blank. I'm sure Qt is processing the '&' as a shortcut key prefix. Similarly, the entered text is shown on another, longer, button label; this label, as well, handles '&' character as an accelerator. Entering "ABC&DEF" is shown as "ABCDEF" with the 'D' underlined.
I have tried building with QT_NO_SHORTCUT #defined, but that made no difference.
Does anyone know of an easy way to disable this special handling of '&'?
The answer is found in Qt doc. QAbstractButton::text:
If the text contains an ampersand character ('&'), a shortcut is automatically created for it. The character that follows the '&' will be used as the shortcut key. Any previous shortcut will be overwritten or cleared if no shortcut is defined by the text. See the QShortcut documentation for details. To display an actual ampersand, use '&&'.
(Emphasize by me.)
QPushButton is derived from QAbstractButton inheriting this behavior.
Sample testQPushButtonAmp.cc:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QPushButton qBtn("Text with &&");
qBtn.show();
return app.exec();
}
testQPushButtonAmp.pro:
SOURCES = testQPushButtonAmp.cc
QT = widgets
Compiled and tested on cygwin64 on Windows 10:
$ qmake-qt5 testQPushButtonAmp.pro
$ make
$ ./testQPushButtonAmp
Qt Version: 5.9.4
Concerning how to disable this default behavior:
I had a look at woboq.org QAbstractButton::setText().
void QAbstractButton::setText(const QString &text)
{
Q_D(QAbstractButton);
if (d->text == text)
return;
d->text = text;
#ifndef QT_NO_SHORTCUT
QKeySequence newMnemonic = QKeySequence::mnemonic(text);
setShortcut(newMnemonic);
#endif
d->sizeHint = QSize();
update();
updateGeometry();
#ifndef QT_NO_ACCESSIBILITY
QAccessibleEvent event(this, QAccessible::NameChanged);
QAccessible::updateAccessibility(&event);
#endif
}
So, QT_NO_SHORTCUT disables to retrieve the shortcut out of text but it has to be defined when Qt library is built from source. Actually, I'm afraid even with disabled shortcuts, the single & will still become invisible in output.
I digged deeper in woboq.org and found some promising candidates e.g.:
qt_set_sequence_auto_menmonic()
Specifies whether mnemonics for menu items, labels, etc., should be honored or not. On Windows and X11, this feature is on by default; on macOS, it is off. When this feature is off (that is, when b is false), QKeySequence::mnemonic() always returns an empty string.
Note: This function is not declared in any of Qt's header files. To use it in your application, declare the function prototype before calling it.
and a sample in QProxyStyle
#include "textedit.h"
#include <QApplication>
#include <QProxyStyle>
class MyProxyStyle : public QProxyStyle
{
public:
int styleHint(StyleHint hint, const QStyleOption *option = 0,
const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const override
{
if (hint == QStyle::SH_UnderlineShortcut)
return 0;
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
int main(int argc, char **argv)
{
Q_INIT_RESOURCE(textedit);
QApplication a(argc, argv);
a.setStyle(new MyProxyStyle);
TextEdit mw;
mw.resize(700, 800);
mw.show();
//...
}
which I tried in my sample.
Finally, nothing of them achieved the desired effect, i.e. only "&&" was rendered as & but "&" never.
__

How to make Qt Application mainwindow to remain always on top of other windows in Windows OS?

Platform - Windows 7,8,10
I have created a QApplication from QMainWindow.
I want it to remain always on top of all other windows.
I have used Qt flags ( Qt::WindowStaysOnTopHint ) to achieve this.
But this Qt flag does not work.
The application is a frameless application.
Please find below the code of the constructor of my Qt App.
myApp::myApp(QWidget *parent)
: QMainWindow(parent)
{
setWindowFlags(Qt::Widget | Qt::FramelessWindowHint);
setWindowFlags(this->windowFlags() | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint );
ui.setupUi(this);
}
How can I make this flag work ?
I have tried all the options suggested by several members of the community.
My present code is as follows
Qt::WindowFlags flags = this->windowFlags();
this->setWindowFlags(flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
ui.setupUi(this);
Strange fact is that this never works on my machine.
When I create an installer or copy the required files and run on a different machines(Windows 7, 8, 10) then I get my application on top of all other windows.
Note: I am using Visual Studio Community Edition 2015
OS - Windows 7 Professional Service Pack 1.
The following code finally worked for me to keep my window always above other windows
SetForegroundWindow((HWND)winId());
Qt::WindowFlags flags = this->windowFlags();
flags = flags & ~Qt::WindowMinimizeButtonHint;
this->setWindowFlags(flags|Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint );
ui.setupUi(this);
I have also blocked the minimze option for the window by unsetting the Minimize flag.
But still there is one problem. The lower portion of the window goes past the taskbar. I have to click on the application icon to bring the lower portion above the taskbar.
To make a window sit on top of all applications.
myApp.h
class myApp: public QMainWindow
{
Q_OBJECT
public:
explicit myApp(QWidget *parent = 0);
~myApp();
protected:
bool event(QEvent *event);
----
};
myApp.cpp
#include <windows.h>
#include <winuser.h>
myApp::myApp(QWidget *parent): QMainWindow(parent)
{
setWindowFlags(Qt::FramelessWindowHint |Qt::WindowStaysOnTopHint);
ui.setupUi(this);
}
bool myApp::event(QEvent *event){
switch (event->type())
{
case QEvent::Show:
{
HWND winHWND =(HWND) winId();
if( winHWND ){
qDebug() << endl << "Setting up associated console window ON TOP !";
SetWindowPos(
winHWND, // window handle
HWND_TOPMOST, // "handle to the window to precede
// the positioned window in the Z order
// OR one of the following:"
// HWND_BOTTOM or HWND_NOTOPMOST or HWND_TOP or HWND_TOPMOST
0, 0, // X, Y position of the window (in client coordinates)
0, 0, // cx, cy => width & height of the window in pixels
SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW // The window sizing and positioning flags.
);
// OPTIONAL ! - SET WINDOW'S "SHOW STATE"
ShowWindow(
winHWND, // window handle
SW_NORMAL // how the window is to be shown
// SW_NORMAL => "Activates and displays a window.
// If the window is minimized or maximized,
// the system restores it to its original size and position.
// An application should specify this flag
// when displaying the window for the first time."
);
qDebug() << endl << "Done.";
} else {
qDebug() << endl << "There is no console window associated with this app :(";
}
break;
}
default:
break;
}
return QMainWindow::event(event);
}
For more help
write one simple line in constructor. (no need to include any other headers)
setWindowFlag(Qt::WindowStaysOnTopHint);
See:
http://doc.qt.io/qt-5/qt.html
http://doc.qt.io/qt-5/qtwidgets-widgets-windowflags-example.html
Use WindowStaysOnTopHint flag. From Qt Doc:
"Informs the window system that the window should stay on top of all
other windows. Note that on some window managers on X11 you also have
to pass Qt::X11BypassWindowManagerHint for this flag to work
correctly."
Your fault is that you called setWindowFlags twice for FramelessWindowHint and WindowStaysOnTopHint respectively. Try:
Qt::WindowFlags flags = windowFlags();
setWindowFlags(flags | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
Or you can use the Windows System API:
#include <Windows.h>
....
SetForegroundWindow((HWND)winId());
setWindowFlags(Qt::WindowStaysOnTopHint);
In your .pro file:
win32-g++:LIBS += libUser32
win32-msvc*:LIBS += User32.lib
You have to set setWindowFlags after ui.setupUi(this);

protothread jump a thread to the beginning in the external main function

I have a protothread set up and blocking ...
static int mythread(struct pt *pt){
static int k;
PT_BEGIN(pt)
while(1){
PT_WAIT_UNTIL(pt, eventA == 1); // blocked at lineA
for(k=0;k<100;k++){
//do something
PT_YIELD(pt); //blocked at lineB
}
PT_WAIT_UNTIL(pt, eventB == 1); //block at lineC
}
PT_END(pt)
}
After a while, mythread can be blocked at "lineA", "lineB", or "lineC".
How could an external function, like main() reset mythread to be blocked at the beginning "lineA" again.
By running the macro PT_RESTART(&pt_mythread)? The compiler doesn't like it. Because my main() function isn't inside PT_BEGIN, PT_END block, so the return inside that macro is bad, bad.
Or running PT_INIT(&pt_mythread) again? Any suggestions?
Yes, calling PT_INIT from outside the protothread will restart it. If you look at the source for PT_RESTART:
#define PT_RESTART(pt) \
do { \
PT_INIT(pt); \
return PT_WAITING; \
} while(0)
This is exactly what it does, but then also returns (like a yield) out of the thread. As you say it's designed to be called from inside the protothread.
The protothread struct is basically just a number representing where it was in the thread:
struct pt {
lc_t lc; // where lc_t is an unsigned short;
};
So the only thing we need to do is reset that number to zero, which is exactly what PT_INIT does.

Qt crashes when calling nested lambda to change widget

I am working on a project using C++ and QT. Part of the project involves a structure which keeps track of methods to update widgets. I have included a sample program below which highlights the issue, which is the problem distilled.
In the program, I have a list of 'relations', which contains lambdas to change widgets, based on data obtained elsewhere. This works fine (and may be dumped), but the problem is when one lambda is calling another.
An example is below. This program only has a combobox with the three strings, which calls 'slot1()' when changed. Slot one then calls the function pushed into the vector with the row, and calls that function with the parameter.
The Vector is
QVector<std::function<void(int)>> func;
When func.pushback takes setProductIndex as a parameter, the program works (I understand this is essentially a no op). The function is called. When it takes setProductIndex2, the program segfaults when the combobox is changed.
I have verified that the functions are indeed being called, but I'm unsure why it would segfault with setProductIndex2. All that is doing, is calling setProductIndex with the passed value which DOES work.
I can work around this, but I would like to know where I'm going wrong for better understanding.
I'm using GCC v4.8.3 and qt 5.3.2 on Fedora Linux.
Thanks.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
qDebug() << "1";
ui->setupUi(this);
QStringList model;
model.append("Test1");
model.append("Test2");
model.append("Test3");
ui->comboBox->addItems(model);
qDebug() << "2";
std::function<void(int)> setProductIndex = [&] (int x) ->void { ui->comboBox->setCurrentIndex(x);
ui->comboBox->setCurrentIndex(x); return;} ;
std::function<void(int)> setProductIndex2 = [&] (int x) ->void {setProductIndex(x);};
func.push_back(setProductIndex2);
qDebug() << "Func size " << func.size();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slot1(int xx)
{
//ui->comboBox->setCurrentIndex(--xx);
func[0](xx);
}

How can I get the current mouse (pointer) position co-ordinates in X

This can either be some sample C code or a utility that will show me either gui or on the console it doesn't matter, but I have to be able to "command" it to grab the co-ordinates at an exact time which makes xev not very useful (that I could figure out).
I'm not a C programmer by any means but I looked at a couple of online tutorials and think this is how you are supposed to read the current mouse position. This is my own code and I'd done nothing with Xlib before so it could be completely broken (for example, the error handler shouldn't just do nothing for every error) but it works. So here is another solution:
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
static int _XlibErrorHandler(Display *display, XErrorEvent *event) {
fprintf(stderr, "An error occured detecting the mouse position\n");
return True;
}
int main(void) {
int number_of_screens;
int i;
Bool result;
Window *root_windows;
Window window_returned;
int root_x, root_y;
int win_x, win_y;
unsigned int mask_return;
Display *display = XOpenDisplay(NULL);
assert(display);
XSetErrorHandler(_XlibErrorHandler);
number_of_screens = XScreenCount(display);
fprintf(stderr, "There are %d screens available in this X session\n", number_of_screens);
root_windows = malloc(sizeof(Window) * number_of_screens);
for (i = 0; i < number_of_screens; i++) {
root_windows[i] = XRootWindow(display, i);
}
for (i = 0; i < number_of_screens; i++) {
result = XQueryPointer(display, root_windows[i], &window_returned,
&window_returned, &root_x, &root_y, &win_x, &win_y,
&mask_return);
if (result == True) {
break;
}
}
if (result != True) {
fprintf(stderr, "No mouse found.\n");
return -1;
}
printf("Mouse is at (%d,%d)\n", root_x, root_y);
free(root_windows);
XCloseDisplay(display);
return 0;
}
xdotool might be the best tool for this.
For C, you can use libxdo.
Actually, xev is very useful if you supply it with the window id grabbed using xwininfo, then it can easily perform this task for you. There are no doubt much more elegant solutions but it works.
xinput can be used to print the full device state of any input device.
First you need to discover your device id:
$ xinput --list | grep -i mouse
⎜ ↳ Logitech USB Receiver Mouse id=11 [slave pointer (2)]
then you can ask for state:
$ xinput --query-state 11;
2 classes :
ButtonClass
button[1]=up
button[2]=up
button[3]=up
button[4]=up
button[5]=up
button[6]=up
button[7]=up
button[8]=up
button[9]=up
button[10]=up
button[11]=up
button[12]=up
button[13]=up
button[14]=up
button[15]=up
button[16]=up
button[17]=up
button[18]=up
button[19]=up
button[20]=up
ValuatorClass Mode=Relative Proximity=In
valuator[0]=274
valuator[1]=886
valuator[2]=0
valuator[3]=675
Or just a loop:
while sleep .2; do xinput --query-state $(xinput --list | grep -i mouse | cut -d= -f2 | cut -f1| head -1); done

Resources