Linux平台下Qt应用中双鼠标设备的事件识别与限定区域操控技术咨询
Absolutely, this is totally achievable on Linux with Qt and Xorg. Here's a step-by-step breakdown of how to implement the behavior you want:
1. First, Identify Your Two Mice
The first step is to tell the two physical mice apart. Qt 5.10+ includes the QInputDevice class, which lets you enumerate all connected input devices. You can filter for pointer devices (mice) and store their unique references or identifiers:
#include <QInputDevice> #include <QList> // Grab all connected mice QList<QInputDevice*> mice; for (const QInputDevice* dev : QInputDevice::devices()) { if (dev->type() == QInputDevice::Pointer) { mice.append(const_cast<QInputDevice*>(dev)); qDebug() << "Detected mouse:" << dev->name() << "ID:" << dev->id(); } } // Assign your mice (adjust indices based on your actual setup) QInputDevice* regularMouse = mice[0]; QInputDevice* constrainedMouse = mice[1];
Pro tip: To avoid relying on device indices (which can change if you unplug/replug mice), you can match against the mouse's USB VID/PID or unique name instead. If you need lower-level control, X11's XListInputDevices() is also an option, but Qt's API is cleaner for most use cases.
2. Filter Events to Handle Each Mouse Differently
Next, intercept mouse events and treat the constrained mouse separately. Install an event filter on your application or target widget to check which device each event originates from:
bool MainWindow::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::MouseMove) { QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); QInputDevice* sourceDevice = mouseEvent->device(); // Check if this is our constrained mouse if (sourceDevice == constrainedMouse) { QWidget* targetWidget = ui->yourConstrainedWidget; QPoint localPos = targetWidget->mapFromGlobal(mouseEvent->globalPos()); // Clamp the position to stay within the widget's bounds localPos.setX(qBound(0, localPos.x(), targetWidget->width() - 1)); localPos.setY(qBound(0, localPos.y(), targetWidget->height() - 1)); QPoint newGlobalPos = targetWidget->mapToGlobal(localPos); // If the mouse tried to escape, warp it back to the widget if (newGlobalPos != mouseEvent->globalPos()) { // Use X11 to warp the specific pointer (Xorg manages separate cursors) Display* display = QX11Info::display(); Window root = DefaultRootWindow(display); XWarpPointer(display, None, root, 0, 0, 0, 0, newGlobalPos.x(), newGlobalPos.y()); XFlush(display); // Update the event to reflect the clamped position mouseEvent->setGlobalPos(newGlobalPos); mouseEvent->setLocalPos(localPos); } } } // Pass other events through normally return QMainWindow::eventFilter(obj, event); }
Don't forget to install the event filter in your main window's constructor:
installEventFilter(this);
3. Confirm Xorg's Multi-Pointer Setup
Since you mentioned you already have two separate cursors configured, Qt will automatically receive distinct events for each pointer. If you haven't set this up yet, use xinput commands to create a second pointer master:
# List all input devices to get your mouse's ID xinput list # Create a new pointer master for the constrained mouse xinput create-master "ConstrainedPointer" # Reattach your second mouse to the new master xinput reattach <your-mouse-device-id> "ConstrainedPointer" pointer
4. Optional: Kernel-Level Tweaks (If You Really Need Them)
If you want ultra-tight control (like preventing the mouse from ever leaving the widget at the driver level), you could modify the input driver for the second mouse to clamp its coordinates. But honestly, this is overkill for most cases—user-space handling with Qt/X11 works perfectly well. That said, since you have kernel access, it's an option if you need it.
Key Gotchas to Watch For
- Ensure you're using Qt 5.10 or newer—
QMouseEvent::device()was added in that version. - When using
XWarpPointer, always callXFlush(display)to apply the change immediately. - Test device identification thoroughly—device IDs can shift if you rearrange USB ports, so using unique identifiers (like VID/PID) is more reliable.
内容的提问来源于stack exchange,提问作者Narek Aydinyan

