如何使用 Qt 禁用 windows(全局)中的键?

How to disable keys in windows (globally) using Qt?

是否可以禁用或阻止某个键,例如 Print Screen 键?

我的事件过滤器:

bool EventFilter::eventFilter(QObject *object, QEvent *event)
{
    qDebug() << "object:" << object << "type:" << event->type();
    return false;
}

我尝试在 qApp 中使用:

ui->setupUi(this);

EventFilter *evt = new EventFilter;

qApp->installEventFilter(evt);

但是 return 只有来自应用程序小部件的事件:

object: QWidgetWindow(0x175bae50, name = "QWidgetClassWindow") type: QEvent::Type(PlatformSurface)
object: QWidget(0x175b02c0) type: QEvent::Type(PlatformSurface)
object: QWidget(0x175b02c0) type: QEvent::Type(WinIdChange)
object: QWidget(0x175b02c0) type: QEvent::Type(Create)
...

并且:

ui->setupUi(this);

EventFilter *evt = new EventFilter;

QDesktopWidget *c = new QDesktopWidget;
c->installEventFilter(evt);

但是return只有2个事件:

object: QDesktopWidget(0x174e0260, name = "desktop") type: QEvent::Type(PolishRequest)
object: QDesktopWidget(0x174e0260, name = "desktop") type: QEvent::Type(Polish)

无法拦截和/或阻止事件?谢谢

您可以安装 low-level keyboard hook 来拦截和阻止所有 Print Screen 按键。下面是在我的windows7机器上测试的

这是一个展示如何执行此操作的最小示例:

#include <QtWidgets>
#include <windows.h>
//link against user32.lib when compiling in MSVC
#ifdef _MSC_VER
#pragma comment(lib, "User32.lib")
#endif

class GlobalPrintScreenBlocker {
public:
    GlobalPrintScreenBlocker():mHKeyboardHook(NULL) {}
    //to avoid leaking the hook procedure handle
    ~GlobalPrintScreenBlocker(){ unblock(); }
    //hook callback function (called on every system-wide key press)
    static LRESULT CALLBACK LowLevelKeyboardProc(int nCode,
                                                 WPARAM wParam, LPARAM lParam) {
        if(nCode == HC_ACTION) {
            PKBDLLHOOKSTRUCT p = reinterpret_cast<PKBDLLHOOKSTRUCT>(lParam);
            if(p->vkCode == VK_SNAPSHOT) return 1; //block print-screen key
        }
        //this is not a message we are interested in
        return CallNextHookEx(NULL, //ignored paramater
                              nCode,
                              wParam,
                              lParam);
    }
    void block(){
        mHKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, //low-level keyboard hool
                                          &LowLevelKeyboardProc, //callback
                                          GetModuleHandle(NULL), 
                                          0);
    }
    void unblock(){
        if(mHKeyboardHook) UnhookWindowsHookEx(mHKeyboardHook);
        mHKeyboardHook = NULL;
    }

private:
    HHOOK mHKeyboardHook;
};

int main(int argc, char* argv[]) {
    QApplication a(argc, argv);

    GlobalPrintScreenBlocker blocker;
    QPushButton button("Disable ScreenShot");
    button.setCheckable(true);
    QObject::connect(&button, &QPushButton::toggled, [&](bool isChecked){
        if(isChecked)
            blocker.block();
        else
            blocker.unblock();
    });
    button.show();

    return a.exec();
}

挂钩在安装它的线程中被调用。这样做的好处是不必担心回调函数中的线程安全问题,并且 32 位进程和 64 位进程之间没有区别(所有进程最终都会通过发布消息到安装钩子的线程的事件循环)。然而,这也有一个缺点,如果你的线程很忙(执行任何其他事情)回调钩子可能不会被调用:

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value ... The value is in milliseconds. If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.

您可以通过为 installing/executing 挂钩分配单独的线程来绕过此限制。另外,请注意,您的钩子的回调函数应尽可能少,以便它能够在时间限制内完成。

P.S.: 我必须使用截图工具来创建上面的屏幕截图。 . .