Disable queueing execute in C - c

I have problem with my sleep function in C.
When i use in this code sleep function like this:
while(1) {
XNextEvent(display, &xevent);
switch (xevent.type) {
case MotionNotify:
break;
case ButtonPress:
printf("Button click: [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
sleep(5);
break;
case ButtonRelease:
break;
}
It doesn't works well for me because printf("button click") is executing all time but slower.
How to print "button click x y" once and stop listening for click for 5 second?

I think you're looking for something like:
/* ignore_click is the time until mouse click is ignored */
time_t ignore_click = 0;
while(1) {
XNextEvent(display, &xevent);
switch (xevent.type) {
case MotionNotify:
break;
case ButtonPress:
{
time_t now;
/* we read current time */
time(&now);
if (now > ignore_click)
{
/* now is after ignore_click, mous click is processed */
printf("Button click: [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
/* and we set ignore_click to ignore clicks for 5 seconds */
ignore_click = now + 5;
}
else
{
/* click is ignored */
}
}
break;
case ButtonRelease:
break;
}
}
The code written above will ignore clicks for 4 to 5 seconds: the time_t type is a second precision structure...
To get more acurate time, you could use struct timeval or struct timespec structure. I do not use them in my example to keep it clear.

Related

Track X11 enter / leave events

I need to be notified when mouse enters or leaves a window (any window, that's why I'm grabbing on the root window). I have a solution using xcb_input_xi_grab_device() but it works only half way. When I run the app, I do get enter/leave events but the mouse pointer disappears and it consumes all mouse events and other windows stop (children of the root window) reacting to clicks.
Using XCB_INPUT_GRAB_OWNER_OWNER should allow passing-through the events but it doesn't work.
app.c:
#include <stdio.h>
#include <xcb/xcb.h>
#include <xcb/xinput.h>
xcb_input_device_id_t find_device(xcb_connection_t *conn)
{
xcb_input_xi_query_device_reply_t *reply = xcb_input_xi_query_device_reply(
conn, xcb_input_xi_query_device(conn, XCB_INPUT_DEVICE_ALL), NULL);
xcb_input_xi_device_info_iterator_t iter =
xcb_input_xi_query_device_infos_iterator(reply);
xcb_input_device_id_t device_id;
int found = 0;
while (iter.rem) {
xcb_input_xi_device_info_t *device = iter.data;
switch (device->type) {
case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER:
case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
device_id = device->deviceid;
found = 1;
break;
}
if (found) {
break;
}
xcb_input_xi_device_info_next(&iter);
}
free(reply);
return device_id;
}
int main()
{
xcb_connection_t *conn = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
uint32_t mask =
XCB_INPUT_XI_EVENT_MASK_ENTER | XCB_INPUT_XI_EVENT_MASK_LEAVE;
xcb_generic_error_t *error;
xcb_input_xi_grab_device_reply_t *reply = xcb_input_xi_grab_device_reply(
conn,
xcb_input_xi_grab_device(conn, screen->root, XCB_CURRENT_TIME,
XCB_CURSOR_NONE, find_device(conn),
XCB_INPUT_GRAB_MODE_22_ASYNC,
XCB_INPUT_GRAB_MODE_22_ASYNC,
XCB_INPUT_GRAB_OWNER_OWNER, 1, &mask),
&error);
free(reply);
if (error) {
printf("failed to grab device\n");
free(error);
return -1;
}
xcb_flush(conn);
xcb_generic_event_t *event;
while ((event = xcb_wait_for_event(conn))) {
xcb_ge_event_t *generic_event = event;
switch (generic_event->event_type) {
case XCB_INPUT_ENTER:
printf("enter\n");
break;
case XCB_INPUT_LEAVE:
printf("leave\n");
break;
}
free(event);
}
return -1; // never reached
}
cc -O2 app.c -o app `pkg-config --cflags --libs xcb xcb-xinput`
I also tried to achieve it with xcb_grab_button(), xcb_input_xi_select_events(), xcb_input_xi_passive_grab_device() or xcb_grab_pointer() but then the problem is the same. Either the mouse events are not passed-through or I don't receive enter/leave events at all.

Console does not record mouse wheel events

I am working on a TUI program with console on Windows 10. I would like to implement widgets that allow vertical scrolling when the user interacts with the mouse wheel. However the console does not record any of the mouse wheel events.
The sample code below from Microsoft does not record mouse wheel events even though my mouse wheel is working since windows manage to scroll the console content. All other mouse input events are working (click, move...).
#include <windows.h>
#include <stdio.h>
HANDLE hStdin;
DWORD fdwSaveOldMode;
VOID ErrorExit(LPCSTR);
VOID KeyEventProc(KEY_EVENT_RECORD); // the "case MOUSE_WHEELED:" in this function never happens
VOID MouseEventProc(MOUSE_EVENT_RECORD);
VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD);
int main(VOID)
{
DWORD cNumRead, fdwMode, i;
INPUT_RECORD irInBuf[128];
int counter=0;
// Get the standard input handle.
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
ErrorExit("GetStdHandle");
// Save the current input mode, to be restored on exit.
if (! GetConsoleMode(hStdin, &fdwSaveOldMode) )
ErrorExit("GetConsoleMode");
// Enable the window and mouse input events.
fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
if (! SetConsoleMode(hStdin, fdwMode) )
ErrorExit("SetConsoleMode");
// Loop to read and handle the next 100 input events.
while (counter++ <= 100)
{
// Wait for the events.
if (! ReadConsoleInput(
hStdin, // input buffer handle
irInBuf, // buffer to read into
128, // size of read buffer
&cNumRead) ) // number of records read
ErrorExit("ReadConsoleInput");
// Dispatch the events to the appropriate handler.
for (i = 0; i < cNumRead; i++)
{
switch(irInBuf[i].EventType)
{
case KEY_EVENT: // keyboard input
KeyEventProc(irInBuf[i].Event.KeyEvent);
break;
case MOUSE_EVENT: // mouse input
MouseEventProc(irInBuf[i].Event.MouseEvent);
break;
case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing
ResizeEventProc( irInBuf[i].Event.WindowBufferSizeEvent );
break;
case FOCUS_EVENT: // disregard focus events
case MENU_EVENT: // disregard menu events
break;
default:
ErrorExit("Unknown event type");
break;
}
}
}
// Restore input mode on exit.
SetConsoleMode(hStdin, fdwSaveOldMode);
return 0;
}
VOID ErrorExit (LPCSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
// Restore input mode on exit.
SetConsoleMode(hStdin, fdwSaveOldMode);
ExitProcess(0);
}
VOID KeyEventProc(KEY_EVENT_RECORD ker)
{
printf("Key event: ");
if(ker.bKeyDown)
printf("key pressed\n");
else printf("key released\n");
}
VOID MouseEventProc(MOUSE_EVENT_RECORD mer)
{
#ifndef MOUSE_HWHEELED
#define MOUSE_HWHEELED 0x0008
#endif
printf("Mouse event: ");
switch(mer.dwEventFlags)
{
case 0:
if(mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
printf("left button press \n");
}
else if(mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
{
printf("right button press \n");
}
else
{
printf("button press\n");
}
break;
case DOUBLE_CLICK:
printf("double click\n");
break;
case MOUSE_HWHEELED:
printf("horizontal mouse wheel\n");
break;
case MOUSE_MOVED:
printf("mouse moved\n");
break;
case MOUSE_WHEELED:// this case never shows up when I use the wheel
printf("vertical mouse wheel\n");
break;
default:
printf("unknown\n");
break;
}
}
VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD wbsr)
{
printf("Resize event\n");
printf("Console screen buffer is %d columns by %d rows.\n", wbsr.dwSize.X, wbsr.dwSize.Y);
}

Take input in an infinte loop in c

I am writing a C program to blink LED for Raspberry Pi. Its like (i) Blink LED (2) Stop blinking it.
Now while the LED is blinking, if I press 2 it should stop blinking. How to do it ?
If I include scanf inside the code will stop blinking.
while(1)
{
printf("Enter a command \n 1.Blink Led\n 2. Stop blinking\n");
scanf("%d",&choice);
if(choice==1)
for (;;)
{
digitalWrite (LED, HIGH) ; // On
delay (500) ; // mS
digitalWrite (LED, LOW) ; // Off
delay (500) ;
// If i press 2 the led should stop blinking
}
else if(choice==2){
digitalWrite (LED, LOW) ;
}
if you don't want to interrupt the Blinking you should try to run the blinking in a parallel process using pthread_t.
i really want to give you the code but i'm not on my PC at the moment.
Use poll:
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
int main()
{
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
unsigned char c, blink=1, on =1, q=1;
while(q) {
if( poll(&mypoll, 1, 500) ) {
c=getchar();
switch(c) {
case '1':
blink = 1;
break;
case '2':
blink =0;
break;
case 'q':
q= 0;
break;
}
}
else{
if (blink) {
if (on)
on =0;
else
on =1;
}
printf("%u\n",on);
}
}
return 0;
}
replace the on parameter with the led functions.

XCB – Not receiving motion notify events on all windows

I am trying to be notified about any pointer motion. Since I don't want to run as the window manager, I need to set XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION on all windows which I do both on startup and when I get a create notify event.
This seems to work fine in general and I receive motion notify events on all windows. However, somehow, this isn't true for Google Chrome windows. I checked the event mask by explicitly querying it afterwards and it is correctly set. I also don't see anything unusual in the propagation mask.
What could cause Google Chrome to not report motion notify events? AFAIK, the X protocol doesn't allow that except for active pointer grabs which Chrome surely doesn't have.
Here is how I register myself on all existing windows. I call register_events on the root window and whenever I receive a create notify event as well:
static void register_events(xcb_window_t window) {
xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(connection,
window, XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_LEAVE_WINDOW });
xcb_generic_error_t *error = xcb_request_check(connection, cookie);
if (error != NULL) {
xcb_disconnect(connection);
errx(EXIT_FAILURE, "could not subscribe to events on a window, bailing out");
}
}
static void register_existing_windows(void) {
xcb_query_tree_reply_t *reply;
if ((reply = xcb_query_tree_reply(connection, xcb_query_tree(connection, root), 0)) == NULL) {
return;
}
int len = xcb_query_tree_children_length(reply);
xcb_window_t *children = xcb_query_tree_children(reply);
for (int i = 0; i < len; i++) {
register_events(children[i]);
}
xcb_flush(connection);
free(reply);
}
The Chrome windows appear to be comprised of quite the tree of nested child windows. It appears you'll need to walk the tree of windows and monitor them all. This code picks up pointer motion events across the entirety of my Chrome windows:
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <X11/Xlib.h>
static void register_events(xcb_connection_t *conn,
xcb_window_t window) {
xcb_void_cookie_t cookie =
xcb_change_window_attributes_checked(conn,
window, XCB_CW_EVENT_MASK,
(uint32_t[]) {
XCB_EVENT_MASK_POINTER_MOTION });
xcb_generic_error_t *error = xcb_request_check(conn, cookie);
if (error != NULL) {
xcb_disconnect(conn);
exit(-1);
}
}
static void register_existing_windows(xcb_connection_t *conn,
xcb_window_t root) {
int i, len;
xcb_window_t *children;
xcb_query_tree_reply_t *reply;
if ((reply = xcb_query_tree_reply(conn,
xcb_query_tree(conn, root), 0))
== NULL)
{
return;
}
len = xcb_query_tree_children_length(reply);
children = xcb_query_tree_children(reply);
for (i = 0; i < len; i++) {
register_events(conn, children[i]);
register_existing_windows(conn, children[i]);
}
xcb_flush(conn);
}
void main(void) {
int i=0;
/* Open the connection to the X server */
xcb_connection_t *conn = xcb_connect (NULL, NULL);
/* Get the first screen */
xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (conn)).data;
register_existing_windows(conn, screen->root);
while(1) {
xcb_generic_event_t *evt;
evt = xcb_wait_for_event(conn);
printf("%i\n", i++);
}
}
(That's just intended as proof of concept, and not very nice.)
While #Jay Kominek's answer was helpful and valid, I've come to realize now that using the Xinput extension provides a much better approach as it won't interfere with applications whatsoever.
Simply selecting on the entire tree causes all kinds of issues, e.g., hover doesn't work in Chrome anymore.
xcb provides xcb_grab_pointer to capture pointer event without registe on specific window.
#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>
void
print_modifiers (uint32_t mask)
{
const char **mod, *mods[] = {
"Shift", "Lock", "Ctrl", "Alt",
"Mod2", "Mod3", "Mod4", "Mod5",
"Button1", "Button2", "Button3", "Button4", "Button5"
};
printf ("Modifier mask: ");
for (mod = mods ; mask; mask >>= 1, mod++)
if (mask & 1)
printf(*mod);
putchar ('\n');
}
int
main ()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
xcb_generic_event_t *e;
uint32_t mask = 0;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
mask = XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION;
xcb_grab_pointer(c, false, screen->root, mask, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
xcb_flush (c);
while ((e = xcb_wait_for_event (c))) {
switch (e->response_type & ~0x80) {
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e;
print_modifiers(ev->state);
switch (ev->detail) {
case 4:
printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
case 5:
printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
default:
printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n",
ev->detail, ev->event, ev->event_x, ev->event_y);
}
break;
}
case XCB_BUTTON_RELEASE: {
xcb_button_release_event_t *ev = (xcb_button_release_event_t *)e;
print_modifiers(ev->state);
printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
ev->detail, ev->event, ev->event_x, ev->event_y);
break;
}
case XCB_MOTION_NOTIFY: {
xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)e;
printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
}
default:
/* Unknown event type, ignore it */
printf("Unknown event: %d\n", e->response_type);
break;
}
/* Free the Generic Event */
free (e);
}
return 0;
}

X: trigger events at fixed intervals

What's the best way of waiting a finite a mount of time for an expose event on X, then waking up and doing a redraw, even if not expose event has been received? The purpose is to have an opengl animation running at sometimes where at others I simply want to redraw if needed. Here is my code as I have it now, check below for pseudo-code of what I'm looking for:
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
need_redraw = True;
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
}
And this is a pseudo-example of what I would like:
bool animation_enabled = true;
XPostTimeoutEventEvery( 0.3 ); // <-- X will send a "Timeout"
// event each 0.3 seconds.
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
// Redraw if it is required
need_redraw = True;
break;
// -- here --
case Timeout:
// Otherwise, after 0.3 seconds, redraw anyway if
// the animation is running
if ( animation_enabled )
{
need_redraw = True;
}
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
// potentially change "animation_enabled" value
}
Just use a regular system timer; if a desired event doesn't arrive in time, just do whatever you want to do.
X is not an application framework, it's a display protocol. Timers are outside (of that) scope of X11.
Check here and the link provided in that answer.
XLib does not offer a "timed out" version of XNextEvent.
But, a timed out version can be easily implemented.
You will need a function
that checks if a file has been updated
within a given timeout,
you can implement it using select:
#include <sys/select.h>
static int wait_fd(int fd, double seconds)
{
struct timeval tv;
fd_set in_fds;
FD_ZERO(&in_fds);
FD_SET(fd, &in_fds);
tv.tv_sec = trunc(seconds);
tv.tv_usec = (seconds - trunc(seconds))*1000000;
return select(fd+1, &in_fds, 0, 0, &tv);
}
Then, you can use wait_fd
in the file descriptor returned by
ConnectionNumber(display)
to wait for an event
within a given time limit:
int XNextEventTimeout(Display *display, XEvent *event, double seconds)
{
if (XPending(display) || wait_fd(ConnectionNumber(display),seconds)) {
XNextEvent(display, event);
return 0;
} else {
return 1;
}
}
In your main loop,
you can use the XNextEventTimeout function
to wait for events within a given timeout.
If the timeout expires, you can simulate the desired event,
in you case an Expose event:
for (;;) {
if (XNextEventTimeout(dpy, &event, 1.)) {
/* Handle timeout "event"
* one option is to simulate an Expose event */
e.type = Expose;
e.xexpose.count = 0;
}
switch (event.type) {
case Expose:
/* Handle expose event */
break;
/* ... */
/* Handle other events */
}
}
A simpler solution is to use the non-blocking Xlib equivalents to XNextEvent. Here's what I use to check for X events each time through the frame loop:
mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
while (XCheckWindowEvent(xDisplay, xWin, mask, &evt) ||
XCheckTypedWindowEvent(xDisplay, xWin, ClientMessage, &evt)) {
/* Handle event */
}
Hope this helps. The full code is in my demo OpenGL/GLX program
http://cs.anu.edu.au/~Hugh.Fisher/3dteach/glxcube.tar

Resources