Register mouse devices on cocoa

It would have been nice to ensure that a device is registered already in
mouseEnteredImpl(); but in that context, NSEvent.deviceID is always 0,
and we can't find out anything else about the device.
QWindowSystemInterface::handleEnterEvent() doesn't currently take a
QPointingDevice either.

In handleMouseEvent() and scrollWheel(), deviceID seems unique for each
trackpad or Magic Mouse, but 0 for any plain USB mouse. There, the first
mouse that the user interacts with becomes primaryPointingDevice():
its deviceID is assigned to systemID (except if deviceID == 0, we use
1 instead, to avoid the auto-incrementing device ID assignment in the
QInputDevicePrivate ctor.) When scrolling occurs, we update the
capabilities to have PixelScroll if theEvent.hasPreciseScrollingDeltas.

So over time, QInputDevice::devices() should build up to a complete
list, with capabilities() also distinguishing plain mice from those that
have the PixelScroll capability. And in the common case that the user
has only one Apple pointing device, it becomes primaryPointingDevice().

Pick-to: 6.2
Task-number: QTBUG-46412
Task-number: QTBUG-63363
Task-number: QTBUG-72167
Change-Id: Id9771b4dfd765e49023bd57d42a2aa4d0635a3b2
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
bb10
Shawn Rutledge 2020-06-24 12:33:43 +02:00 committed by Tor Arne Vestbø
parent 07d8885ccc
commit 69c833dae9
6 changed files with 52 additions and 4 deletions

View File

@ -84,6 +84,7 @@ public:
Velocity = 0x0008,
NormalizedPosition = 0x0020,
MouseEmulation = 0x0040,
PixelScroll = 0x0080,
Scroll = 0x0100,
Hover = 0x0200,
Rotation = 0x0400,

View File

@ -74,6 +74,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaMouse)
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
Q_DECLARE_LOGGING_CATEGORY(lcQpaApplication)
Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard)
Q_DECLARE_LOGGING_CATEGORY(lcInputDevices)
class QPixmap;
class QString;

View File

@ -61,6 +61,7 @@ Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse", QtCriticalMsg);
Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen", QtCriticalMsg);
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard")
Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
//
// Conversion Functions

View File

@ -46,8 +46,6 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
QHash<quint64, QPointingDevice*> QCocoaTouch::_touchDevices;
QPointF QCocoaTouch::_screenReferencePos;

View File

@ -62,6 +62,7 @@
#include <private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
#include <private/qwindow_p.h>
#include <private/qpointingdevice_p.h>
#include "qcocoabackingstore.h"
#ifndef QT_NO_OPENGL
#include "qcocoaglcontext.h"

View File

@ -187,6 +187,36 @@
}
@end
static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
{
// macOS will in many cases not report a deviceID (0 value).
// We can't pass this on directly, as the QInputDevicePrivate
// constructor will treat this as a request to assign a new Id.
// Instead we use the default Id of the primary pointing device.
static const int kDefaultPrimaryPointingDeviceId = 1;
if (!deviceID)
deviceID = kDefaultPrimaryPointingDeviceId;
if (const auto *device = QPointingDevicePrivate::pointingDeviceById(deviceID))
return device; // All good, already have the device registered
const auto *primaryDevice = QPointingDevice::primaryPointingDevice();
if (primaryDevice->systemId() == kDefaultPrimaryPointingDeviceId) {
// Adopt existing primary device instead of creating a new one
QPointingDevicePrivate::get(const_cast<QPointingDevice *>(primaryDevice))->systemId = deviceID;
qCDebug(lcInputDevices) << "primaryPointingDevice is now" << primaryDevice;
return primaryDevice;
} else {
// Register a new device. Name and capabilities may need updating later.
const auto *device = new QPointingDevice(QLatin1String("mouse"), deviceID,
QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
QInputDevice::Capability::Scroll | QInputDevice::Capability::Position,
1, 3, QString(), QPointingDeviceUniqueId(), QCocoaIntegration::instance());
QWindowSystemInterface::registerInputDevice(device);
return device;
}
}
@implementation QNSView (Mouse)
- (void)initMouse
@ -294,6 +324,9 @@
button = Qt::RightButton;
const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
const QPointingDevice *device = pointingDeviceFor(theEvent.deviceID);
Q_ASSERT(device);
if (eventType == QEvent::MouseMove)
qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons;
else
@ -696,8 +729,21 @@
<< " pixelDelta=" << pixelDelta << " angleDelta=" << angleDelta
<< (isInverted ? " inverted=true" : "");
QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint,
qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, phase, source, isInverted);
const QPointingDevice *device = pointingDeviceFor(theEvent.deviceID);
Q_ASSERT(device);
if (theEvent.hasPreciseScrollingDeltas) {
auto *devicePriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(device));
if (!devicePriv->capabilities.testFlag(QInputDevice::Capability::PixelScroll)) {
devicePriv->name = QLatin1String("trackpad or magic mouse");
devicePriv->capabilities |= QInputDevice::Capability::PixelScroll;
qCDebug(lcInputDevices) << "mouse scrolling: updated capabilities" << device;
}
}
QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp,
device, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta,
m_currentWheelModifiers, phase, source, isInverted);
}
#endif // QT_CONFIG(wheelevent)