Xlib mouse events and ButtonPressMask - events

I have written a simple program which will report key press and release events for a particular window. In my case, it is mostly the terminal since I invoke the program from the terminal. I am able to get the key press and release events taking place in the terminal window (I have used XSelectInput() with KeyPressMask and KeyReleaseMask on the terminal) but the same is not working with ButtonPress and ButtonRelease. Not just these, but any events related to the mouse are not being reported. Any idea why this is happening?
#include
#include
#include
#include
#include
#include
int main() {
Display *display = XOpenDisplay(NULL);
KeySym k;
int revert_to;
Window window;
XEvent event;
XGetInputFocus(display, &window, &revert_to);
XSelectInput(display, window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
while(1)
{
XNextEvent(display,&event);
switch (event.type) {
case KeyPress : printf("Key Pressed\n"); break;
case KeyRelease : printf("Key Released\n"); break;
case ButtonPress : printf("Button Pressed\n"); break;
case ButtonRelease : printf("Button Released\n"); break;
case EnterNotify : printf("Enter\n"); break;
}
}
XCloseDisplay(display);
return 0;
}

The problem you encounter is that Xlib sends ButtonPress/Release events to only one client. I think that the window you're working with already has a client which is listening to its mouse events. Therefore your SelectInput call did not actually set ButtonPress/Release masks and generated an error which you didn't check for.

Related

Capturing mouse click count from the Background [duplicate]

I am using "XGrabPointer" to get the mouse click events when ever they occured in the active window.But my requirement is to detect the clicks globally i.e in any application on the X11 desktop.
XGrabPointer blocks the active window so i can not move to other applications and detect the mouse click events.
Here are the codes:
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
int main(int argc, char **argv)
{
Display *display;
XEvent xevent;
Window window;
int grb;
int scr;
if( (display = XOpenDisplay(NULL)) == NULL )
return -1;
unsigned int t_new=0,t_prev=0,t_diff=0;
scr = DefaultScreen(display);
window = RootWindow(display, scr);
while(1) {
XGrabPointer(display,
window,
True,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync,
GrabModeAsync,
None,
None,
CurrentTime);
XAllowEvents(display,AsyncPointer, CurrentTime);
XNextEvent(display, &xevent);
switch (xevent.type) {
case MotionNotify:{
printf("motion event\n");
break;
}
case ButtonPress:{
switch (xevent.xbutton.button) {
case 1:
printf("Left Click\n");
t_prev=t_new;
printf("Click Occured : [%d, %d]\n",
xevent.xbutton.x_root,
xevent.xbutton.y_root);
break;
case 2:
printf("Grabed\n");
printf("Middle Click\n");
break;
case 3:
printf("Right Click\n");
break;
case 4:
printf("Grabed\n");
printf("Scroll UP\n");
break;
case 5:
printf("Scroll Down\n");
break;
}
break;
}
}
}
XUngrabPointer(display,CurrentTime);
return 0;
}
Couldn't find an answer on how to listen to mouse events in the background as well. It's impossible to do it with mouse grabbing and you won't be able to click anywhere outside of your program.
So the solution is to read linux's /dev/input/mice device for the raw mouse input (we want button clicks) and when a low-level event occur we query X server for mouse position (can't query mouse key presses from X this way).
Display *display;
Window root_window;
XEvent event;
display = XOpenDisplay(0);
root_window = DefaultRootWindow(display);
int fd, bytes;
unsigned char data[3];
const char *pDevice = "/dev/input/mice";
// Open Mouse
fd = open(pDevice, O_RDWR);
if (fd == -1) {
printf("ERROR Opening %s\n", pDevice);
return -1;
}
int left, middle, right;
while (1) {
// Read Mouse
bytes = read(fd, data, sizeof(data));
if (bytes > 0) {
left = data[0] & 0x1;
right = data[0] & 0x2;
middle = data[0] & 0x4;
XQueryPointer(
display,
root_window,
&event.xbutton.root,
&event.xbutton.subwindow,
&event.xbutton.x_root,
&event.xbutton.y_root,
&event.xbutton.x,
&event.xbutton.y,
&event.xbutton.state
);
printf("x=%d, y=%d, left=%d, middle=%d, right=%d\n", event.xmotion.x, event.xmotion.y, left, middle, right);
}
}
Sample output
x=470, y=969, left=1, middle=0, right=0
x=470, y=969, left=0, middle=0, right=0
x=467, y=969, left=0, middle=4, right=0
x=463, y=969, left=0, middle=0, right=0
x=444, y=971, left=0, middle=0, right=2
x=441, y=971, left=0, middle=0, right=0

I can not synthesize a right click when using SendInput

I'm using WinAPI, with C++, I want to make a right click simulation with SendInput, but I'm not sure of what's going wrong.
My test program should work like that: when i press middle button of mouse, it perform a right click.
#include <iostream>
#include <windows.h>
#include <stdio.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// Fetch tab key state.
while (1)
{
SHORT tabKeyState = GetAsyncKeyState(4); // Mouse mid button
// Test high bit - if set, button was down when GetAsyncKeyState was called.
if (tabKeyState < 0)
{
INPUT Input[2] = { 0 };
// left down
Input[0].type = INPUT_MOUSE;
Input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
Input[0].mi.time = 500;
// left up
Input[1].type = INPUT_MOUSE;
Input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP;
Input[1].mi.time = 500;
::SendInput(2, Input, sizeof(INPUT));
}
}
return 0;
}
In the code to set the properties for the second event record you use index 0 instead of index 1.
Input[1].type = INPUT_MOUSE;
Input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
Input[0].mi.time = 100;
Use index 1 rather than 0 in the final two lines.
By the by, it's easier to write the if statement like this
if (tabKeyState < 0)
I solve this question using Sleep to make what i wanted to do and I discovered that the sendinput was not working cause I was executing this inside the VS. This question can be closed now.

Cannot turn on input method on a SDL2 created window

I wrote a test program for SDL2 text event handling, and the input method cannot be turned on when I'm focusing on the window created by SDL2.
I'm testing that on Linux with Xfce desktop and Fcitx input method engine.
The code is simple:
#include <SDL.h>
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
SDL_Window* window = SDL_CreateWindow("sdl text test", 50, 50, 400, 400, SDL_WINDOW_OPENGL);
SDL_StartTextInput();
while (1)
{
// process events
SDL_Event event{};
bool should_exit = false;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
should_exit = true;
break;
case SDL_TEXTEDITING:
printf("text edit: %s %d %d\n", event.edit.text, event.edit.start, event.edit.length);
break;
case SDL_TEXTINPUT:
printf("text input: %s\n", event.text.text);
break;
}
}
if (should_exit) break;
SDL_Delay(20);
}
SDL_StopTextInput();
}
I have a brief look on SDL2's documents, but failed to find anything related with keyboard grabbing.
try delete
videodata->ime_uilesss = UILess_SetupSinks(videodata);
in function IME_Init of SDL_windowskeyboard.c.
It's ugly, but works.
If videodata->ime_uiless == SDL_False,
then windows will show input method,
else the sdl2 will render and show input method.
I'm using Windows 10 + SDL and was looking at SDL support for the IME under Windows, and have no idea how it could possibly work considering the IME_Render/IME_Present function are never called in SDL codebase.
Compiling SDL with #define SDL_DISABLE_WINDOWS_IME in SDL_windowskeyboard.c fixed it for me (xwang's suggestion will lead to a similar result).
I don't know why but it may do the trick: build SDL2 yourself.
I once use SDL2 comes with Ubuntu apt repo, libsdl2-dev/bionic-updates,now 2.0.8+dfsg1-1ubuntu1.18.04.1 amd64 . IME cannot be shown or switched.
After I replace with myself-built SDL2 lib(same version 2.0.8), IME works good.

X11 key press translator

I would like to make a key press translator that would "convert" one key press to another, eg. Ctrl+T would be translated to Ctrl+X. I would like it to make "gobal"; to make it work in any application.
As a proof of concept I'm experimenting with the code below but it doesn't work. The problem is that when I capture a key press I send out another key press that is again captured by my code... I'm getting an infinite loop (the counter is there only to break out of the infinite loop).
How should I send out key press event from a key press event handler?
#include <stdio.h>
#include <X11/Xlib.h>
#include <xdo.h>
#include <X11/extensions/XTest.h>
int main(void)
{
Display *dpy = XOpenDisplay(0x0);
XEvent ev;
int counter;
xdo_t *xdo = xdo_new(NULL);
XGrabKeyboard(dpy, DefaultRootWindow(dpy), False,
GrabModeAsync, GrabModeAsync,CurrentTime);
for(counter = 0; counter < 10; counter++)
{
XNextEvent(dpy, &ev);
if(ev.type == KeyPress) {
XUngrabKeyboard(dpy, CurrentTime);
printf("%d %d\n", ev.xkey.keycode, ev.xany.send_event);
xdo_keysequence(xdo, CURRENTWINDOW, "A", 0);
}
}
return 0;
}

Win32 console problem

is it possible to create a program that works as console application if started from the console and works as windows program (with GUI) when started otherwise?
If it is possible - how can I do that?
regards
Tobias
If you set the program up to build as a GUI program you can then attempt to attach to the console using AttachConsole(). You you attach OK then you were started from a console and you can proceed to redirect your standard handles to the newly attached console.
In this way you can start up and see if you are being started from a console that you can attach to and if so become a console program. If you cant attach you can show a GUI.
I've had some success with this, the main problem I have is redisplaying the command window's prompt when my program exits (which is how normal console programs operate), but I expect you could do something clever (read the console buffer on start up and find the prompt to redisplay when you exit?) if you really wanted to ...
If you need the program to act as a console application (e.g. print the usage information to the console) you must complile as a console application. A windows application will not have access to the console and cmd.exe will not wait for it to finish before printing the prompt and accepting the next command.
The best solution is to have two versions, one for command line and one for the GUI (which users usually run via a link on the desktop or start menu).
If you insist on using a single binary you will have to live with a console window appearing, at least for a short time. You can get rid of the console window using
FreeConsole();
You can tell that your application was run from GUI if it is the only process attached to the console. You can use GetConsoleProcessList to find the list of processes attached to the console.
This is the answer from Dan Tillett and it is remarkably effective. No flashes, no .com and .exe to trick cmd.exe. Seems to work flawlessly typing the command, in a .bat file, with focus, without focus and as double-click GUI app.
It's the bees knees!
Here is web page describing it, but I've posted it here because if that page goes 404 next month or 2 years from now, the excellent and "most complete" solution I've seen would be "off the grid".
http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/
#define WINVER 0x0501 // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
// Attach output of application to parent console
static BOOL attachOutputToConsole(void) {
HANDLE consoleHandleOut, consoleHandleError;
int fdOut, fdError;
FILE *fpOut, *fpError;
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
//redirect unbuffered STDOUT to the console
consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE);
fdOut = _open_osfhandle((intptr_t)consoleHandleOut, _O_TEXT);
fpOut = _fdopen(fdOut, "w" );
*stdout = *fpOut;
setvbuf(stdout, NULL, _IONBF, 0 );
//redirect unbuffered STDERR to the console
consoleHandleError = GetStdHandle(STD_ERROR_HANDLE);
fdError = _open_osfhandle((intptr_t)consoleHandleError, _O_TEXT);
fpError = _fdopen(fdError, "w" );
*stderr = *fpError;
setvbuf(stderr, NULL, _IONBF, 0 );
return TRUE;
}
//Not a console application
return FALSE;
}
//Send the "enter" to the console to release the command prompt on the parent console
static void sendEnterKey(void) {
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
//Send the "Enter" key
ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "Enter" key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) {
int argc = __argc;
char **argv = __argv;
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nCmdShow);
BOOL console;
int i;
//Is the program running as console or GUI application
console = attachOutputToConsole();
if (console) {
//Print to stdout
printf("Program running as console application\n");
for (i = 0; i < argc; i++) {
printf("argv[%d] %s\n", i, argv[i]);
}
//Print to stderr
fprintf(stderr, "Output to stderr\n");
}
else {
MessageBox(NULL, "Program running as windows gui application",
"Windows GUI Application", MB_OK | MB_SETFOREGROUND);
}
//Send "enter" to release application from the console
//This is a hack, but if not used the console doesn't know the application has returned
//"enter" only sent if the console window is in focus
if (console && GetConsoleWindow() == GetForegroundWindow()){
sendEnterKey();
}
return 0;
}
The program itself will never know how it was started. Unless you are willing to pass an execution arguments to the program. For example: program.exe -GUI ... you can capture the passed parameters and decide how the program should run based on parameters passed.
your program whould be something like:
class MainClass
{
public static int Main(string[] args)
{
// Test if input arguments were supplied:
if(args[0]=="GUI")
new myGUI().show(); //runs an instance of your gui
else
//you know what should go here
}
}
You can sort of guess whether you are started from the console or not by doing this:
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y;
It's a guess -- if your cursor position is not 0,0 than you are in a console and can work as a console app. Otherwise go and create your windows.
Another way to guess is to look at the process tree and see what process launched your app. If it is cmd.exe go in console mode, otherwise go into GUI mode.
Make it a console application and put this into the code:
void ConsoleWindowVisible(bool show)
{
DWORD dummy;
if
(
!show && // Trying to hide
GetConsoleProcessList(&dummy, 1) == 1 // Have our own console window
)
ShowWindow(GetConsoleWindow, SW_HIDE); // Hide the window
else // Trying to show or use parent console window
ShowWindow(GetConsoleWindow, SW_NORMAL); // Show the window
}
int main(int argc, char** argv)
{
ConsoleWindowVisible(false);
}
Cheers.
gor.f.gyolchanyan#gmail.com

Resources