由于需要分析qtbase中的触摸屏处理事件,所以下载源码进行分析。思路为:widgets窗口线程起来之后,怎样通过libinput进行触摸识别。(理解了触摸屏的识别之后,键盘、鼠标、案件的识别也是类似的)
路径:qtbase/src/widgets/kernel/qgesturemanager.cpp
for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) {
Qt::GestureType gestureType = context.value();
const QMap &const_recognizers = m_recognizers;
QMap::const_iterator
typeToRecognizerIterator = const_recognizers.lowerBound(gestureType),
typeToRecognizerEnd = const_recognizers.upperBound(gestureType);
for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) {
QGestureRecognizer *recognizer = typeToRecognizerIterator.value();
QObject *target = context.key(); //获取事件key码
QGesture *state = getState(target, recognizer, gestureType);//通过key码来确定事件类型的状态
if (!state)
continue;
QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event);
QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask;
QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask;
if (recognizerState == QGestureRecognizer::TriggerGesture) {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture triggered: " << state << event;
triggeredGestures << state;
} else if (recognizerState == QGestureRecognizer::FinishGesture) {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: gesture finished: " << state << event;
finishedGestures << state;
} else if (recognizerState == QGestureRecognizer::MayBeGesture) {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: maybe gesture: " << state << event;//触摸屏事件类型输出
newMaybeGestures << state;
} else if (recognizerState == QGestureRecognizer::CancelGesture) {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: not gesture: " << state << event;
notGestures << state;
} else if (recognizerState == QGestureRecognizer::Ignore) {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: ignored the event: " << state << event;
} else {
qCDebug(lcGestureManager) << "QGestureManager:Recognizer: hm, lets assume the recognizer"
<< "ignored the event: " << state << event;
}
if (resultHint & QGestureRecognizer::ConsumeEventHint) {
qCDebug(lcGestureManager) << "QGestureManager: we were asked to consume the event: "
<< state << event;
consumeEventHint = true;
}
}
}
state << event类型的来源:qtbase/src/platformsupport/input/libinput/qlibinputtouch.cpp
//触屏被按下
void QLibInputTouch::processTouchDown(libinput_event_touch *e)
{
int slot = libinput_event_touch_get_slot(e);//输入事件的获取是通过libinput
DeviceState *state = deviceState(e);
QWindowSystemInterface::TouchPoint *tp = state->point(slot);
if (tp) {
qWarning("Incorrect touch state");
} else {
QWindowSystemInterface::TouchPoint newTp;
newTp.id = qMax(0, slot);
newTp.state = Qt::TouchPointPressed;//手指按下
newTp.area = QRect(0, 0, 8, 8);
newTp.area.moveCenter(getPos(e));
state->m_points.append(newTp);//将按下的状态数据存储到state中
}
}
//手指松开
void QLibInputTouch::processTouchUp(libinput_event_touch *e)
{
int slot = libinput_event_touch_get_slot(e);
DeviceState *state = deviceState(e);
QWindowSystemInterface::TouchPoint *tp = state->point(slot);
if (tp) {
tp->state = Qt::TouchPointReleased;
// There may not be a Frame event after the last Up. Work this around.
Qt::TouchPointStates s = 0;
for (int i = 0; i < state->m_points.count(); ++i)//触控的点数
s |= state->m_points.at(i).state;
if (s == Qt::TouchPointReleased)
processTouchFrame(e);//多点触控处理
} else {
qWarning("Inconsistent touch state (got 'up' without 'down')");
}
}
void QLibInputTouch::processTouchFrame(libinput_event_touch *e)
{
DeviceState *state = deviceState(e);
if (!state->m_touchDevice) {
qWarning("TouchFrame without registered device");
return;
}
if (state->m_points.isEmpty())
return;
QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, state->m_touchDevice, state->m_points,
QGuiApplication::keyboardModifiers());
for (int i = 0; i < state->m_points.count(); ++i) {
QWindowSystemInterface::TouchPoint &tp(state->m_points[i]);
if (tp.state == Qt::TouchPointReleased)
state->m_points.removeAt(i--);//每松开一个手指,则触控的点数减1
else if (tp.state == Qt::TouchPointPressed)
tp.state = Qt::TouchPointStationary;
}
}
processTouchDown和processTouchUp事件处理是怎么来的呢?
见路径:qtbase/src/platformsupport/input/libinput/qlibinputhandler.cpp
首先看一下头文件定义:
class QLibInputHandler : public QObject
{
Q_OBJECT
public:
QLibInputHandler(const QString &key, const QString &spec);
~QLibInputHandler();
signals:
void deviceAdded(const QString &sysname, const QString &name);
void deviceRemoved(const QString &sysname, const QString &name);
private slots:
void onReadyRead();
void onCursorPositionChangeRequested(const QPoint &pos);
private:
void processEvent(libinput_event *ev);
udev *m_udev;
libinput *m_li; //libinput定义
int m_liFd;
QScopedPointer m_notifier;//监听系统文件操作,将操作转换为Qt事件进入系统的消息循环队列
QScopedPointer m_pointer;
QScopedPointer m_keyboard;
QScopedPointer m_touch;
QMap m_devCount;
};
然后.cpp文件分析:
m_li = libinput_udev_create_context(&liInterface, Q_NULLPTR, m_udev);
if (Q_UNLIKELY(!m_li))
qFatal("Failed to get libinput context");
libinput_log_set_handler(m_li, liLogHandler);
if (qLcLibInput().isDebugEnabled())
libinput_log_set_priority(m_li, LIBINPUT_LOG_PRIORITY_DEBUG);
if (Q_UNLIKELY(libinput_udev_assign_seat(m_li, "seat0")))
qFatal("Failed to assign seat");
m_liFd = libinput_get_fd(m_li);
qDebug() << "[qlibinputhandler.cpp] m_liFd is: " << m_liFd;
m_notifier.reset(new QSocketNotifier(m_liFd, QSocketNotifier::Read));
//若监听到发生触摸、按键等事件,立即通知onReadyRead
connect(m_notifier.data(), SIGNAL(activated(int)), SLOT(onReadyRead()));
void QLibInputHandler::onReadyRead()
{
qDebug() << "have a event";
qDebug() << "[qlibinputhandler.cpp] enter to onReadyRead";
if (libinput_dispatch(m_li)) {
qWarning("libinput_dispatch failed");
return;
}
libinput_event *ev;
while ((ev = libinput_get_event(m_li)) != Q_NULLPTR) {
processEvent(ev); //按键处理事件
libinput_event_destroy(ev);
}
}
在processEvent(ev)中进行了一系列的处理:
void QLibInputHandler::processEvent(libinput_event *ev)
{
libinput_event_type type = libinput_event_get_type(ev); //按键的事件类型
qDebug() << "[qlibinputhandler.cpp] libinput_event_type is: " << type;
libinput_device *dev = libinput_event_get_device(ev);
switch (type) {
case LIBINPUT_EVENT_DEVICE_ADDED:
{
.
.
.
case LIBINPUT_EVENT_TOUCH_DOWN://触摸事件处理
m_touch->processTouchDown(libinput_event_get_touch_event(ev));
break;
case LIBINPUT_EVENT_TOUCH_MOTION://触摸移动处理
m_touch->processTouchMotion(libinput_event_get_touch_event(ev));
break;
case LIBINPUT_EVENT_TOUCH_UP://触摸松开处理
m_touch->processTouchUp(libinput_event_get_touch_event(ev));
break;
case LIBINPUT_EVENT_TOUCH_CANCEL:
m_touch->processTouchCancel(libinput_event_get_touch_event(ev));
break;
case LIBINPUT_EVENT_TOUCH_FRAME:
m_touch->processTouchFrame(libinput_event_get_touch_event(ev));
break;
default:
break;
}
}
到此与qtbase/src/platformsupport/input/libinput/qlibinputtouch.cpp中的各类触摸事件结合了起来。
上述事件的流程图如下所示: