How to read low level mouse click position in linux . - c++

I am using this code to read mouse events from the dev/input/event* in linux .
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>
#include <fcntl.h>
#define MOUSEFILE "/dev/input/event4"
int main()
{
int fd;
struct input_event ie;
if((fd = open(MOUSEFILE, O_RDONLY)) == -1) {
perror("opening device");
exit(EXIT_FAILURE);
}
while(read(fd, &ie, sizeof(struct input_event))) {
printf("time %ld.%06ld\ttype %d\tcode %d\tvalue %d\n",
ie.time.tv_sec, ie.time.tv_usec, ie.type, ie.code, ie.value);
}
return 0;
}
It gives me the results in the format :
time 1342517261.840285 type 2 code 0 value -1
'time' is the timestamp, it returns the time at which the event happened.
'code' is event code, for example REL_X or KEY_BACKSPACE, complete
list is in include/linux/input.h.
'value' is the value the event carries. Either a relative change for
EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
release, 1 for keypress and 2 for autorepeat.
when i click , i get the event but i don't get the position of the mouse on the screen , what is the way to get the position of the mouse on screen .
Edit 1:So as it turns out that i have to use the relative co-ordinates to get the mouse co-ordinates .I believe this is a common requirement so there might be libraries/pre-existing code that you can use to get the co-ordinates. Any info on this topic will be very useful .
Edit2 : SOLUTION
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>
#include <fcntl.h>
#include <X11/Xlib.h>
#define MOUSEFILE "/dev/input/event4"
int main()
{
int fd;
struct input_event ie;
Display *dpy;
Window root, child;
int rootX, rootY, winX, winY;
unsigned int mask;
dpy = XOpenDisplay(NULL);
XQueryPointer(dpy,DefaultRootWindow(dpy),&root,&child,
&rootX,&rootY,&winX,&winY,&mask);
if((fd = open(MOUSEFILE, O_RDONLY)) == -1) {
perror("opening device");
exit(EXIT_FAILURE);
}
while(read(fd, &ie, sizeof(struct input_event))) {
if (ie.type == 2) {
if (ie.code == 0) {
XQueryPointer(dpy,DefaultRootWindow(dpy),&root,&child,
&rootX,&rootY,&winX,&winY,&mask);
//rootX += ie.value;
}
else if (ie.code == 1) {
XQueryPointer(dpy,DefaultRootWindow(dpy),&root,&child,
&rootX,&rootY,&winX,&winY,&mask);
// rootY += ie.value;
}
printf("time%ld.%06ld\tx %d\ty %d\n",
ie.time.tv_sec, ie.time.tv_usec, rootX, rootY);
} else
printf("time %ld.%06ld\ttype %d\tcode %d\tvalue %d\n",
ie.time.tv_sec, ie.time.tv_usec, ie.type, ie.code, ie.value);
}
return 0;
}
XQueryPointer seems more convenient solution . Thanks , #perreal for the guidance .

You can get the initial position from X11, and use relative coordinates to track the pointer:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>
#include <fcntl.h>
#include <X11/Xlib.h>
#define MOUSEFILE "/dev/input/event6"
int main()
{
int fd;
struct input_event ie;
Display *dpy;
Window root, child;
int rootX, rootY, winX, winY;
unsigned int mask;
dpy = XOpenDisplay(NULL);
XQueryPointer(dpy,DefaultRootWindow(dpy),&root,&child,
&rootX,&rootY,&winX,&winY,&mask);
if((fd = open(MOUSEFILE, O_RDONLY)) == -1) {
perror("opening device");
exit(EXIT_FAILURE);
}
while(read(fd, &ie, sizeof(struct input_event))) {
if (ie.type == 2) {
if (ie.code == 0) { rootX += ie.value; }
else if (ie.code == 1) { rootY += ie.value; }
printf("time%ld.%06ld\tx %d\ty %d\n",
ie.time.tv_sec, ie.time.tv_usec, rootX, rootY);
} else if (ie.type == 1) {
if (ie.code == 272 ) {
printf("Mouse button ");
if (ie.value == 0)
printf("released!!\n");
if (ie.value == 1)
printf("pressed!!\n");
} else {
printf("time %ld.%06ld\ttype %d\tcode %d\tvalue %d\n",
ie.time.tv_sec, ie.time.tv_usec, ie.type, ie.code, ie.value);
}
}
return 0;
}

A mouse only sends relative movement, not absolute position. You have to keep track of it yourself, and when you receive a mouse-button event you have to check your own coordinates for the position.

Related

C++ writing to Framebuffer, wrong screensize

i try to write to the Linux framebuffer with c++, my problem is, that my program cant write to the whole screen, because the screensize i get is wrong. Although this code worked on an older VM, but i lost it.
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
int main() {
fb_var_screeninfo vinfo;
fb_fix_screeninfo finfo;
size_t screensize = 0;
long int location = 0;
/* Open the file for reading and writing */
int fbfd = open("/dev/fb0", O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
/* Get fixed screen information */
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
exit(2);
}
/* Get variable screen information */
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
exit(3);
}
/* Figure out the size of the screen in bytes */
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("Screen size is %ld\n", screensize);
printf("Vinfo.bpp = %d\n", vinfo.bits_per_pixel);
/* Map the device to memory */
auto fbp = static_cast<unsigned char*>(
mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0));
if(fbp == MAP_FAILED) {
perror("Error: failed to map framebuffer device to memory");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
unsigned x = 0;
unsigned y = 0; /* Where we are going to put the pixel */
/* Figure out where in memory to put the pixel */
location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) +
(y + vinfo.yoffset) * finfo.line_length;
for(uint32_t i = 0; i < vinfo.yres; i++) {
for(uint32_t count = 1; count < vinfo.xres; count++) {
fbp[location++] = 255; /* Some blue */
fbp[location++] = 0; /* A little green */
fbp[location++] = 0; /* A lot of red */
fbp[location++] = 0; /* No transparency */
}
}
munmap(fbp, screensize);
close(fbfd);
return 0;
}
I tried increasing the screensize by multiplying it by 2 and it wrote to the full screen, but then my coordinates are wrong.

Proper method to send and read OpenCV Mat object data between processes via pipes

I tried sending and receiving images between the parent and child processes using normal pipes, using the OpenCV Mat object.
The algorithm being used is:
1. Child reads an image
2. Stores it in a pipe
3. Signals the Parent that image has been written into pipe
4. Parent receives the signal and (in signal_handler) reads the image from the pipe and displays the image.
This is to be compiled as: $ g++ simple_pipe.cpp -o sp pkg-config --cflags --libs opencv
The code goes by...
#include <bits/stdc++.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// OpenCV 3.4 libraries
#include <opencv2/opencv.hpp> // FOR OpenCV
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
// #defines...
#define IMG_HT 180 // == ROWS
#define IMG_WD 180 // == COLS
#define BUFF_SIZE (3*IMG_HT*IMG_WD)
#define BFSZ 1024
#define SLEEP_FOR_SOME_TIME 10
using namespace std;
int fd1[2], fd2[2];
// fd1 => for parent ; 0 - read, 1 - write
// fd2 => for child ; 0 - read, 1 - write
pid_t child_pid;
void signal_handler(int signal_number) {
if (child_pid == 0) {
// the child part
}
else {
// the parent part
printf("Signalled, with signum = %d, and PID = %d\n", signal_number, getpid());
// close unwanted ends
close(fd1[1]);
close(fd2[1]);
close(fd1[0]);
unsigned char buffer[BUFF_SIZE];
read(fd2[0], buffer, BUFF_SIZE);
close(fd2[0]);
for (int i=0; i<100; i++) {
printf("%u ", buffer[i]);
}
cout << "\n";
cv::Mat img(IMG_HT, IMG_WD, CV_8UC3, cv::Scalar(0, 0, 0));
img.data = (buffer);
pid_t theProcess = getpid();
string windowName = to_string(theProcess);
cv::imshow(windowName, img);
cv::waitKey(0);
}
}
int main() {
int res1 = pipe(fd1);
int res2 = pipe(fd2);
if (res1 == -1 or res2 == -1) {
printf("Pipe failed!\n");
exit(EXIT_FAILURE);
}
signal(SIGABRT, signal_handler);
child_pid = fork();
if (child_pid < 0) {
printf("Fork failed!\n");
exit(EXIT_FAILURE);
}
if (child_pid == 0) {
// child part
printf("This is the child, with PID = %d, and parent PID = %d\n", getpid(), getppid());
char *imgName = "Dbo2.jpg";
// open image
cv::Mat img = cv::imread(imgName);
// cv::resize(img, img, cv::Size(IMG_WD, IMG_HT));
// close unwanted ends
close(fd1[1]);
close(fd1[0]);
close(fd2[0]);
write(fd2[1], img.data, sizeof(img.data));
close(fd2[1]);
kill(getppid(), SIGABRT);
while (1) {
sleep(SLEEP_FOR_SOME_TIME);
}
}
else {
// parent part
printf("The parent PID is: %d, with child PID = %d\n", getpid(), child_pid);
while (1) {
sleep(SLEEP_FOR_SOME_TIME);
}
}
return 0;
}
The problem I am facing is that the image obtained is corrupted - meaning, it's completely black
This is the original image being read
And, this is the black resulting image read by the parent:
I wanted to know where I am missing out on the reading/writing(or compressing) part so that I can read the same image on the parent side?

c++ pipe buffering disable

How to disable buffering in pipe. I'm creating a simple recorder/player for I/O. To do this I need record output witch time delays.
To record delays, I need something like this
example tekst
"wait 1s"
example tekst
"wait 1s"
example tekst
...
but if I use
pipe2(in, O_DIRECT );
i see something like this
"wait 100s"
"100 times" example tekst
"wait 100s"
"100 times" example tekst
...
man7 tells:
O_DIRECT (since Linux 3.4)
Create a pipe that performs I/O in "packet" mode. Each
write(2) to the pipe is dealt with as a separate packet, and
read(2)s from the pipe will read one packet at a time.
I tried to disable buffering, by:
fcntl(in[1], F_SETPIPE_SZ, 1);
but it's still not working.
read.cpp
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <assert.h>
bool keep = true;
void intHandler(int dummy) {
keep = 0;
}
int main(void) {
signal(SIGINT, intHandler);
int in[2];
int out[2];
int pid;
int fo;
char buf[1024];
pipe2(in, O_DIRECT );
pipe2(out, O_DIRECT );
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
close(in[0]);
close(out[1]);
close(0);
close(1);
dup2(in[1], 1);
dup2(out[0], 0);
close(in[1]);
close(out[0]);
sleep(1);
char *newargv[] = {"/root/Pulpit/a1", NULL, NULL, NULL};
char *newenviron[] = {NULL};
int ret = execve("/root/Pulpit/a1", newargv, newenviron);
printf("%d", ret);
return 0;
} else {
close(out[0]);
close(in[1]);
int n = 0;
while (keep) {
int wyn = read(in[0], buf, 1024);
if (wyn > 0) {
char aa[1024];
write(1, buf, wyn);
fsync(1);
}
}
}
return (0);
}
a1.cpp
#include <cstdlib>
#include <unistd.h>
#include "stdio.h"
using namespace std;
/*
*
*/
int main(int argc, char** argv) {
while(true){
printf("example text\n");
usleep(100000);
}
return 0;
}

How to wait for serial input in raw (noncanonical) mode?

This program runs on PC and I want him wait until there are data available on serial connection from Arduino, and display them. If Arduino don't send anything, I want the program to wait indefinitely.
What happens, is that I've got only Resource temporarily unavailable messages.
After kind help from Kurt Stutsman here is a working program that waits for binary input from serial connection, (from the Arduino in this case).
#include <string.h>
#include <iostream>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h> // File control definitions
#include <termios.h> // POSIX terminal control definitions
#include <unistd.h> // UNIX standard function definitions
using namespace std;
int connect(const char* serialport)
{
struct termios toptions;
int fd;
fd = open(serialport, O_RDWR );
if (fd == -1) {
return -1;
}
if (tcgetattr(fd, &toptions) < 0)
return -1;
speed_t brate = B9600; //9600 bauds
cfsetospeed(&toptions, brate);
cfmakeraw(&toptions);
toptions.c_cc[VMIN] = 1; //I want read to wait for the input
toptions.c_cc[VTIME] = 0; //indefinitely, until it arrives. Byte after byte.
tcsetattr(fd, TCSANOW, &toptions);
if( tcsetattr(fd, TCSAFLUSH, &toptions) < 0) {
return -1;
}
return fd;
}
int main() {
int fd = connect("/dev/ttyACM0");
if (fd==-1)
{
cout<<"Error in opening serial port\n";
cout<<strerror(errno)<<'\n';
return -1;
}
while(true)
{
uint8_t b=0;
int ret=read(fd, &b, 1);
if (ret == 1)
{
cout<<"received byte "<<int(b)<<'\n';
} else if (ret == 0)
{
cout<<"EOF\n";
} else
{
cout<<strerror(errno)<<'\n';
}
}
return 0;
}
You can test it with this simple Arduino C++ code:
void setup() {
Serial.begin(9600); // connect to the serial port
}
void loop()
{
Serial.write(uint8_t(42));
delay(1000);
}

NCURSES and Linux Input Device

I wrote a getSample(devicePath) function that reads raw input events from keyboard, however after running this function, ncurses doesn't display anything.
includes
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <ncurses.h>
#include <vector>
#include <string>
getSample
const int KEY_PRESSED = 1;
const int KEY_RELEASED = 0;
std::vector<input_event> getSample(std::string devicePath) {
std::vector<input_event> events;
int fileDescriptor = open(devicePath.c_str(), O_RDONLY);
while (true) {
struct input_event event;
read(fileDescriptor, &event, sizeof(struct input_event));
if (event.type == EV_KEY)
if (event.value == KEY_PRESSED || event.value == KEY_RELEASED) {
if (event.code == 28 && event.value == KEY_PRESSED)
break;
events.push_back(event);
}
}
close(fileDescriptor);
return events;
}
main
int main() {
std::string devicePath = "/dev/input/by-id/"
"usb-Microsft_Microsoft_Wireless_Desktop_Receiver_3."
"1-event-kbd";
std::vector<input_event> sample = getSample(devicePath);
initscr();
printw("Hello World!");
refresh();
getch();
endwin();
return 0;
}
Is there a way to fix it?
Tip
Function getSample works correctly, because when I replace ncurses code with simple printf(), everything works fine
int main() {
std::string devicePath = "/dev/input/by-id/"
"usb-Microsft_Microsoft_Wireless_Desktop_Receiver_3."
"1-event-kbd";
std::vector<input_event> sample = getSample(devicePath);
for (unsigned int i = 0; i < sample.size(); i++)
printf("%d | %3d | %ld.%06ld\n", sample[i].value, sample[i].code,
(long)sample[i].time.tv_sec, (long)sample[i].time.tv_usec);
return 0;
}