alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

How to record mouse data and remove cursor/button functionality

Thu May 17, 2018 8:07 pm

Hi,

I'm pretty new to RPi and slightly less new to C. I am hoping to find a solution to a problem I've been running into.
I am trying to use two mice with my Pi, one which I'm hoping to use as a regular mouse, and the other which I am trying to record data from and then do something with that data, without using it as a mouse. I don't want the second mouse to interact with the OS at all: ideally, I can simply print the data to the screen without having the movement or clicks actually do anything.

Is this possible? I have figured out how to record movement data and clicks by looking at /dev/input/mouse0 and mouse1, but am not sure where to go from there.

Thank you for any help

ghans
Posts: 7787
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 5:18 am

• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:06 pm

Thank you for the reply!

I was poking around earlier and found a similar thread suggesting I edit xorg.conf. I can't seem to find that file though, and online resources are telling me that it has since been deprecated, and that these .conf files are now held in xorg.conf.d. I was able to locate this on my RPi in /usr/share/X11 but am not sure which .conf file to alter with the new lines- none of them hold similar syntax to what is shown in the stackexchange link you posted.

10-evdev.conf seems to have catchalls for pointers, keyboards, touchpads, etc.... but no individual mice files that I should alter per the suggestion of the stackexchange post. Can I write an individual Section "InputClass" for my mouse? Should I alter the catchall for pointers in some way? I'm worried that changing the catchall will mess with my first mouse, and I really would like to handle the mice individually. I can't seem to find much online regarding this, but I'll try to keep poking around. Maybe I'm just not looking in the right places.

Thanks again for your help, I'm a newbie in this area so it's really appreciated.

EDIT: I also can't use xinput for some reason. Not sure why this is?

n67
Posts: 788
Joined: Mon Oct 30, 2017 4:55 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:16 pm

A couple of "basic Unix" notes - that, admittedly, have little to do with your actual issue:

1) Install the "locate" command. It is very useful, for finding files. apt-get install locate should do it.

Note: After installing locate, either wait a day (i.e., until tomorrow) or run "updatedb" (as root).

On my system, "locate xorg.conf" get me:

Code: Select all

$ locate xorg.conf
/usr/share/man/man5/xorg.conf.5.gz
/usr/share/man/man5/xorg.conf.d.5.gz
/usr/share/X11/xorg.conf.d
/usr/share/X11/xorg.conf.d/10-evdev.conf
/usr/share/X11/xorg.conf.d/10-quirks.conf
/usr/share/X11/xorg.conf.d/40-libinput.conf
/usr/share/X11/xorg.conf.d/70-synaptics.conf
/usr/share/X11/xorg.conf.d/99-fbturbo.conf
$
Note that there isn't any xorg.conf file, per se. Only files in xorg.conf.d

2) You should create a new file in xorg.conf.d, not edit an existing one.
(Not sure what number to use, though - that gets beyond my pay grade).
"L'enfer, c'est les autres"

If a post offends you, just put that poster on your foes list, and be done with it (and with them).

To do otherwise, risks being banned.

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:20 pm

Thanks for the quick reply!

I'll install locate right now, seems like a useful tool.

Creating a new file in xorg.conf.d seems promising, just not sure what to name it and how to format it. I'm assuming something like this:

Code: Select all

Section "InputClass"
	Identifier "Mouse4"
	MatchIsPointer "on"
	MatchDevicePath "/dev/input/event4"
	Driver "evdev"
EndSection
Would be good to include (I know event4 is the event associated with the mouse I am trying to mute). This is essentially copy pasted from 10-evdev.conf with Identifier and MatchDevicePath updated to point to my new mouse.
Still not sure what to name it though... I'll try to see if there is anything online that would be helpful.
Last edited by alphascrooge on Fri May 18, 2018 4:22 pm, edited 1 time in total.

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:21 pm

If you open the "non-X-mouse" file in /dev/input and set it for "exclusive access" in your program the events will not be passed on to X while your program has it open....

Code: Select all

result = ioctl(mouseFd, EVIOCGRAB, 1);
Also "evtest" is a useful tool to use when trying to learn about the events that come from a particular device.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:31 pm

Thank you for the reply, that was very helpful!

Just to be clear, ioctl with the EVIOCGRAB tag will not pass the events to X? I'm having a hard time finding documentation for EVIOCGRAB, the man page for ioctl and ioctl_list doesn't seem to describe it, so I don't really know what that tag does.

I'll check out evtest per your suggestion

Thanks again :)

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:47 pm

alphascrooge wrote:
Fri May 18, 2018 4:31 pm
Thank you for the reply, that was very helpful!

Just to be clear, ioctl with the EVIOCGRAB tag will not pass the events to X? I'm having a hard time finding documentation for EVIOCGRAB, the man page for ioctl and ioctl_list doesn't seem to describe it, so I don't really know what that tag does.

I'll check out evtest per your suggestion

Thanks again :)
Indeed I'm not sure where I found out about it, probably someone on a forum told me about it (and so the myth is passed on to the next generation :-) ). But it does work !
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 4:54 pm

Hi Peter,

Thanks for you quick replies, its super helpful. Its odd that there's no clear documentation on this....

I'm running into an issue where EVIOCGRAB isn't declared, so I'm getting a compilation error. Should I be including a file where it is defined?

I have been googling around and https://unix.stackexchange.com/question ... documented seems to say that EVIOCGRAB would be located in drivers/input/evdev.c, but I can't seem to find this directory. Does this not exist on RPi or is it named something else?

Thanks very much for your help!

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 5:02 pm

It's in /usr/include/linux/input.h so you'll need to "#include linux/input.h".

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 5:53 pm

Thanks for all your help so far, maybe I could bother you just a little more?

So I'm now using ioctl on the mousefd. Looks something like this:

Code: Select all

fd1 = open(mouse1, O_RDWR);
if(fd1 == -1) {return -1}

//mute mouse1
result = ioctl(fd1, EVIOCGRAB, 1);
if(result == -1) 
{
	printf("Muting broke. %s\n", strerror(errno));
}
The issue is that ioctl is returning with an error, specifically "Inappropriate ioctl for device".
Is there anything immediately apparent that I'm doing wrong here? I'm not sure why ioctl isn't working, it's throwing the error and isn't blocking mouse input. I've checked around online, and it seems that this error is a result of something to do with tty, but I don't really understand it.

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 9:32 pm

alphascrooge wrote:
Fri May 18, 2018 5:53 pm
Thanks for all your help so far, maybe I could bother you just a little more?

So I'm now using ioctl on the mousefd. Looks something like this:

Code: Select all

fd1 = open(mouse1, O_RDWR);
if(fd1 == -1) {return -1}

//mute mouse1
result = ioctl(fd1, EVIOCGRAB, 1);
if(result == -1) 
{
	printf("Muting broke. %s\n", strerror(errno));
}
The issue is that ioctl is returning with an error, specifically "Inappropriate ioctl for device".
Is there anything immediately apparent that I'm doing wrong here? I'm not sure why ioctl isn't working, it's throwing the error and isn't blocking mouse input. I've checked around online, and it seems that this error is a result of something to do with tty, but I don't really understand it.
Without knowing what "mouse1" is I can't say much....

In my openGLES code I look for a file that ends with "event-mouse" in "/dev/input/by-id", so it normally finds the file for my tracker ball which is :
/dev/input/by-id/usb-Logitech_USB_Trackball-event-mouse which is in turn a link to /dev/input/mouse0

In your case I expect it will be /dev/input/mouse1 that you will need to open, though there may be no gaurantee mouse0 and mouse1 will always be the same way round.

My code opens the file with " mouseFd = open(fullPath,O_RDONLY | O_NONBLOCK);" You can't write to is so it should not be opened with O_RDWR. I use O_NONBLOCK so my code can just try to read events and not block if there aren't any to read.


PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 9:47 pm

Awesome! That solved the issue! Now X isn't seeing mouse1, once I changed the path to the by-id directory and added O_RDONLY.
There's only 1 problem: I used to have the coordinates and buttons status printed to screen when a mouse event was detected. Upon moving either mouse it would print something like:

Mouse0: x=1, y=0, left=0, right=0, middle=0 (When I move mouse 0).
or
Mouse1: x=0, y=0, left=1, right=0, middle=0 (When I left click mouse 1).

Now, it isn't printing anything for mouse1. As far as I can tell, I've effectively disconnected mouse1 and can't read any of the data it's outputting. I'm hoping to be able to still access that data but not have it do anything on screen. Is this possible?

Thank you so much for all your help, you're a true hero :)

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 9:53 pm

In case it's helpful, here's my (relevant) code:
fd0 is the file descriptor for mouse0: open(fullpath, O_RDWR);
fd1 is the file descriptor for mouse1: open(fullpath, O_RDONLY|O_NONBLOCK);

Code: Select all

	result = ioctl(fd1, EVIOCGRAB, 1);
	if(result == -1){
		fprintf(stderr, "?\n");
		printf("muting broke. %s\n", strerror(errno));
	
	}
	printf("result: %d\n", result);
	
	//more initialization
	int left0, left1, middle0, middle1, right0, right1;
	signed char x0, x1, y0, y1;
	
	//-----------------------------------------------------------//
	//I track the data from the mice in 2 different processes.   //
	//Tracking the data on the same process led to weird errors  //
	//where it would only read data from one mouse at a time, but//
	//would alternate which mouse it read from based on the mouse//
	//it read from last, every 5 seconds or so.                  //
	//Therefore, using different processes for each mouse.       //
	//-----------------------------------------------------------//
	
	
	if(fork() == 0) 	//child process
	{
		while(1){
			bytes0 = read(fd0, data0, sizeof(data0));//Read data from mouse
			
			if(bytes0 > 0){
				left0 = data0[0] & 0x1;				//mask to find data on the left mouse button (first bit)
				right0 = data0[0] & 0x2;			//mask to find data on the right mouse button (2nd bit)
				middle0 = data0[0] & 0x4;			//(3rd bit)
		
				x0 = data0[1];						//get position data
				y0 = data0[2];
				
				//Now we can use the data. In this case, print.
				printf("Mouse0:  x=%d, y=%d, left=%d, middle=%d, right=%d\n", x0,y0,left0,middle0,right0);
			}
		}
	}
	else{				//parent process
		while(1){
			bytes1 = read(fd1, data1, sizeof(data1));
		
			if(bytes1 > 0){
				left1 = data1[0] & 0x1;
				right1 = data1[0] & 0x2;
				middle1 = data1[0] & 0x4;
				x1 = data1[1];
				y1 = data1[2];
			
				printf("Mouse1:  x=%d, y=%d, left=%d, middle=%d, right=%d\n", x1,y1,left1,middle1,right1);
			}
		}
	}

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Fri May 18, 2018 10:00 pm

Yes you will have to read events from the file you opened...

Here is the code I use... My main program loop calls "mouseMotion" which reads the evens and set the appropriate global variables (mouseMoveLR and mouseMoveUD) to reflect the mouse movements since the function was last called. It will try to read upto 64 events at a time.

Code: Select all

void mouseMotion(void)
{
    struct input_event ev[64];
    int rd;

    mouseMoveLR = mouseMoveUD = 0;
    if(mouseFd != -1)
    {
	rd = read(mouseFd,ev,sizeof(ev));
	if(rd > 0)
	{
	    int count,n;
	    struct input_event *evp;

	    count = rd / sizeof(struct input_event);
	    n = 0;
	    while(count--)
	    {
		evp = &ev[n++];

		if(evp->type == 1)
		{
		    if(evp->value == 1)
		    {
			if(evp->code == BTN_LEFT)  
			{
			    mousePressLeft = true;
			}
			if(evp->code == BTN_RIGHT)  
			{
			    mousePressRight = true;
			}
		    }

		}
		if(evp->type == 2)
		{
		    if(evp->code == 0)
		    {   // Mouse Left/Right
			//printf("Mouse moved %d left/right\n",evp->value);
			mouseMoveLR += evp->value;
		    }
		    if(evp->code == 1)
		    {   // Mouse Up/Down
			//printf("Mouse moved %d up/down\n",evp->value);
			mouseMoveUD += evp->value;
		    }
		}

	    }
	}
    }
}

struct input_event is defined in /usr/include/linux/input.h


HTH

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Wed May 23, 2018 5:41 am

Hi,

Sorry for delay, hopefully someone sees this and can help.
I am getting an error with the line:

Code: Select all

result = ioctl(fd1, EVIOCGRAB, 1);
Specifically it returns -1, and strerror(errno) gives me "Inappropriate ioctl for device"
Code behavior stays the same, and I am still able to read data from mouse1 and it still is interacting with the OS (which I don't want it to).

I'm relatively lost here. Google searches haven't really helped much, so was curious if anyone on here maybe knew something.

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Wed May 23, 2018 6:25 am

Can you put all your code somewhere ? I can plug two mice into a PI and try your code to see what is going on.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Thu May 24, 2018 11:28 am

I've looked at your code now, an you are not using the event devices so I can't really say if it should work or not.

Your code opens the file /dev/input/mouse[0,1]

My code is written to use /dev/input/event[0,3] which provide a stream of event structures rather than the old style mouse driver emulation provided by /dev/input/mouse[0,3]

PeterO
Last edited by PeterO on Thu May 24, 2018 11:42 am, edited 1 time in total.
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Thu May 24, 2018 11:40 am

PeterO wrote:
Fri May 18, 2018 9:32 pm

In my openGLES code I look for a file that ends with "event-mouse" in "/dev/input/by-id", so it normally finds the file for my tracker ball which is :
/dev/input/by-id/usb-Logitech_USB_Trackball-event-mouse which is in turn a link to /dev/input/mouse0

In your case I expect it will be /dev/input/mouse1 that you will need to open, though there may be no gaurantee mouse0 and mouse1 will always be the same way round.

My code opens the file with " mouseFd = open(fullPath,O_RDONLY | O_NONBLOCK);" You can't write to is so it should not be opened with O_RDWR. I use O_NONBLOCK so my code can just try to read events and not block if there aren't any to read.
Looking at that post again I got some things wrong :oops:

It should read

In my openGLES code I look for a file that ends with "event-mouse" in "/dev/input/by-id", so it normally finds the file for my tracker ball which is :
/dev/input/by-id/usb-Logitech_USB_Trackball-event-mouse which is in turn a link to /dev/input/event0

With two identical trackballs plugged in evtest reports this:

Code: Select all

[email protected]:/dev/input/by-id $ sudo evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:	Logitech USB Trackball
/dev/input/event1:	Logitech USB Receiver
/dev/input/event2:	Logitech USB Receiver
/dev/input/event3:	Logitech USB Trackball
In my case it will be /dev/input/event0 and event3 that need to be openen, though there may be no gaurantee event0 and event3 will always be the same way round. You will need to use evtest to find out which event files map to your two mice.

My code opens the file with " mouseFd = open(fullPath,O_RDONLY | O_NONBLOCK);" You can't write to is so it should not be opened with O_RDWR. I use O_NONBLOCK so my code can just try to read events and not block if there aren't any to read.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Thu May 24, 2018 4:07 pm

Editing my code to the changes you suggested seemed to work. I changed

Code: Select all

mouse0 = "/dev/input/event1"
mouse1 = "/dev/input/event5"
and my open statements to O_RDONLY|O_NONBLOCK

Now, when I run it, I no longer get the ioctl error, and the second mouse stops moving and clicking, just like I wanted.
The only issue is, now moving the mice doesn't print to terminal anymore. I think it's because I'm not able to interpret the data correctly? The way I do this is:

Code: Select all

bytes0 = read(fd0, data0, sizeof(data0));
which I then mask on to get the data I'm looking for with:

Code: Select all

left0 = data0[0] & 0x1;
 right0 = data0[0] & 0x2;
 middle0 = data0[0] & 0x4;
 x0 = data0[1];
 y0 = data0[2];
Then I print these values. Should I be doing something else?

EDIT: I should note, this system of interpreting data was working before I changed the paths and the open() function call.
EDIT2: After more exploring, I've determined that I actually can detect the events when they occur, I just don't know how to interpret the data. What I have right now is:

Code: Select all

data1 = struct input_event data1[64];
mouse1 = "/dev/input/event1";
fd1 = open(mouse1, O_RDONLY | O_NONBLOCK);

...

while(1){
	bytes1 = read(fd1, data1, sizeof(data1));
	if(bytes1 > 0){
		fprintf(stderr, "we have an event!\n");
		struct input_event *evp;
		evp = data1;
		
		if(evp->type == 1){
			if(evp->value == 1){
				if(evp->code == BTN_LEFT){
					fprintf(stderr, "Left\n");
				}
				if(evp->code == BTN_RIGHT){
					fprintf(stderr, "Right\n");
				}
			}
		}
	}
}
Upon running, "we have an event!" prints every time I move or click a mouse button, but "Left" nor "Right" appear when I click their respective buttons. I'm thinking I'm not interpreting the data correctly.

alphascrooge
Posts: 12
Joined: Thu May 17, 2018 8:00 pm

Re: How to record mouse data and remove cursor/button functionality

Thu May 24, 2018 5:41 pm

Update:

I have it working now! For some reason, the type, code, and value were all mixed up, and not what the documentation suggested they should be, which raises some red flags in my mind.
Currently, left click has:
type: 4
code: 4
value: 589825

and right click has:
type: 4
code: 4
value: 589826

I'm not sure why these have taken seemingly random values.
According to linux/input.h, for left click they should be:
type: 1
code: 1 (not actually sure, taking PeterO's word here)
value: BTN_LEFT (0x110)

and right should be:
type: 1
code: 1 (again, taking PeterO's word)
value: BTN_RIGHT (0x111)

Seems like a weird discrepancy, but what I have is working for me now. To add buttons, I add a print statement checking value, type, and code, then add a case for that specific combination of values. Kind of hacky, but it seems to be doing the job.

Thanks again for the help, I really appreciate you sticking with me all this time.

User avatar
PeterO
Posts: 4237
Joined: Sun Jul 22, 2012 4:14 pm

Re: How to record mouse data and remove cursor/button functionality

Thu May 24, 2018 5:59 pm

The code I posted earlier viewtopic.php?f=33&t=213801#p1317163 reads the event stream and interprets them.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 3 guests