My xlib code can listen to keyboard events but it fails for some windows - c++

I have this code to listen to keyboard events of the active window:
#include<X11/Xlib.h>
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <thread>
using namespace std;
#define IR_MODE 8192
#define SHIFT_MODE 16
#define US_MODE 0
static int ErrorHandler (Display *display, XErrorEvent *error)
{
cout<< "An error ocurred. We don't know anything.";
return 0;
}
int main()
{
Display *d = XOpenDisplay(0);
if(d == 0)
{
cout<< "Cannot open display\n";
exit(0);
}
Window root = DefaultRootWindow(d);
XSetErrorHandler(ErrorHandler);
Window current_window;
int rev;
XGetInputFocus(d,&current_window,&rev);
XSelectInput(d,current_window, KeyPressMask | KeyReleaseMask | FocusChangeMask);
while(true)
{
XEvent e;
XNextEvent(d, &e);
switch(e.type)
{
case FocusOut:
XGetInputFocus(d,&current_window,&rev);
if(current_window == PointerRoot || current_window == None)
{
current_window = root;
}
XSelectInput(d,current_window, KeyPressMask | KeyReleaseMask | FocusChangeMask);
break;
case KeyPress:
{
cout<< "key pressed\n";
break;
}
case KeyRelease:
cout<< "key released\n";
break;
}
}
XCloseDisplay(d);//*/
}
It works for many windows. But it fails for some windows, specially for gnome applications, e.g. nautilus. Why does this happen and how can I solve the problem?
The program just tries to listen to keyboard without interfering anything. As if the keyboard is being tapped with a difference: the program doesn't intend to lose language layout info. When a key is pressed, some information including ASCII codes are chosen and attached to the key event according to language layout and then the key event is sent. The program needs the key event with the information attached to it. So The program does not intend to Grab keyboard. It does not care for active or focused window. It just tries to listen to keys even if the program's window is not active. There are programs which check regularly with XQueryKeymap, but I'm not going to use that. Because it uses up CPU and then it will be more than just a fair listener. Also if checking is not frequent some keys may escape.

I guess your program does not work with GTK3 windows which uses xinput2. This is true if GTK3 was built without --disable-xinput.
AFAIK XSelectInput() won't work with xinput2, you need XISelectEvents() for such windows.
Look at meta_core_select_events() function from Mutter sources. It works both for xinput2 and traditional windows. This patch may be also helpful.

Related

Adjust video capture input port using C++ / python

I am having a video capture device (VCD) that acquires frames from a TV which have various output ports (VGA, HDMI, DVI). I read these frames using C++/OpenCV, process them and then show the output on a C++/Qt QLabel.
My problems show up when I change the input port (DVI to HDMI or HDMI to VGA,...), at then I need to manually open the crossbar dialog window for the VCD and switch the input port.
Shows command window with ffmpeg command line + crossbar window for the video capture device
Moreover, for each input port, I need to adjust some parameters relating to color range, scaling size and wire's length.
I need to automate this process of selecting the right input port with the corresponding right parameters using a C++ or python code.
I was searching for a way to read all the input pins of the crossbar dialog box for the video capture device and this set/unset the required pins.
Thanks in advance.
Here is the example in C++/WinAPI how you can set/unset the VIDEO INPUT pins on settings dialog. This code assumes, that checkboxes are children elements of the main dialog; there can be case, when they are nested inside the tab control "Custom settings", so in this case you need find the that tab at first.
#include <windows.h>
#include <string>
#include <vector>
#include <map>
#include <iostream>
int main(int, char **)
{
// Find the dialog
HWND hwnd = FindWindowA(NULL, "%Your settings dialog caption%");
if (hwnd == NULL)
{
std::cerr << "cannot find settings dialog" << std::endl;
return 1;
}
std::map<std::string, HWND> options;
// Get first dialog element
HWND h = GetWindow(hwnd, GW_CHILD);
char caption[250];
std::vector<std::string> inputs{
"1/HDMI",
"2/DVI-D",
"3/COMPONENT",
"DVI",
"4/VGA",
"SOG",
"5/SDI",
"6/COMPOSITE",
"7/S-VIDEO",
"8/AUTO"
};
while (h != NULL)
{
// Get element text
if (GetWindowTextA(h, caption, 250))
{
std::string scaption(caption);
// Check the text, if it's in the list of the option, put it into map.
if (std::find(inputs.begin(), inputs.end(), scaption) != inputs.end())
{
options[caption] = h;
}
}
h = GetWindow(h, GW_HWNDNEXT);
}
// Check the 4/VGA option.
SendMessageA(options["4/VGA"], BM_CLICK, 0, 0);
return 0;
}

X11: XQueryPointer gives me fuzzy Windows

I am currently trying to find if one of my Windows is underneath the Mouse cursor. This is not done in my process that creates the window, but in another process.
What I am currently doing is finding the Window via the process PID (and I made sure _NET_WM_PID is set correctly by my program). This basically works via XQueryTree and XGetWindowProperty. This works fine and is not the problem.
The problem is that XQueryPointer gives me fuzzy Windows back. I wrote a simple test program to show what I mean. First gather an ID from any Window you like using the command xprop via bash. It will give you the Window ID.
Then run this simple test program I wrote (quick and dirty), it gives you every 0,5s the current ID from the Window underneath the mouse cursor:
#include <X11/Xlib.h>
#include <iostream>
#include <unistd.h>
#include <stdint.h>
int main()
{
Display *display = XOpenDisplay(0);
Window root = XDefaultRootWindow(display);
Window root_return;
Window child_return;
int root_x_return;
int root_y_return;
int win_x_return;
int win_y_return;
uint32_t mask_return;
while (true)
{
if (::XQueryPointer(display, root, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return) == True)
{
std::cout << "Window ID: " << child_return << std::endl;
}
usleep(500000);
}
return 0;
}
Can somebody tell me what the problem is?
And here is my example output:
My program finds Window ID 73400324
xprop finds Window ID 73400324
The test program finds Window ID 20996726
Could be child windows, or the decoration that the window manager adds to a plain window.
By the way, the normal way to detect if your window is under the mouse is by catching the XEnterWindowEvent and XLeaveWindowEvent, but this is normally done within the program itself, not externally.

Clipboard Shortcut/Hotkey binding with Qt outside of application

I've tried googling, and searching on this site about this but to no avail.
I am building a Clipboard related application for Windows using Qt, and one of the requirements for it to work right is to be able to register for keyboard events outside my Qt application, like ctrl + c, ctrl + v. (copy/paste). The only thing that I have found online is using an external plugin for Qt but the entire concept was not explained properly, so I hit a dead end.
Does anyone have an idea how I can do this? Again, I want to register shortcuts to my application that will occur outside the application itself.
Thanks in advance!
Binding clipboard shortcuts and binding shortcuts in general are as I have discovered, two different things. Related to Clipboard events, Qt provides access to a dataChanged() signal through its QClipboard class. Using that, you are able to know when the clipboard data has changed, and act accordingly, and should eliminate the need to perform a system-wide binding of the Copy/Paste shortcuts.
In order to register a global shortcut (in this case the need for ctrl + v), and this is platform specific like in my needs, one can use the RegisterHotKey function under Windows. The HWND requested as the first parameter can be obtained from the winId function that is provided by QWidget.
In order to accept the WM_HOTKEY event, one would have to implement the winEvent virtual protected function under Qt <= 5.0, and nativeEvent on >= 5.0.
This depends on the Desktopenvironment the application runs in and it is OS-specific. If you intend to run the application within KDE you can register global hotkeys easyly by deploying a .desktop File with your Application or by adding things to /usr/share/kde4/apps/khotkeys .
Within Windows, the easiest way would probably be adding a registry key to the registry in order to register a global Hotkey. See MSDN
I think you're just confused about how the clipboard works. You never need to register clipboard-related hotkeys outside of your application. Those are handled by other applications. What those applications do is interact with the system-wide clipboard. Your application needs to interact with the same clipboard and get notifications about new clipboard data being available etc.
You might get more helpful answers if you tell us what you mean by a "clipboard related" application. Is it used to sell wooden clipboards? Or to calibrate clipboard springs? Or to manage inventory of clipboards? Or does it run on a digital clipboard? Sigh.
This should get you up and running in Windows+Qt and HotKeys pretty quickly.
I haven't tried the Qt eXTension library with QxtGlobalShortcut, but it sounds like it may be a more elegant complete solution for more platforms. (like in #TimMeyer's comment to your question)
https://stackoverflow.com/a/3154652/808151
I wrote up this function to listen for a single system wide hotkey in windows.
#ifndef HOTKEYTHREAD_H
#define HOTKEYTHREAD_H
#include <QThread>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
class HotKeyThread : public QThread
{
Q_OBJECT
public:
HotKeyThread(QObject *parent);
~HotKeyThread();
signals:
void hot_key_event(int);
public slots:
void run();
void stop();
private:
volatile bool m_stopped;
DWORD m_thread_id;
};
#endif // HOTKEYTHREAD_H
.cpp file
#include "hotkeythread.h"
#include <QDebug>
#include <process.h>
#define WM_END_THREAD (WM_USER+2)
HotKeyThread::HotKeyThread(QObject *parent)
: QThread(parent)
{
this->m_thread_id = 0;
}
HotKeyThread::~HotKeyThread()
{
}
void HotKeyThread::stop()
{
if(this->m_thread_id != 0)
::PostThreadMessage(this->m_thread_id, WM_END_THREAD, 0, 0);
}
//
void HotKeyThread::run()
{
// store a thread id so we can exit later
m_thread_id = ::GetCurrentThreadId();
qDebug() << "ThreadIDs" << QString::number(m_thread_id, 16) << QString::number((int) this->currentThreadId(), 16);
// register an atom, and a hotkey
BOOL retVal;
int counter = 0;
int magic_num = 1128;
ATOM id = ::GlobalAddAtom(MAKEINTATOM(magic_num + counter++));
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
int modifier = 0x0;// modify this line
int key = VK_NUMPAD0;// modify this line
if(QSysInfo::windowsVersion() > QSysInfo::WV_VISTA)
{
retVal = ::RegisterHotKey(NULL, id, modifier | MOD_NOREPEAT, key);
}
else
{
// No repeat is only supported in 7 and later
retVal = ::RegisterHotKey(NULL, id, modifier, key);
}
if(retVal)
{
qDebug() << "Successfully added a HotKey!";
}
else
{
qDebug() << "Failed to add a hotkey!";
return;
}
// wait on hotkeys
MSG msg = {0};
while (0 < ::GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_HOTKEY)
{
bool control = LOWORD(msg.lParam) & MOD_CONTROL;
bool shift = LOWORD(msg.lParam) & MOD_SHIFT;
bool alt = LOWORD(msg.lParam) & MOD_ALT;
bool win = LOWORD(msg.lParam) & MOD_WIN;
qDebug() << "HotKey!" << (control ? "Ctrl +": "")
<< (alt ? "Alt +": "")
<< (shift ? "Shift +":"")
<< (win ? "Win +":"") << QString::number(HIWORD(msg.lParam),16);
// TODO Notify MainWindow of the event
emit hot_key_event(msg.lParam);
}
else if(msg.message == WM_END_THREAD)
{
// exit
break;
}
}
// Clean up Hotkey
::UnregisterHotKey(NULL, id);
::GlobalDeleteAtom(id);
}
Usage in your GUI
// Start HotKey Thread!
m_hot_key_thread = new HotKeyThread(this);
QObject::connect(m_hot_key_thread, SIGNAL(hot_key_event(int)),
this, SLOT(handle_hot_key_event(int)), Qt::QueuedConnection);
m_hot_key_thread->start();
and when your program is closing use
m_hot_key_thread->stop();
Hope that helps.

why getting first chace exception in c++

I made a sample to check what happen when Ctrl+C is pressed in windows console application:
bool TerminationFlag=true;
int main()
{
g_hTerminateEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
::SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
while(1)
{
if(TerminationFlag == false)
{
break;
}
}
return 0;
}
BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_C_EVENT ||
dwCtrlType == CTRL_BREAK_EVENT ||
dwCtrlType == CTRL_CLOSE_EVENT)
{
TerminationFlag=false;
::SetEvent(g_hTerminateEvent);
return TRUE;
}
return FALSE;
}
I tested the code by running it using start debugging option in visual
studio when I press ctrl+c I get the following message
First-chance exception at 0x7c87647d
when I press on continue option my code comes to the line TerminationFlag=false; even though I have handled Ctrl+C in control handler. Can you please tell me whats the problem?
I assume you're using Microsoft Visual Studio from your description of the problem. The first chance exception being raised is the CTRL-C event which is trapped by the debugging environment. This is expected behaviour.
You can choose to ignore this: go to Debug menu/Exceptions/Win32 Exceptions and take out the CONTROL-C check from the "Thrown" column menu. This will ensure that the debugger only breaks on CONTROL-C when it is user-unhandled. See picture below:
Incidentally, you should be waiting for the termination event not polling for a flag. You may want something like:
#include "windows.h"
#include <iostream>
HANDLE g_hTerminateEvent;
BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_C_EVENT ||
dwCtrlType == CTRL_BREAK_EVENT ||
dwCtrlType == CTRL_CLOSE_EVENT)
{
std::cout << "Terminating" << std::endl;
SetEvent(g_hTerminateEvent);
return TRUE;
}
return FALSE;
}
int main()
{
g_hTerminateEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
DWORD result = WaitForSingleObject(g_hTerminateEvent, INFINITE);
return 0;
}
When running this sort of thing in the debugger you will never get the same picture as if you will run it without debugger. In debugger you typically cannot step over system functions that make console input/output. Debugger will unavoidable interact with system here.
The most reliable way to go on here is tracing.
This may not answer the question directly.
p.s. In your code samples as they are now there is no need for the event.
Update from MSDN:
Value Meaning
0 CTRL_C_EVENT
A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.

How do I turn off or ignore key repeat for my curses application?

So I recently found curses (specifically PDcurses) and I'm just getting into it. Right now I'm trying to write a little space shooter type game with it and it's worked fine so far for rendering and getting menu type input, but now when I go into the game, I've noticed that key repeat is pretty bad for action games. I need to be able to hold the key and move my avatar every single frame that the key is down. I know how to do this with a normal Win32 application, but I don't have a window and therefore I don't have a wndproc and I can't control the messages the console recieves :/
I don't expect this is something for curses to handle, though if it can that would be awesome, I was really just looking for a work-around that plays nicely with curses.
I have tried cbreak(), nodelay() and raw() to no avail.
Additional info:
Microsoft Visual Studio 2010 Ultimate
PDcurses 3.4, from prebuilt binaries
Windows 7 x64 Ultimate
This is far from a complete solution, and I don't know how it'll interact with PDCurses, but it's an attempt:
In summary, grab the console's handle with GetStdHandle(), configure it for raw reading with SetConsoleMode(), and then read keys one at a time with ReadConsoleInput(). I use a std::set to keep track of the currently pressed keys and so ignore repeats.
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <cassert>
#include <set>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
BOOL success;
success=GetConsoleMode(h, &mode);
assert(success);
mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
mode |= ENABLE_WINDOW_INPUT;
success=SetConsoleMode(h, mode);
assert(success);
INPUT_RECORD buffer[10];
std::set<WORD> keys_down;
while (true)
{
DWORD count=0;
success=ReadConsoleInput(h, buffer, 10, &count);
if (!success)
{
continue;
}
for (size_t i=0;i<count;++i)
{
switch (buffer[i].EventType)
{
case KEY_EVENT:
{
WORD keycode=buffer[i].Event.KeyEvent.wVirtualKeyCode;
if (buffer[i].Event.KeyEvent.bKeyDown)
{
if (keys_down.find(keycode)==keys_down.end())
{
std::cout<<"Key down: "<<keycode<<std::endl;
keys_down.insert(keycode);
}
}
else
{
if (keys_down.find(keycode)!=keys_down.end())
{
std::cout<<"Key up:"<<keycode<<std::endl;
keys_down.erase(keycode);
}
}
break;
}
default:
break;
}
}
}
}