提交 1cc5afe1 编写于 作者: mahuifa's avatar mahuifa

Merge branch 'Dev'

......@@ -17,6 +17,7 @@
| WindowRect | 框选鼠标当前位置窗口范围(类似窗口截图) | Windows、Linux |
| MouseKeyEvent | Qt实现自定义全局鼠标键盘事件监听器Demo | Windows |
| SnippingTool | Qt实现截图工具 | Windows、Linux |
| MouseKeyEvent | Qt全局鼠标、键盘事件监听器 | Windows、Linux |
......@@ -166,4 +167,17 @@ Qt自身的鼠标事件、事件过滤器一般当鼠标移出窗口或者遇见
> 5. 使用自定义全局 鼠标事件监听器解决截图时窗口透明导致的鼠标穿透而无法捕捉到鼠标事件问题。
> 6. Windows下使用user32获取鼠标所在位置窗口大小,Linux下使用x11获取鼠标所在位置窗口大小。
![image-20221121125725058](FunctionalModule.assets/image-20221121125725058.png)
\ No newline at end of file
![image-20221121125725058](FunctionalModule.assets/image-20221121125725058.png)
### 1.10 MouseKeyEvent
> 1. windows下使用鼠标钩子实现全局鼠标监听功能;
> 2. 通过封装将Windows鼠标信号转换成Qt鼠标信号;
> 3. Linux下使用X11实现全局鼠标事件监听功能;
> 4. 通过封装将X11鼠标信号转换为Qt鼠标信号(功能比Windows鼠标钩子强);
> 5. Windows下实现全局键盘事件监听器功能;
> 6. Linux下通过x11 API获取到全局键盘事件,但是无法将x11键盘事件映射为QKeyEvent。
![MouseKeyEvent](FunctionalModule.assets/MouseKeyEvent.gif)
\ No newline at end of file
#---------------------------------------------------------------------------------------
# @功能: 封装的跨平台Qt全局鼠标、键盘事件监听器类
# | 功能 | 系统 | 是否实现 | 实现方式 |
# | 全局鼠标事件监听器 | Windows | 已实现 | user32鼠标钩子 |
# | 全局鼠标事件监听器 | Linux | 已实现 | x11 API |
# | 全局键盘事件监听器 | Windows | 已实现 | user32键盘钩子 |
# | 全局键盘事件监听器 | Linux | 未实现 | |
#
# @编译器: Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE: D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
# @开发者 mhf
# @邮箱 1603291350@qq.com
# @时间 2022-12-01 15:31:51
# @备注 Linux下全局键盘事件监听器通过使用X11 API已经获取到了全局键盘事件,但是不知道怎么将
# X11键盘事件映射为QKeyEvent,通过阅读Qt源码,发现Qt使用的是xcb将xkb映射为QKeyEvent,后续有时间在继续研究。
# Qt源码位置:D:\Qt\Qt5.12.5\5.12.5\Src\qtbase\src\plugins\platforms\xcb\qxcbkeyboard.cpp
#---------------------------------------------------------------------------------------
QT += concurrent
HEADERS += \
$$PWD/globalkeyevent.h \ # 全局键盘事件监听器类头文件
$$PWD/globalmouseevent.h # 全局鼠标事件监听类头文件
SOURCES += \
$$PWD/globalkeyevent_win.cpp \ # Windows全局键盘事件监听器
$$PWD/globalkeyevent_x11.cpp \ # Linux全局键盘事件监听器(未实现)
$$PWD/globalmouseevent_win.cpp \ # windows全局鼠标事件监听器
$$PWD/globalmouseevent_x11.cpp # linux全局鼠标事件监听器
......
#ifndef GLOBALKEYEVENT_H
#define GLOBALKEYEVENT_H
#include <QObject>
class QKeyEvent;
/**
* 全局鼠标事件单例信号类
*/
class GlobalKeyEvent : public QObject
{
Q_OBJECT
public:
static GlobalKeyEvent* getInstance()
{
static GlobalKeyEvent keyEvent;
return &keyEvent;
}
static bool installKeyEvent(); // 安装全局键盘事件监听器
static bool removeKeyEvent(); // 卸载全局键盘事件监听器
signals:
/**
* @brief 由于传递的是指针,为了保证不会出现内存泄露,需要在槽函数中delete。
* 建议此信号只绑定一次,因为如果绑定多次可能会出现一个槽函数里把信号delete了,另外一个槽函数还在使用,出现野指针,或者多个槽函数多次delete
*/
void keyEvent(QKeyEvent* event);
private:
GlobalKeyEvent(){}
};
#endif // GLOBALKEYEVENT_H
#include "globalkeyevent.h"
#if defined(Q_OS_LINUX)
#include <QtConcurrent>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/record.h> // 如果找不到可以安装sudo apt-get install xorg-dev
#include <X11/Xlibint.h>
#if 0
//#include <xcb/xcb_keysyms.h> // sudo apt install libxcb-keysyms1-dev
//#include <xcb/xinput.h> // sudo apt install libxcb-xinput-dev
#include <xkbcommon/xkbcommon.h> // sudo apt install libxkbcommon-dev
#include <xkbcommon/xkbcommon-keysyms.h>
#endif
static XRecordContext g_context = 0;
static Display* g_display = nullptr;
static bool init()
{
g_display =XOpenDisplay(nullptr); // 打开与控制显示器的X服务器的连接,详细说明看【https://tronche.com/gui/x/xlib/display/opening.html】
if(!g_display)
{
qWarning() << "连接X服务失败!";
return false;
}
XRecordClientSpec clients = XRecordAllClients; // 初始化 XRecordCreateContext 所需的 XRecordClientSpec 参数,XRecordAllClients 的意思是 "记录所有 X Client" 的事件
XRecordRange*range = XRecordAllocRange(); // 创建 XRecordRange 变量,用于控制记录事件的范围
if (!range)
{
qDebug() << "无法分配XRecordRange";
return false;
}
// 会监听到 first - last之间并包含first和last的所有类型的事件
memset(range, 0, sizeof(XRecordRange));
range->device_events.first = KeyPress;
range->device_events.last = KeyRelease;
// 根据上面的记录客户端类型和记录事件范围来创建 “记录上下文”
// 然后把 XRecordContext 传递给 XRecordEnableContext 函数来开启事件记录循环
g_context = XRecordCreateContext(g_display, 0, &clients, 1,&range, 1);
XFree(range);
if(g_context == 0)
{
qWarning() << "创建事件记录上下文失败!";
return false;
}
XSync(g_display, false); // XSync 的作用就是把上面的X 代码立即发给 X Server,这样 X Server 接受到事件以后会立即发送给 XRecord 的 Client 连接 True
return true;
}
/**
* @brief 处理鼠标事件的回调函数,将X11鼠标事件转换为Qt鼠标事件,通过单例类MouseEvent发送出去
* @param ptr
* @param data
*/
static void callback(XPointer ptr, XRecordInterceptData* data)
{
Q_UNUSED(ptr)
if (data->category == XRecordFromServer)
{
xEvent * event = reinterpret_cast<xEvent*>(data->data);
// qDebug() << QString("鼠标坐标:[%1, %2]").arg(event->u.keyButtonPointer.rootX).arg(event->u.keyButtonPointer.rootY); // 获取鼠标坐标
switch (event->u.u.type) // 动作类型
{
case KeyPress: // 键盘按下
{
// QPoint point = QCursor::pos(); // 获取鼠标当前位置
qDebug() << event->u.u.detail;
switch (event->u.u.detail) // 按键类型
{
case Button1: // 左键按下
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
}
case Button2: // 中键按下
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button3: // 右键按下
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
}
case Button4: // 向前滚动
{
// emit GlobalMouseEvent::getInstance()->wheelEvent(new QWheelEvent(point, 120, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button5: // 向后滚动
{
// emit GlobalMouseEvent::getInstance()->wheelEvent(new QWheelEvent(point, -120, Qt::MiddleButton, Qt::NoModifier));
break;
}
default:
{
qDebug() << QString("未定义的按键:%1").arg(event->u.u.detail); // 比如很多鼠标边上会多几个键
break;
}
}
break;
}
case KeyRelease: // 键盘释放
{
// QPoint point = QCursor::pos(); // 获取鼠标当前位置
switch (event->u.u.detail) // 按键类型
{
case Button1: // 左键释放
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
}
case Button2: // 中键释放
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button3: // 右键释放
{
// emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
}
case Button4: // 向前滚动
{
break;
}
case Button5: // 向后滚动
{
break;
}
default:
{
// qDebug() << QString("未定义的按键:%1").arg(event->u.u.detail); // 比如很多鼠标边上会多几个键
}
}
break;
}
default:
break;
}
}
XRecordFreeData(data);
}
/**
* 调用 XRecordEnableContext 函数建立 XRecord 上下文
* X Server 事件一旦发生就传递给事件处理回调函数
* XRecordEnableContext 函数一旦调用就开始进入堵塞时的事件循环,直到线程或所属进程结束
*/
static void enableContext()
{
Status ret = XRecordEnableContext(g_display, g_context, callback, nullptr);
XCloseDisplay(g_display); // 关闭连接
g_display = nullptr;
qDebug() << QString("退出键盘事件监听:%1").arg(ret);
}
/**
* @brief 安装全局键盘事件监听器
* @return
*/
bool GlobalKeyEvent::installKeyEvent()
{
bool ret = init();
if(!ret) return false;
QtConcurrent::run(enableContext); // 由于XRecordEnableContext会一直阻塞,所以需要在线程中调用
return true;
}
/**
* @brief 卸载全局键盘事件监听器
* @return
*/
bool GlobalKeyEvent::removeKeyEvent()
{
if(g_context == 0) return false;
Display* display = XOpenDisplay(nullptr); // 这里需要单独建立一个连接来关闭监听,否则XRecordEnableContext不会退出
if(!display)
{
qWarning() << "连接X服务失败!";
return false;
}
XRecordDisableContext(display, g_context);
XFlush(display);
XSync(display, false);
XRecordFreeContext(display, g_context); // 释放监听上下文,否则XRecordEnableContext不会退出
g_context = 0;
XCloseDisplay(display);
return true;
}
#endif
......@@ -12,6 +12,9 @@
#include <QObject>
class QMouseEvent;
class QWheelEvent;
/**
* 全局鼠标事件单例信号类
*/
......@@ -29,7 +32,12 @@ public:
static bool removeMouseEvent(); // 卸载全局鼠标事件监听器
signals:
void mouseSignal(QEvent* event);
/**
* @brief 由于传递的是指针,为了保证不会出现内存泄露,需要在槽函数中delete。
* 建议此信号只绑定一次,因为如果绑定多次可能会出现一个槽函数里把信号delete了,另外一个槽函数还在使用,出现野指针,或者多个槽函数多次delete
*/
void mouseEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent* event);
private:
GlobalMouseEvent(){}
......
......@@ -19,30 +19,29 @@ static HHOOK g_hook = nullptr;
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
QPoint point = QCursor::pos(); // 获取鼠标当前位置
qDebug() << wParam;
switch (wParam)
{
case WM_LBUTTONDOWN: // 鼠标左键按下
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
case WM_MOUSEMOVE: // 鼠标移动
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseMove, point, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseMove, point, Qt::NoButton, Qt::NoButton, Qt::NoModifier));
break;
case WM_RBUTTONDOWN: // 鼠标右键按下
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
case WM_RBUTTONUP: // 鼠标右键抬起
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
case WM_LBUTTONUP: // 鼠标左键抬起
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
case WM_MOUSEWHEEL: // 鼠标滚轮
{
MSLLHOOKSTRUCT * msll = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
// qDebug() << QString("坐标:(%1, %2)").arg(msll->pt.x).arg(msll->pt.y); // 获取鼠标坐标
int delta = GET_WHEEL_DELTA_WPARAM(msll->mouseData); // 获取滚轮状态,向前:120,向后-120
emit GlobalMouseEvent::getInstance()->mouseSignal(new QWheelEvent(point, delta, Qt::MiddleButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->wheelEvent(new QWheelEvent(point, delta, Qt::MiddleButton, Qt::NoModifier));
break;
}
default:
......
......@@ -106,10 +106,11 @@ void MouseEventX11()
}
#else
XRecordContext g_context = 0;
Display* g_display = nullptr;
// 使用static修饰全局函数和全局变量:只能在本源文件使用
static XRecordContext g_context = 0;
static Display* g_display = nullptr;
bool init()
static bool init()
{
g_display =XOpenDisplay(nullptr); // 打开与控制显示器的X服务器的连接,详细说明看【https://tronche.com/gui/x/xlib/display/opening.html】
if(!g_display)
......@@ -148,7 +149,7 @@ bool init()
* @param ptr
* @param data
*/
void callback(XPointer ptr, XRecordInterceptData* data)
static void callback(XPointer ptr, XRecordInterceptData* data)
{
Q_UNUSED(ptr)
......@@ -165,27 +166,27 @@ void callback(XPointer ptr, XRecordInterceptData* data)
{
case Button1: // 左键按下
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
}
case Button2: // 中键按下
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button3: // 右键按下
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
}
case Button4: // 向前滚动
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QWheelEvent(point, 120, Qt::MiddleButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->wheelEvent(new QWheelEvent(point, 120, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button5: // 向后滚动
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QWheelEvent(point, -120, Qt::MiddleButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->wheelEvent(new QWheelEvent(point, -120, Qt::MiddleButton, Qt::NoModifier));
break;
}
default:
......@@ -198,7 +199,7 @@ void callback(XPointer ptr, XRecordInterceptData* data)
}
case MotionNotify: // 鼠标移动
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier));
}
case ButtonRelease: // 鼠标释放
{
......@@ -207,17 +208,17 @@ void callback(XPointer ptr, XRecordInterceptData* data)
{
case Button1: // 左键释放
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
break;
}
case Button2: // 中键释放
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier));
break;
}
case Button3: // 右键释放
{
emit GlobalMouseEvent::getInstance()->mouseSignal(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
emit GlobalMouseEvent::getInstance()->mouseEvent(new QMouseEvent(QEvent::MouseButtonRelease, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier));
break;
}
case Button4: // 向前滚动
......@@ -248,7 +249,7 @@ void callback(XPointer ptr, XRecordInterceptData* data)
* X Server 事件一旦发生就传递给事件处理回调函数
* XRecordEnableContext 函数一旦调用就开始进入堵塞时的事件循环,直到线程或所属进程结束
*/
void enableContext()
static void enableContext()
{
Status ret = XRecordEnableContext(g_display, g_context, callback, nullptr);
XCloseDisplay(g_display); // 关闭连接
......
......@@ -4,6 +4,8 @@
# 2、通过封装将Windows鼠标信号转换成Qt鼠标信号;
# 3Linux下使用X11实现全局鼠标事件监听功能;
# 4、通过封装将X11鼠标信号转换为Qt鼠标信号(功能比Windows鼠标钩子强);
# 5Windows下实现全局键盘事件监听器功能;
# 6Linux下通过x11 API获取到全局键盘事件,但是无法将x11键盘事件映射为QKeyEvent
# @编译器: Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
......@@ -12,7 +14,7 @@
# @时间 2022-11-13 22:23:08
# @备注
#---------------------------------------------------------------------------------------
QT += core gui concurrent
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
......@@ -36,7 +38,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 定义程序版本号
VERSION = 1.3.0
VERSION = 1.6.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
contains(QT_ARCH, i386){ # 使用32位编译器
......
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include "globalmouseevent.h"
#include <QMetaEnum>
#include <globalmouseevent.h>
#include "globalkeyevent.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
......@@ -10,28 +11,33 @@ Widget::Widget(QWidget *parent)
{
ui->setupUi(this);
this->setWindowTitle(QString("Qt-自定义全局鼠标监听Demo - V%1").arg(APP_VERSION));
connect(GlobalMouseEvent::getInstance(), &GlobalMouseEvent::mouseSignal, this, &Widget::on_mouseSignal);
this->setWindowTitle(QString("Qt-自定义全局鼠标键盘事件监听Demo - V%1").arg(APP_VERSION));
connect(GlobalMouseEvent::getInstance(), &GlobalMouseEvent::mouseEvent, this, &Widget::on_mouseEvent);
connect(GlobalMouseEvent::getInstance(), &GlobalMouseEvent::wheelEvent, this, &Widget::on_wheelEvent);
connect(GlobalKeyEvent::getInstance(), &GlobalKeyEvent::keyEvent, this, &Widget::on_keyEvent);
}
Widget::~Widget()
{
#if defined(Q_OS_LINUX)
GlobalMouseEvent::removeMouseEvent();
GlobalKeyEvent::removeKeyEvent();
#endif
delete ui;
}
/**
* @brief 获取全局鼠标事件
* @brief 全局鼠标事件
* @param event
*/
void Widget::on_mouseSignal(QEvent* event)
void Widget::on_mouseEvent(QMouseEvent* event)
{
QMouseEvent* me = dynamic_cast<QMouseEvent*>(event);
switch (event->type())
{
case QEvent::MouseButtonPress: // 鼠标按下
{
QString but;
switch (me->button())
switch (event->button())
{
case Qt::LeftButton:
{
......@@ -54,20 +60,20 @@ void Widget::on_mouseSignal(QEvent* event)
break;
}
}
QString str = QString("鼠标%1按下:(x:%2, y:%3)").arg(but).arg(me->x()).arg(me->y());
QString str = QString("鼠标%1按下:(x:%2, y:%3)").arg(but).arg(event->x()).arg(event->y());
ui->textEdit->append(str);
break;
}
case QEvent::MouseMove: // 鼠标移动
{
QString str = QString("鼠标移动:(x:%1, y:%2)").arg(me->x()).arg(me->y());
QString str = QString("鼠标移动:(x:%1, y:%2)").arg(event->x()).arg(event->y());
ui->textEdit->append(str);
break;
}
case QEvent::MouseButtonRelease: // 鼠标右键抬起
{
QString but;
switch (me->button())
switch (event->button())
{
case Qt::LeftButton:
{
......@@ -90,26 +96,29 @@ void Widget::on_mouseSignal(QEvent* event)
break;
}
}
QString str = QString("鼠标%1释放:(x:%2, y:%3)").arg(but).arg(me->x()).arg(me->y());
ui->textEdit->append(str);
break;
}
case QEvent::Wheel: // 鼠标滚轮
{
QWheelEvent* we = dynamic_cast<QWheelEvent*>(event);
QString str = QString("鼠标滚轮:%1,(x:%2, y:%3)").arg(we->delta() > 0 ? "向前" : "向后").arg(we->x()).arg(we->y());
QString str = QString("鼠标%1释放:(x:%2, y:%3)").arg(but).arg(event->x()).arg(event->y());
ui->textEdit->append(str);
break;
}
default:
break;
}
delete event; // 使用完成后记得delete
}
delete event;
/**
* @brief 全局鼠标滚轮事件
* @param event
*/
void Widget::on_wheelEvent(QWheelEvent* event)
{
QString str = QString("鼠标滚轮:%1,(x:%2, y:%3)").arg(event->delta() > 0 ? "向前" : "向后").arg(event->x()).arg(event->y());
ui->textEdit->append(str);
delete event; // 使用完成后记得delete
}
/**
* @brief 安装全局鼠标钩子
* @brief 安装全局鼠标事件监听器
*/
void Widget::on_but_mouseI_clicked()
{
......@@ -118,10 +127,48 @@ void Widget::on_but_mouseI_clicked()
}
/**
* @brief 卸载鼠标钩子
* @brief 卸载全局鼠标事件监听器
*/
void Widget::on_but_mouser_clicked()
{
bool ret = GlobalMouseEvent::removeMouseEvent();
ui->textEdit->append(QString("<<<<<<<<<< 全局鼠标事件监听器卸载%1 >>>>>>>>>>").arg(ret ? "成功" : "失败"));
}
/**
* @brief 全局键盘事件
* @param event
*/
void Widget::on_keyEvent(QKeyEvent* event)
{
QMetaEnum type = QMetaEnum::fromType<QEvent::Type>();
QMetaEnum key = QMetaEnum::fromType<Qt::Key>();
QMetaEnum keyboard = QMetaEnum::fromType<Qt::KeyboardModifiers>();
QString str = QString("状态:[%1]\t按键:[%2]\t修饰:[%3]]").arg(type.valueToKey(event->type()))
.arg(key.valueToKey(event->key()))
.arg(QString(keyboard.valueToKeys(int(event->modifiers()))));
if(!event->text().isEmpty())
{
str += QString("\t字符:[%1]").arg(event->text());
}
ui->textEdit->append(str);
delete event; // 使用完成后记得delete
}
/**
* @brief 安装全局键盘事件监听器
*/
void Widget::on_but_keyI_clicked()
{
bool ret = GlobalKeyEvent::installKeyEvent();
ui->textEdit->append(QString("<<<<<<<<<< 全局键盘事件监听器安装%1 >>>>>>>>>>").arg(ret ? "成功" : "失败"));
}
/**
* @brief 卸载全局键盘事件监听器
*/
void Widget::on_but_KeyR_clicked()
{
bool ret = GlobalKeyEvent::removeKeyEvent();
ui->textEdit->append(QString("<<<<<<<<<< 全局键盘事件监听器卸载%1 >>>>>>>>>>").arg(ret ? "成功" : "失败"));
}
......@@ -16,11 +16,17 @@ public:
~Widget();
private slots:
void on_mouseSignal(QEvent* event);
void on_mouseEvent(QMouseEvent* event);
void on_wheelEvent(QWheelEvent* event);
void on_keyEvent(QKeyEvent* event);
void on_but_mouseI_clicked();
void on_but_mouser_clicked();
void on_but_keyI_clicked();
void on_but_KeyR_clicked();
private:
Ui::Widget *ui;
};
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>581</width>
<height>505</height>
<width>742</width>
<height>530</height>
</rect>
</property>
<property name="font">
......@@ -20,35 +20,65 @@
<string>Widget</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QPushButton" name="but_mouser">
<property name="text">
<string>卸载鼠标钩子</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item row="0" column="0">
<widget class="QTextEdit" name="textEdit"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="but_mouseI">
<property name="text">
<string>安装鼠标钩子</string>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="but_mouseI">
<property name="text">
<string>安装全局鼠标监听器</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_mouser">
<property name="text">
<string>卸载全局鼠标监听器</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="but_keyI">
<property name="text">
<string>安装全局键盘监听器</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="but_KeyR">
<property name="text">
<string>卸载全局键盘监听器</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
......
TEMPLATE = subdirs
SUBDIRS += \
CachedTable \ # 通过QSqlTableModel显示和修改数据,通过按键保存修改内容和恢复修改内容
RelationalTableModel \ # 本示例展示了如何使用QSqlRelationalTableModel(关系表模型)来可视化数据库中[外键]的使用。
SqlWidgetMapper \ # 通过QDataWidgetMapper将数据库数据映射到小部件
TableModel \ # 这个Demo中展示了如何使用具有表视图的专用 SQL 表模型(QSqlTableModel)来编辑数据库中的信息。
TableModel2\ # 这个Demo中展示了如何使用具有表视图的专用 SQL 表模型(QSqlTableModel)来编辑数据库中的信息,实现创建空白数据行、自增key
SignIn # 使用QSqlite数据库实现用户登录、后台管理用户功能
SUBDIRS += TableModel \ # (1) 这个Demo中展示了如何使用具有表视图的专用 SQL 表模型(QSqlTableModel)来编辑数据库中的信息。
SUBDIRS += TableModel2\ # (2) 这个Demo中展示了如何使用具有表视图的专用 SQL 表模型(QSqlTableModel)来编辑数据库中的信息,实现创建空白数据行、自增key
SUBDIRS += CachedTable \ # (3) 通过QSqlTableModel显示和修改数据,通过按键保存修改内容和恢复修改内容
SUBDIRS += RelationalTableModel \ # (4) 本示例展示了如何使用QSqlRelationalTableModel(关系表模型)来可视化数据库中[外键]的使用。
SUBDIRS += SqlWidgetMapper \ # () 通过QDataWidgetMapper将数据库数据映射到小部件
SUBDIRS += SignIn # () 使用QSqlite数据库实现用户登录、后台管理用户功能
......@@ -14,7 +14,7 @@ bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // 使用数据库驱动(Qsqlite)和默认连接名称(qt_sql_default_connection)添加一个数据库
// qDebug() << QSqlDatabase::defaultConnection; // 打印默认数据库连接名称
#if 0
#if 1
db.setDatabaseName("test.db"); // 使用文件数据库(可生成数据库文件,数据一直有效)
#else
db.setDatabaseName(":memory:"); // 使用内存数据库(不会生成数据库文件,所有数据都在内存中进行操作,性能强,程序退出后数据丢失)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册