<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 制作按鍵觸發(fā)Windows通知的腳本

          共 5589字,需瀏覽 12分鐘

           ·

          2020-12-14 04:33



          對于鍵盤沒有背光燈的同學而言,切換大小寫或控制Num鍵開關的時候沒有提示,經(jīng)常需要試探性地輸入一些字符來判斷開關是否打開,體驗非常糟糕。

          因此,有人就想到自制腳本這一招,一旦觸發(fā)大小寫切換或Num鍵切換就進行windows通知提示:

          https://github.com/skate1512/Toggle_Keys_Notification

          今天我們來試試這個腳本,此外,我們還可以基于這個項目,擴展成任意一個按鍵被觸發(fā)或切換都進行 windows 通知的腳本:

          1.準備

          開始之前,你要確保Python和pip已經(jīng)成功安裝在電腦上,如果沒有,請訪問這篇文章:超詳細Python安裝指南?進行安裝。如果你用Python的目的是數(shù)據(jù)分析,可以直接安裝Anaconda:Python數(shù)據(jù)分析與挖掘好幫手—Anaconda,它內(nèi)置了Python和pip.

          此外,推薦大家用VSCode編輯器,因為它可以在編輯器下方的終端運行命令安裝依賴模塊:Python 編程的最好搭檔—VSCode 詳細指南

          Windows環(huán)境下打開 Cmd (開始-運行-CMD),蘋果系統(tǒng)環(huán)境下請打開 Terminal (command+空格輸入Terminal),輸入命令安裝依賴:

          pip?install?win10toast


          除此之外,我們需要下載作者的代碼,如果你能聯(lián)通GitHub,請前往以下地址下載:
          https://github.com/skate1512/Toggle_Keys_Notification

          如果不能聯(lián)通GitHub,或者網(wǎng)絡速度比較慢,請在Python實用寶典公眾號后臺回復:按鍵觸發(fā)通知?下載本文完整源代碼。

          2.源碼使用與解析

          2.1 源碼使用

          作者的項目可以在 Toggle_Keys_Notification 項目內(nèi),運行 notify.py 啟動監(jiān)聽:

          python?notify.py


          啟動后點擊一下大小寫切換鍵,觸發(fā)通知則說明代碼正常運轉(zhuǎn):


          2.2 源碼分析

          該項目通過win32gui和win32con實現(xiàn)了彈出toast進行通知的功能,最核心的_show_toast代碼位于 toast.py 中,下面是這個函數(shù)的部分代碼剖析:

          注冊和創(chuàng)建 window :

          message_map = {WM_DESTROY: self.on_destroy, }
          # 注冊Window
          self.wc = WNDCLASS()
          self.hinst = self.wc.hInstance = GetModuleHandle(None)
          self.wc.lpszClassName = str("PythonTaskbar") # 定義該窗口結構的名稱
          self.wc.lpfnWndProc = message_map
          try:
          ????self.classAtom = RegisterClass(self.wc)
          except:
          ????pass
          # Window格式
          style = WS_OVERLAPPED | WS_SYSMENU
          # 創(chuàng)建Window
          self.hwnd = CreateWindow(self.classAtom, "Taskbar", style,
          ?????????????????????????0, 0, CW_USEDEFAULT,
          ?????????????????????????CW_USEDEFAULT,
          ?????????????????????????0, 0, self.hinst, None)
          UpdateWindow(self.hwnd)


          所使用到的win32模塊解析如下。

          GetModuleHandle: 獲取一個應用程序或動態(tài)鏈接庫的模塊句柄。
          WM_DESTROY: 關閉程序。
          RegisterClass: 將定義好的Window屬性保存保存下來。
          WS_OVERLAPPED: 重疊式窗口,該式樣窗口 帶有一個標題欄和邊框。
          WS_SYSMENU: 具有 SYSTEM 菜單欄的樣式
          CW_USEDEFAULT: 采用系統(tǒng)默認位置

          CreateWindow??這個函數(shù)具有非常多的參數(shù),甚至有一個百度百科來詳細解析每一個參數(shù)的具體作用,大家感興趣可以移步:
          https://baike.baidu.com/item/CreateWindow/5076220

          了解win32這些模塊名稱的意義后,理解上述代碼的邏輯便很輕松了。

          圖標加載及任務欄圖標顯示配置:

          # 圖標
          if?icon_path is not None:
          ????# 獲取圖標地址
          ????icon_path = path.realpath(icon_path)
          else:
          ????icon_path = resource_filename(Requirement.parse("win10toast"), "win10toast/data/python.ico")
          # 加載格式
          icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE
          try:
          ????hicon = LoadImage(self.hinst, icon_path, IMAGE_ICON, 0, 0, icon_flags)
          except Exception?as?e:
          ????logging.error("Some trouble with the icon ({}): {}"
          ??????????????????.format(icon_path, e))
          ????hicon = LoadIcon(0, IDI_APPLICATION)
          # 任務欄圖標
          flags = NIF_ICON | NIF_MESSAGE | NIF_TIP
          nid = (self.hwnd, 0, flags, WM_USER + 20, hicon, "Tooltip")
          Shell_NotifyIcon(NIM_ADD, nid)
          Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, WM_USER + 20, hicon, "Balloon Tooltip", msg, 200, title, NIIF_ICON_MASK))

          # 等待一會后銷毀
          sleep(duration)
          DestroyWindow(self.hwnd)
          UnregisterClass(self.wc.lpszClassName, None)


          這部分代碼控制了通知彈出框的展示和銷毀。如果你希望通知彈出框久一點再消失,可以適當修改傳入的 duration 變量值。

          DestroyWindow后,通知彈出框便消失了,整個 show_toast 的過程結束。

          其實非常簡單,從 CreateWindow 到 DestroyWindow 處理彈出框的各種屬性,然后注銷窗體,完成整個彈出流程。

          3.擴展觸發(fā)通知

          為了擴展監(jiān)聽的按鍵,并能監(jiān)聽按鍵觸發(fā),需要先了解 notify.py 是如何檢測到按鍵變化的。

          獲取按鍵狀態(tài):

          keyboard = ctypes.WinDLL("User32.dll")
          VK_NUMLOCK =?0x90
          VK_CAPITAL =?0x14
          def?get_capslock_state():
          ????"""Returns the current Caps Lock State(On/Off)"""
          ????return?"Caps Lock On"?if?keyboard.GetKeyState(VK_CAPITAL)?else?"Caps Lock Off"


          def?get_numlock_state():
          ????"""Returns The current Num Lock State(On/Off)"""
          ????return?"Num Lock On"?if?keyboard.GetKeyState(VK_NUMLOCK)?else?"Num Lock Off"


          可以看到,獲取按鍵狀態(tài)是通過?keyboard.GetKeyState(XXXX) 實現(xiàn)的。

          而這個XXXX是對應的按鍵的十六進制,比如 VK_NUMLOCK 是Num鍵,對應的16進制代碼是0x90,VK_CAPITAL 是大小寫按鍵,對應的十六進制代碼是0x14.

          變量名是可以用戶自定義的,比如大小寫鍵有些人習慣稱之為VK_CAPITAL,也有些人喜歡稱之為?VK_CAPITAL,都可以,只要其最終對應的變量值為十六進制的0x14即可。

          部分按鍵16進制清單如下(完整版可以閱讀原文查看):

          常數(shù)名稱十六進制值對應按鍵
          VK_BACK08Backspace鍵
          VK_TAB09Tab鍵
          VK_CLEAR0CClear鍵(Num Lock關閉時的數(shù)字鍵盤5)
          VK_RETURN0DEnter鍵
          VK_SHIFT10Shift鍵
          VK_CONTROL11Ctrl鍵
          VK_MENU12Alt鍵
          VK_PAUSE13Pause鍵
          VK_CAPITAL14Caps Lock鍵


          再來看看監(jiān)聽邏輯:

          caps_curr = get_capslock_state()
          num_curr = get_numlock_state()

          while?True:
          ????caps_change = get_capslock_state()
          ????num_change = get_numlock_state()

          ????if?caps_curr != caps_change:
          ????????if?caps_change == "Caps Lock On":
          ????????????pop_up("Caps Lock On", "CapsLock_On.ico")
          ????????else:
          ????????????pop_up("Caps Lock Off", "CapsLock_Off.ico")
          ????????caps_curr = caps_change
          ????????time.sleep(0.1)

          ????if?num_curr != num_change:
          ????????if?num_change == "Num Lock On":
          ????????????pop_up("Num Lock On", "NumLock_On.ico")
          ????????else:
          ????????????pop_up("Num Lock Off", "NumLock_Off.ico")
          ????????num_curr = num_change
          ????time.sleep(0.2)


          在剛開始運行監(jiān)聽腳本時,先獲取到按鍵的狀態(tài),在循環(huán)體中,不斷地獲得當前按鍵狀態(tài),如果發(fā)生了狀態(tài)變化,則觸發(fā)pop_up函數(shù),彈出剛剛我們提到的show_toast 函數(shù):

          def?pop_up(body, icon):
          ????"""Generates Pop-up notification when state changes"""
          ????notification = ToastNotifier()
          ????notification.show_toast("Lock Key State", body, icon_path="assets\\"+icon, duration=1.5)


          整套監(jiān)聽并通知的機制還是非常簡單的,如果我們想要自定義一些按鍵,你只需要在開頭添加對應的按鍵的十六進制編碼,然后添加一些監(jiān)聽函數(shù)。

          比如我們想監(jiān)聽 ESC 按鍵被按下:VK_ESCAPE=0x1B,使用 keyboard 模塊添加一個鉤子函數(shù),監(jiān)聽按鍵:

          import?keyboard?as?kb
          def?hook_esc(button):
          ????"""Alert if ESC button is pressed"""
          ????esc_button = kb.KeyboardEvent('down', VK_ESCAPE,?'ESC')
          ????if?button.event_type ==?'down'?and?esc_button.name == button.name:
          ????????pop_up("ESC Pressed",?"CapsLock_On.ico")
          ????????# 敲擊后回填為None
          ????????button.event_type =?None


          然后再在循環(huán)體內(nèi)添加判斷邏輯:

          kb.hook(hook_esc)


          效果如下:


          當然,圖標和標題還可以進一步優(yōu)化:

          比如將Lock Key State這個標題用 toast_title 變量替代,默認為Lock Key State。這樣在調(diào)用pop_up函數(shù)的時候就能自定義標題了,效果如下:

          總而言之,能擴展的東西非常多,這只是一個學習的例子,如果大家感興趣的話可以在 Python實用寶典 公眾號后臺回復?按鍵觸發(fā)通知?下載完整源代碼進行改造。

          我們的文章到此就結束啦,如果你喜歡今天的Python 實戰(zhàn)教程,請持續(xù)關注Python實用寶典。

          有任何問題,可以在公眾號后臺回復:加群,回答相應紅字驗證信息,進入互助群詢問。

          原創(chuàng)不易,希望你能在下面點個贊和在看支持我繼續(xù)創(chuàng)作,謝謝!

          點擊下方閱讀原文可獲得更好的閱讀體驗

          Python實用寶典?(pythondict.com)
          不只是一個寶典
          歡迎關注公眾號:Python實用寶典

          瀏覽 64
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天堂免费在线视频 | 免费视频无码 | 国产天堂在线观看视频 | 影音先锋男人的 | 三区七区九区一区在线 |