Edited at

PyQt5:ウィンドウを表示してなくてもキーに反応させる

More than 1 year has passed since last update.

「関連する専門用語を知らなすぎてググれない」状態に苦労させられた.


やったこと

「グローバルホットキー」により,「非アクティブなウィンドウ」で「キーボードフック」させる.

要するに「Ctrl + Cみたいなキー入力」により,「最小化とかタスクトレイに格納とかしてるウィンドウ」でも「キー入力に反応」させる・・・てな感じ.

実際に,Ctrl+Shift+Altでタスクトレイに格納or再表示を繰り返すアプリを作った.



ブラウザをアクティブにしたまま,アプリを隠したり再表示したりできる.

おまけで,タスクトレイのアイコンをクリックしても同じ挙動をする.


  • アプリが最前面にあるが,わざとそうなるプログラムにした

  • 普通だと,トレイに格納→再表示しても,アプリは最前面に来ない

  • つまり,トレイから呼び出すと即アクティブ・・・ができない

    (上のgifでも,再表示されたアプリは非アクティブのまま)


環境


  • Windows10

  • Python3.6 + PyQt5

決まり手:keyboard(ライブラリ名)


boppreh/keyboard


keyboard

Take full control of your keyboard with this small Python library. Hook global events, register hotkeys, simulate key presses and much more.


グローバルホットキーをフックできたのは全部これのおかげ.

PyQtはグローバルキーボードフックをサポートしていないため,諦めるか外部ライブラリに頼るしか手はない.

※最有力にPyGlobalShortcutがあったものの,WindowsでもLinuxでもインストールできなかったため採用見送り.


ソースコード


show_or_hide.py

# -*- coding: utf-8 -*-

import sys
import keyboard
from PyQt5.QtWidgets import QWidget, QApplication, QSystemTrayIcon
from PyQt5.QtGui import QIcon
from PyQt5.Qt import Qt

class Window(QWidget):
tray = QSystemTrayIcon()

def __init__(self):
super().__init__()
iconPath = 'sample_icon.png'

self.setWindowFlags(Qt.WindowStaysOnTopHint) # 常に最前面に表示
self.setWindowTitle('PyQt5 Window Show or Hide') # ウィンドウタイトル
self.setWindowIcon(QIcon(iconPath)) # ウィンドウアイコン

self.tray.setIcon(QIcon(iconPath)) # トレイアイコン
self.tray.activated.connect(self.ShowOrHide) # トレイクリック時
self.tray.show()

# グローバルホットキー:Ctrl+Shift+Altを押した場合
keyboard.add_hotkey('ctrl+shift+alt', lambda: self.ShowOrHide())

def ShowOrHide(self):
# ウィンドウの表示or非表示
if self.isHidden():
self.show()
else:
self.hide()

if __name__ == '__main__':
app = QApplication(sys.argv)
execute = Window()
execute.show()
sys.exit(app.exec_())