How to use use XNextEvent, XPeekEvent and XPutBackEvent - linux

I am trying to develop a little Linux application to perform measurements directly on the screen i.e. to measure distances and angles in images, documents etc.
To this end I was inspired by How to listen for mouse events in Linux?
and thought I could use XNextEvent or XPeekEvent and possibly XPutBackEvent.
This program responds nicely to mouse events but since it uses XNextEvent the bucket stops there and the event is not sent to the target window and the mouse becomes useless and if I use XPutBackEvent the same event comes back again.
To fix this I replaced XNextEvent with XPeekEvent, which is supposed to send the event up the ladder. This didn't help but made things worse sending an endless stream of the same event, filtering
out equal events didn't help either.
Thanks in advance for any tip to solve this problem.
The problem is basically that the events do not disappear and I don't know how to get rid of them in order to be able to use the mouse. The code below is copied from
How to listen for mouse events in Linux? and somewhat modified.
#include <stdio.h>
#include <X11/Xlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
char *key_name[] = {
"first",
"second (or middle)",
"third",
"fourth", // :D
"fivth" // :|
};
int main(int argc, char **argv)
{
Display *display;
XEvent xevent,oldevent;
Window window;
long unsigned int buttontime=0;
if( (display = XOpenDisplay(NULL)) == NULL )
return -1;
window = DefaultRootWindow(display);
XAllowEvents(display, AsyncBoth, CurrentTime);
XGrabPointer(display,
window,
1,
//PointerMotionMask |
ButtonPressMask | ButtonReleaseMask ,
GrabModeAsync,
GrabModeAsync,
None,
None,
CurrentTime);
while(1)
{
XNextEvent(display, &xevent);
//XPeekEvent(display, &xevent);
switch (xevent.type) {
/*case MotionNotify:
printf("Mouse move : [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
break;*/
case ButtonPress:
//if ((buttontime <= xevent.xbutton.time))
{
printf("Button pressed : %s\n", key_name[xevent.xbutton.button - 1]);
printf("timevent %lu\n",xevent.xbutton.time);
printf("timeold %lu\n",buttontime);
buttontime = xevent.xbutton.time;
buttontime++;
}
break;
case ButtonRelease:
printf("Button released : %s\n", key_name[xevent.xbutton.button - 1]);
break;
}
// XPutBackEvent(display, &xevent);
sleep(1);
}
return 0;
}

Related

Catching SIGUSR1 with sigtimedwait()

I'm not new to programming, but pretty new to Linux. I'm trying to use signals to asynchronously catch a push on a button, like this:
Run a worker thread which raises SIGUSR1 when the button is pushed.
Run a loop (main thread) around sigtimedwait() that will rotate info every two seconds (as long as the button is not pushed) or break (when the button is pushed).
According to the notes on sigtimedwait(), one should block the signals you want to wait for, then call sigtimedwait(). But I never see sigtimedwait() catching the blocked signals. I have run the code below in a few ways to see what happens with different scenarios:
Call to pthread_sigmask() disabled, call to signal() disabled,
result: programs exits with message "User defined signal 1".
Call to pthread_sigmask() disabled, call to signal() enabled, result:
message "Button 1 pressed sync1 hit" appears, sigtimedwait() always
returns EAGAIN.
Call to pthread_sigmask() enabled, call to signal() disabled, result:
message "Button 1 pressed" appears, sigtimedwait() always returns
EAGAIN.
Call to pthread_sigmask() enabled, call to signal() enabled, result
of course same as previous because the handler will not be called.
All as expected, except for the fact that sigtimedwait() doesn't seem to catch the signal when it's pending.
I've looked into similar code, e.g. this. But I don't understand how that particular code could work: SIGUSR1 isn't blocked, so raising that should immediately terminate the program (the default action for SIGUSR1).
It looks like I'm missing something here. What am I doing wrong? Or is the whole idea of using raise() in a worker thread wrong? I'm running this on a Raspberry Pi 3 with Raspbian Stretch (Debian 9.1), could there be a problem in that?
[I know printf() shouldn't be used in a signal handler, but for this purpose it works]
Any help appreciated, thx!
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#define PIN_BUTTON1 RPI_V2_GPIO_P1_22 // GPIO #24
// Thread function
void* check_button1(void* param)
{
while (true)
{
if (bcm2835_gpio_lev(PIN_BUTTON1) == HIGH)
{
printf("Button 1 pressed ");
raise(SIGUSR1);
}
delay(250);
}
}
// Signal handler, if applied
volatile sig_atomic_t usr_interrupt = 0;
void sync1(int sig)
{
printf("sync1 hit ... ");
usr_interrupt = 1;
}
int main(int argc, char** argv)
{
if (!bcm2835_init())
{
printf("Failed to initialize BCM2835 GPIO library.");
return 1;
}
bcm2835_gpio_fsel(PIN_BUTTON1, BCM2835_GPIO_FSEL_INPT);
sigset_t sigusr;
sigemptyset(&sigusr);
sigaddset(&sigusr, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &sigusr, NULL);
signal(SIGUSR1, sync1);
// Start the threads to read the button pin state
pthread_t th1;
pthread_create(&th1, NULL, check_button1, NULL);
// Create a two second loop
struct timespec timeout = { 0 };
timeout.tv_sec = 2;
usr_interrupt = 0;
int nLoopCount = 0;
while (true)
{
printf("Loop %d, waiting %d seconds ... ", ++nLoopCount, timeout.tv_sec);
int nResult = sigtimedwait(&sigusr, NULL, &timeout);
if (nResult < 0)
{
switch (errno)
{
case EAGAIN: printf("EAGAIN "); break; // Time out, no signal raised, next loop
case EINTR: printf("EINTR "); break; // Interrupted by a signal other than SIGCHLD.
case EINVAL: printf("EINVAL "); exit(1); // Invalid timeout
default: printf("Result=%d Error=%d ", nResult, errno); break;
}
printf("\n");
continue;
}
printf("Signal %d caught\n", nResult);
}
return 0;
}
ADDENDUM: In the meantime, I got this working by replacing raise(SIGUSR1) by kill(getpid(), SIGUSR1). Strange, because according to the manual raise(x) is equivalent to kill(getpid, x) in single-threaded programs and to pthread_kill(pthread_self(), x) in multi-threaded ones. Replacing raise(SIGUSR1) by pthread_kill(pthread_self, SIGUSR1) has no effect. If anyone could explain this to me ...

getch not working without initscr

I gone through the Documentation of NCURSES. I am not getting that if I use getch without initscr then why this program is not working. Is there any other approach to get arrow keys input without clearing screen (that initscr do).
#include <ncurses.h>
#include <unistd.h>
int main()
{
int ch;
//initscr();
//raw();
//keypad(stdscr, TRUE);
//noecho();
while(1)
{
ch = getch();
switch(ch)
{
case KEY_UP:
printw("\nUp Arrow");
break;
case KEY_DOWN:
printw("\nDown Arrow");
break;
case KEY_LEFT:
printw("\nLeft Arrow");
break;
case KEY_RIGHT:
printw("\nRight Arrow");
break;
}
if(ch == KEY_UP)
break;
}
//endwin();
}
Alternatively you may use change the terminal attribute through tcsetattr in termios. If you cycle between the canonical mode (requires new line for the process to begin) and non-canonocal mode (Keypress is more than enough).
The following program works as follows - THe process waits for user input. If up arrow key is pressed, it prints 'Arrow key pressed' and exits. If something else is pressed, it waits for the user to press Enter and then prints the user inpu. Exits after the inut is printed.
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
struct termios oldt, newt;
char ch, command[20];
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
while(1)
{
ch = getchar();
if (ch == '\033')
{ printf("Arrow key\n"); ch=-1; break;}
else if(ch == -1) // by default the function returns -1, as it is non blocking
{
continue;
}
else
{
break;
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if(ch != EOF)
{
ungetc(ch,stdin);ith
putchar(ch);
scanf("%s",command);
printf("\n%s\n",command);
return 1;
}
return 0;
}
getch is the same as wgetch(stdscr). It assumes that the screen has been initialized. ncurses (any curses implementation) has to do a couple of things to make wgetch usable:
read the terminal description
initialize the terminal I/O modes
allocate a screen to draw on.
The last is because wgetch does a wrefresh on the window for which it was called, before doing a read.
You could use newterm with filter to avoid clearing the screen, and doing line-oriented input. The filter program in ncurses-examples demonstrates how to do this.
I have a solution without ncurses
You can use simple-getch like this:
t_key keys[] = {
{"[A", K_UP},
{"[B", K_DOWN},
{"[D", K_LEFT},
{"[C", K_RIGHT},
{NULL, K_UNK},
};
int key;
ch_init();
while ((key = ch_get(keys)) != K_BACK)
{
printf("%d\n", key);
}
ch_end();
keys array is a list of escape sequences which will be used, (when you type an arrow key in a terminal, it will write an escape key followed by multiples characters to define the key.)
This sequences may/will change between terminals, you should use termcap to properly set this sequences.

How to listen for mouse events in Linux?

I want to write a program that would run in the background and log pointer's position when a mouse click occured. I tried to search for it in Google, but results were for NCurses and some GUI libraries. Is there any way that I could write a program that listens to mouse events in the background? C and/or Python ways are prefered.
Here is an example for logging mouse position, clicks and releases:
#include <stdio.h>
#include <X11/Xlib.h>
char *key_name[] = {
"first",
"second (or middle)",
"third",
"fourth", // :D
"fivth" // :|
};
int main(int argc, char **argv)
{
Display *display;
XEvent xevent;
Window window;
if( (display = XOpenDisplay(NULL)) == NULL )
return -1;
window = DefaultRootWindow(display);
XAllowEvents(display, AsyncBoth, CurrentTime);
XGrabPointer(display,
window,
1,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask ,
GrabModeAsync,
GrabModeAsync,
None,
None,
CurrentTime);
while(1) {
XNextEvent(display, &xevent);
switch (xevent.type) {
case MotionNotify:
printf("Mouse move : [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
break;
case ButtonPress:
printf("Button pressed : %s\n", key_name[xevent.xbutton.button - 1]);
break;
case ButtonRelease:
printf("Button released : %s\n", key_name[xevent.xbutton.button - 1]);
break;
}
}
return 0;
}
Compile it using:
$ gcc mouse.c -o mouse -lX11
$ ./mouse
Mouse move : [664, 395]
Mouse move : [665, 393]
Mouse move : [666, 393]
Mouse move : [666, 392]
Mouse move : [664, 392]
Mouse move : [664, 393]
Mouse move : [664, 395]
Button pressed : first
Button released : first
Button pressed : third
Button released : third
^C
$
Look also here Keyboard and Pointer Events and there are a lot of information in The Xlib Manual.
similar question: How can I capture mouseevents and keyevents using python in background on linux
The above answer is using python binding for evdev. this binding is available for capturing mouse event.

Ignore auto repeat in X11 applications

If you press and hold a key in X11 while AutoRepeat is enabled, you continuously receive KeyPress and KeyRelease events. I know that AutoRepeat can be disabled using the function XAutoRepeatOff(), but this changes the setting for the whole X server. Is there a way to either disable AutoRepeat for a single application or to ignore repeated keystrokes?
What I'm looking for is a single KeyPress event when a key is pressed and a single KeyRelease event when a key is released, without interfering with the X server's AutoRepeat setting.
Here's a minimal example to get you going (mostly from the Beginner Xlib Tutorial):
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
Display *dis;
Window win;
XEvent report;
int main ()
{
dis = XOpenDisplay (NULL);
// XAutoRepeatOn(dis);
win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500,
0, BlackPixel (dis, 0), BlackPixel (dis, 0));
XSelectInput (dis, win, KeyPressMask | KeyReleaseMask);
XMapWindow (dis, win);
XFlush (dis);
while (1)
{
XNextEvent (dis, &report);
switch (report.type)
{
case KeyPress:
fprintf (stdout, "key #%ld was pressed.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
case KeyRelease:
fprintf (stdout, "key #%ld was released.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
}
}
return (0);
}
When you receive a key release and the next event is a key press of the same key combination, then it's auto-repeat and the key wasn't acutally released. You can use code like this to peek next event
if (event->type == KeyRelease && XEventsQueued(disp, QueuedAfterReading))
{
XEvent nev;
XPeekEvent(disp, &nev);
if (nev.type == KeyPress && nev.xkey.time == event->xkey.time &&
nev.xkey.keycode == event->xkey.keycode)
{
/* Key wasn’t actually released */
}
}
You can use the XkbSetDetectableAutorepeat function to tell the X server to only send KeyRelease events when the user actually releases the key - when you don't want autorepeat events, then you discard any KeyPress without matching KeyRelease.
For your reference, here's a working minimal example that deletes auto-repeated KeyPress events. Thank you, kralyk!
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
Display *dis;
Window win;
XEvent report;
int main ()
{
dis = XOpenDisplay (NULL);
// XAutoRepeatOn(dis);
win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500,
0, BlackPixel (dis, 0), BlackPixel (dis, 0));
XSelectInput (dis, win, KeyPressMask | KeyReleaseMask);
XMapWindow (dis, win);
XFlush (dis);
while (1)
{
XNextEvent (dis, &report);
switch (report.type)
{
case KeyPress:
fprintf (stdout, "key #%ld was pressed.\n",
(long) XLookupKeysym (&report.xkey, 0));
break;
case KeyRelease:
{
unsigned short is_retriggered = 0;
if (XEventsQueued(dis, QueuedAfterReading))
{
XEvent nev;
XPeekEvent(dis, &nev);
if (nev.type == KeyPress && nev.xkey.time == report.xkey.time &&
nev.xkey.keycode == report.xkey.keycode)
{
fprintf (stdout, "key #%ld was retriggered.\n",
(long) XLookupKeysym (&nev.xkey, 0));
// delete retriggered KeyPress event
XNextEvent (dis, &report);
is_retriggered = 1;
}
}
if (!is_retriggered)
fprintf (stdout, "key #%ld was released.\n",
(long) XLookupKeysym (&report.xkey, 0));
}
break;
}
}
return (0);
}
You could set a timer when a key is pressed or released and ignore KeyPress and KeyRelease events that occur within the repetition interval.
another approach. it works for me.
char keyz[1024] = {0};
bool physical;
XEvent event, nev;
while (!quit) {
XNextEvent(display, &event);
...
switch(event.type) {
case KeyPress:
physical = (keyz[event.xkey.keycode] == 0);
keyz[event.xkey.keycode] = 1;
keyboard(event.xkey.window, true, event.xkey.keycode, physical);
break;
case KeyRelease:
physical = true;
if (XPending(display)) {
XPeekEvent(display, &nev);
if (nev.type == KeyPress && nev.xkey.time == event.xkey.time
&& nev.xkey.keycode == event.xkey.keycode) physical = false;
}
if (physical) keyz[event.xkey.keycode] = 0;
keyboard(event.xkey.window, false, event.xkey.keycode, physical);
break;
...
}
Here's the solution I came up with.
XEvent event;
while(1)
{
XNextEvent(display, &event);
switch(event.type)
{
// Other cases
case ...:
...
break;
...
// On KeyRelease
case KeyRelease:
{
char keys[32];
XQueryKeymap(display, keys);
if(!(keys[event.xkey.keycode>>3] & (0x1 << (event.xkey.keycode % 8))))
{
// Stuff to do on KeyRelease
...
}
}
break;
// On KeyPress
case KeyPress:
// Stuff to do on KeyPress
...
break;
default:
...
}
}
So, everytime I get a KeyRelease event, I use XQueryKeymap which will copy to keys the bits of pressed keys (8 different keys by char).
For the ones who are not used to work with bitwise operatos and shift operator, here's a simple explanation:
keys[event.xkey.keycode>>3] search for index event.xkey.keycode / 8 using "right shift operator" (that allows for "integer division" by 2, 4, 8, 16 and so on, without type cast to float or double and back to integer).
0x1 << (event.xkey.keycode % 8) does the oposite. It multiplies the value of 0x1 (== 1) by 2 raised to (event.xkey.keycode % 8)
The & bitwise operator between keys[event.xkey.keycode>>3] and 0x1 << (event.xkey.keycode % 8) will compare if the only bit set in the right side operand is set to 1 inside this array index. If so, the key is being pressed.
Finally you just enclose it in (), with a ! right before and if the result becomes true, you're not pressing that key anymore.
One final Note: To use this method, you need to keep feeding the XServer with events. If not, XQueryKeymap will freze until it does (better use with threads).

Multithreading Semaphore

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
void *thread_function(void *arg);
sem_t bin_sem;
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = sem_init(&bin_sem, 0, 0);
if (res != 0) {
perror(“Semaphore initialization failed”);
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror(“Thread creation failed”);
exit(EXIT_FAILURE);
}
printf(“Input some text. Enter ‘end’ to finish\n”);
while(strncmp(“end”, work_area, 3) != 0) {
fgets(work_area, WORK_SIZE, stdin);
sem_post(&bin_sem);
}
printf(“\nWaiting for thread to finish...\n”);
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror(“Thread join failed”);
exit(EXIT_FAILURE);
}
printf(“Thread joined\n”);
sem_destroy(&bin_sem);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
sem_wait(&bin_sem);
while(strncmp(“end”, work_area, 3) != 0) {
printf(“You input %d characters\n”, strlen(work_area) -1);
sem_wait(&bin_sem);}
pthread_exit(NULL);
}
In the program above, when the semaphore is released using sem_post(), is it
possible that the fgets and the counting function in thread_function execute
simultaneously .And I think this program fails in allowing the second thread
to count the characters before the main thread reads the keyboard again.
Is that right?
The second thread will only read characters after sem_wait has returned, signaling that a sem_post has been called somewhere, so I think that is fine.
As for fgets and the counting function, those two could be running simultaneously.
I would recommend a mutex lock on the work_area variable in this case, because if the user is editing the variable in one thread while it is being read in another thread, problems will occur.
You can either use a mutex or you can use a semaphore and set the initial count on it to 1.
If you implement a mutex or use a semaphore like that though, make sure to put the mutex_lock after sema_wait, or else a deadlock may occur.
In this example you want to have a mutex around the read & writes of the shared memory.
I know this is an example, but the following code:
fgets(work_area, WORK_SIZE, stdin);
Should really be:
fgets(work_area, sizeof(work_area), stdin);
If you change the size of work_area in the future (to some other constant, etc), it's quite likely that changing this second WORK_SIZE could be missed.

Resources