【问题标题】:Clipboard Shortcut/Hotkey binding with Qt outside of application剪贴板快捷方式/热键与应用程序外部的 Qt 绑定
【发布时间】:2013-08-29 07:42:24
【问题描述】:

我试过谷歌搜索,并在这个网站上搜索这个但无济于事。

我正在使用 Qt 为 Windows 构建一个与剪贴板相关的应用程序,它正常工作的要求之一是能够在我的 Qt 应用程序之外注册键盘事件,例如 ctrl + c、ctrl + v。(复制/粘贴)。我在网上唯一找到的是使用 Qt 的外部插件,但整个概念没有得到正确解释,所以我走到了死胡同。

有人知道我该怎么做吗?同样,我想为我的应用程序注册快捷方式,这些快捷方式将出现在应用程序本身之外。

提前致谢!

【问题讨论】:

标签: c++ windows qt


【解决方案1】:

我发现,绑定剪贴板快捷方式和绑定快捷方式通常是两个不同的东西。与剪贴板事件相关,Qt 通过其QClipboard 类提供对dataChanged() 信号的访问。使用它,您可以知道剪贴板数据何时发生变化,并采取相应的行动,并且应该消除对复制/粘贴快捷方式执行系统范围绑定的需要。

为了注册一个全局快捷方式(在这种情况下需要 ctrl + v),并且这是特定于平台的,就像我的需要一样,可以在 Windows 下使用RegisterHotKey 函数。作为第一个参数请求的HWND可以从QWidget提供的winId函数中获取。

为了接受 WM_HOTKEY 事件,必须在 Qt winEvent 虚拟保护函数,在 >= 5.0 上实现 nativeEvent

【讨论】:

    【解决方案2】:

    这取决于应用程序运行的桌面环境,并且是特定于操作系统的。如果您打算在 KDE 中运行应用程序,您可以通过在应用程序中部署 .desktop 文件或向 /usr/share/kde4/apps/khotkeys 添加内容来轻松注册全局热键。

    在 Windows 中,最简单的方法可能是将注册表项添加到注册表中以注册全局热键。见MSDN

    【讨论】:

    • 正如我所说,这是针对 Windows 的。
    【解决方案3】:

    我认为您只是对剪贴板的工作方式感到困惑。您永远不需要在应用程序之外注册与剪贴板相关的热键。这些由其他应用程序处理。这些应用程序所做的是与系统范围的剪贴板交互。您的应用程序需要与同一个剪贴板进行交互并获得有关新剪贴板数据可用等的通知。

    如果您告诉我们您所说的“剪贴板相关”应用程序是什么意思,您可能会得到更多有用的答案。它是用来卖木制剪贴板的吗?或者校准剪贴板弹簧?或者管理剪贴板的库存?还是在数字剪贴板上运行?叹息。

    【讨论】:

      【解决方案4】:

      这应该让您在 Windows+Qt 和 HotKeys 中快速启动并运行。

      我还没有尝试过使用QxtGlobalShortcut 的Qt eXTension 库,但听起来它可能是针对更多平台的更优雅的完整解决方案。 (就像@TimMeyer 对您的问题的评论)

      https://stackoverflow.com/a/3154652/808151

      我编写了这个函数来监听 Windows 中的单个系统范围的热键。

      #ifndef HOTKEYTHREAD_H
      #define HOTKEYTHREAD_H
      
      #include <QThread>
      
      #define WIN32_LEAN_AND_MEAN
      #include <Windows.h>
      
      class HotKeyThread : public QThread
      {
          Q_OBJECT
      
      public:
          HotKeyThread(QObject *parent);
          ~HotKeyThread();
      signals:
          void hot_key_event(int);
      public slots:
          void run();
          void stop();
      private:
          volatile bool m_stopped;
          DWORD m_thread_id;
      };
      
      #endif // HOTKEYTHREAD_H
      

      .cpp 文件

      #include "hotkeythread.h"
      
      #include <QDebug>
      #include <process.h> 
      
      #define WM_END_THREAD (WM_USER+2)
      
      HotKeyThread::HotKeyThread(QObject *parent)
          : QThread(parent)
      {
          this->m_thread_id = 0;
      }
      
      HotKeyThread::~HotKeyThread()
      {
      
      }
      
      void HotKeyThread::stop()
      {
          if(this->m_thread_id != 0)
              ::PostThreadMessage(this->m_thread_id, WM_END_THREAD, 0, 0);
      }
      
      //
      void HotKeyThread::run()
      {
          // store a thread id so we can exit later
          m_thread_id = ::GetCurrentThreadId();
      
          qDebug() << "ThreadIDs" << QString::number(m_thread_id, 16) << QString::number((int) this->currentThreadId(), 16);
      
          // register an atom, and a hotkey
          BOOL retVal;
          int counter = 0;
          int magic_num = 1128;
          ATOM id = ::GlobalAddAtom(MAKEINTATOM(magic_num + counter++));
      
          // http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
          int modifier = 0x0;// modify this line
          int key = VK_NUMPAD0;// modify this line
          if(QSysInfo::windowsVersion() > QSysInfo::WV_VISTA)
          {
              retVal = ::RegisterHotKey(NULL, id, modifier | MOD_NOREPEAT, key);
          }
          else
          {
              // No repeat is only supported in 7 and later
              retVal = ::RegisterHotKey(NULL, id, modifier, key);
          }
      
          if(retVal)
          {
              qDebug() << "Successfully added a HotKey!";
          }
          else
          {
              qDebug() << "Failed to add a hotkey!";
              return;
          }
      
          // wait on hotkeys
          MSG msg = {0};
          while (0 < ::GetMessage(&msg, NULL, 0, 0))
          {
              if(msg.message == WM_HOTKEY)
              {
                  bool control = LOWORD(msg.lParam) & MOD_CONTROL;
                  bool shift = LOWORD(msg.lParam) & MOD_SHIFT;
                  bool alt = LOWORD(msg.lParam) & MOD_ALT;
                  bool win = LOWORD(msg.lParam) & MOD_WIN;
                  qDebug() << "HotKey!" << (control ? "Ctrl +": "") 
                      << (alt ? "Alt +": "")
                      << (shift ? "Shift +":"") 
                      << (win ? "Win +":"") << QString::number(HIWORD(msg.lParam),16);
                  // TODO Notify MainWindow of the event
                  emit hot_key_event(msg.lParam);
              }
              else if(msg.message == WM_END_THREAD)
              {
                  // exit
                  break;
              }
          }
      
          // Clean up Hotkey
          ::UnregisterHotKey(NULL, id);
          ::GlobalDeleteAtom(id);
      }
      

      在您的 GUI 中使用

       // Start HotKey Thread!
       m_hot_key_thread = new HotKeyThread(this);
       QObject::connect(m_hot_key_thread, SIGNAL(hot_key_event(int)), 
                   this, SLOT(handle_hot_key_event(int)), Qt::QueuedConnection);
       m_hot_key_thread->start();
      

      当你的程序关闭时

       m_hot_key_thread->stop();
      

      希望对您有所帮助。

      【讨论】:

      • 您是否考虑添加一些 cmets 来解释一切的含义和/或它的作用,以及如何使用它而不是仅仅使用它?这将帮助人们根据自己的目的对其进行自定义。
      • 看到有评论// modify this line的两行?在那里输入一个特定的虚拟键盘代码和任何你想要的修饰符。然后你的程序将接收来自 Windows 事件的信号到 Qt Slots。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多