Consider this :
xinput --test 11 | grep "button press 1"
*11 is my Optical mouse index (could be anything else) and "button press 1" means left click.
When I click somewhere in the screen, that shows me this :
button press 1
No problem so far . But when I wanted to use the output of that as the input to my C program , I noticed that the stdin of the program after another level of pipe is always empty :
xinput --test 11 | grep "button press 1" | ./poll_test
Here's my poll_test code:
/*This is just a program to test polling functionality on stdin.
I've used other programs instead of this as well.
None of them were able to read the stdin */
#include <fcntl.h>
#include <stdio.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <unistd.h>
void main(int argc, char ** argv) {
int fd;
char buf[1024];
int bytes_read;
struct pollfd pfds[1];
while (1) {
pfds[0].fd = 0;
pfds[0].events = POLLIN;
poll(pfds, 1, -1);
if (pfds[0].revents & POLLIN) {
bytes_read = read(0, buf, 1024);
printf("%s\n" , buf);
if (!bytes_read) {
printf("stdin closed\n");
return;
}
write(1, buf, bytes_read);
}
}
}
It prints nothing despite of the clicks.
That is confusing.This is not a normal behavior. When I run this for example:
ls | grep a | grep b
It shows me the results successfully. The only difference is that the ls
here exits after it prints out to the stdout but that's not the case in the xinput version.
I spend a lot of time to write a script to play a beep in the event of a mouse click but that didn't work. So I wanted to use a C program because there's no polling functionality in bash.
As far as I know , working of the pipes in bash is something like this :
The second program (the right one in the pipe statement) gets executed until it wants to READ from its stdin and it stops going further until there's something to read from the STDIN.
With that in mind, the third program in the command I posted should be able to read the output.As it's the case when the first programs exits.
The next step would be to use libxcb directly instead of the command xinput if pipe problem doesn't work.
I'm totally confused. Any help would be much appreciated.
EDIT: I also tried using an intermediate file descriptor:
exec 3<&1
xinput --test 11 | grep -i "button press 1" >&3 | ./poll_test 3>&1
but didn't help.And also flushing the stdout forcibly doesn't work either :
xinput --test 11 | grep -i "button press 1" ; stdbuf -oL | ./poll_test
It seems grep
is changing its buffering behaviour depending on whether the output is a terminal or not. I don't know exactly why this happens, but --line-buffered
forces it to use line buffering (evaluating the expression as soon as the line ends):
xinput --test 11 | grep "button press 1" --line-buffered | ./poll_test
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With