I always thought that when you connect two mice to a computer, there should be two mouse cursors, one for each mouse. Unfortunately that's not really how it works on modern operating systems, at least not by default. Software add-ons exist that draw a second cursor for the second mouse (and also perform some tricks to make button clicks work as expected). I'm sure they work fine, but I came up with a pure hardware solution to the problem that requires no special software running on the host. Here's a video demonstrating this solution.
What you can see here is two mice, connected through a USB hub to an Arduino Leonardo with a USB Host Shield. The mice are wireless, but they use 2.4 GHz USB receivers so they're effectively USB devices. The Arduino is connected to the computer and acts as a USB mouse.
The Arduino reads inputs from the two mice, does its magic, and sends the resulting inputs to the computer. What's the trick that makes the computer display two cursors? If you look closely, you'll notice that the two cursors flicker a bit. That's because they're not really two cursors, instead it's just the one normal cursor oscillating quickly between two positions on the screen, appearing as two due to persistence of vision. The Arduino keeps track of the X/Y positions of both cursors and updates them based on the inputs received from each mouse. Then it alternates between the two causing the illusion of two cursors. To be able to do that it uses absolute cursor positioning, unlike a regular mouse, which only sends the X/Y deltas and doesn't know where on the screen the cursor is at any moment. (I have previously used absolute cursor positioning for both good and evil.)
One remaining problem is what to do when you click a button on one of the mice. The user will naturally expect for the click to happen at the screen position of the cursor corresponding to that mouse. So we can't keep alternating between the two cursors. For as long as the button is pressed, we only send the cursor position of the mouse that's doing the clicking. This means that the second cursor disappears for a brief moment, but the clicks work as expected.
If you want to play around with it, I posted the source code on GitHub. It uses the standard USB HID protocol and works with Windows, Linux and Mac, without any additional software needed on the computer.

Can be used to add a trackball like Ploopy nano for scroll only and a second mouse for point and click ?
ReplyDeleteQt actually has *some* support for this, but the Windows core API and even much of Linux (and probably OSX as well) all do send mouse ID events to windows, but some API calls are still single-cursor with no way to distinguish which mouse caused the action. Newer API calls have a structure that tells you which device caused the action as does frameworks such as Qt and MFC (and even .NET and WPF support this).
ReplyDeleteThe real issue is cursor drawing for the longest time was done on the driver side. And drivers tend to stick to being very backwards compatible. So unless the OS has a driver in place that decides to actually supply the second cursor and handle/dispatch the events separately, both cursors will be as one.
Really the best a driver can do is disable the default cursor and handle all the events itself moving only the cursor whose mouse is assigned to it while leaving the other one stationary. It would, of course, have to keep track of positions itself and even have to deal with stuff such as dynamic acceleration, sensitivity, snapping, click speeds--much of what the hardware driver was supposed to deal with.
So in short, the core problem is whenever a mouse moves, it moves both cursors. The program can identify who moved it, but they do not move independently unless some other emulation driver layer is loaded to provide that.