
對于鍵盤沒有背光燈的同學(xué)而言,切換大小寫或控制Num鍵開關(guān)的時候沒有提示,經(jīng)常需要試探性地輸入一些字符來判斷開關(guān)是否打開,體驗非常糟糕。
因此,有人就想到自制腳本這一招,一旦觸發(fā)大小寫切換或Num鍵切換就進(jìn)行windows通知提示:
https://github.com/skate1512/Toggle_Keys_Notification
今天我們來試試這個腳本,此外,我們還可以基于這個項目,擴(kuò)展成任意一個按鍵被觸發(fā)或切換都進(jìn)行 windows 通知的腳本:

1.準(zhǔn)備
1.準(zhǔn)備
開始之前,你要確保Python和pip已經(jīng)成功安裝在電腦上,如果沒有,可以訪問這篇文章:超詳細(xì)Python安裝指南 進(jìn)行安裝。
(可選1) 如果你用Python的目的是數(shù)據(jù)分析,可以直接安裝Anaconda:Python數(shù)據(jù)分析與挖掘好幫手—Anaconda,它內(nèi)置了Python和pip.
(可選2) 此外,推薦大家用VSCode編輯器,它有許多的優(yōu)點:Python 編程的最好搭檔—VSCode 詳細(xì)指南。
請選擇以下任一種方式輸入命令安裝依賴 :
- Windows 環(huán)境 打開 Cmd (開始-運行-CMD)。
 - MacOS 環(huán)境 打開 Terminal (command+空格輸入Terminal)。
 - 如果你用的是 VSCode編輯器 或 Pycharm,可以直接使用界面下方的Terminal.
 
pip install win10toast
除此之外,我們需要下載作者的代碼,如果你能聯(lián)通GitHub,請前往以下地址下載:
https://github.com/skate1512/Toggle_Keys_Notification
如果不能聯(lián)通GitHub,或者網(wǎng)絡(luò)速度比較慢,請在Python實用寶典公眾號后臺回復(fù):按鍵觸發(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進(jìn)行通知的功能,最核心的_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") # 定義該窗口結(jié)構(gòu)的名稱
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 ** : 獲取一個應(yīng)用程序或動態(tài)鏈接庫的模塊句柄。
** WM_DESTROY ** : 關(guān)閉程序。
** RegisterClass ** : 將定義好的Window屬性保存保存下來。
** WS_OVERLAPPED ** : 重疊式窗口,該式樣窗口 帶有一個標(biāo)題欄和邊框。
** WS_SYSMENU ** : 具有 SYSTEM 菜單欄的樣式
** CW_USEDEFAULT ** : 采用系統(tǒng)默認(rèn)位置
** CreateWindow **這個函數(shù)有非常多的參數(shù),甚至有一個百度百科來詳細(xì)解析每一個參數(shù)的具體作用,大家感興趣可以移步:
https://baike.baidu.com/item/CreateWindow/5076220
了解win32這些模塊名稱的意義后,理解上述代碼的邏輯便很輕松了。
圖標(biāo)加載及任務(wù)欄圖標(biāo)顯示配置:
# 圖標(biāo)
if icon_path is not None:
    # 獲取圖標(biāo)地址
    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)
# 任務(wù)欄圖標(biāo)
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)
這部分代碼控制了通知彈出框的展示和銷毀。如果你希望通知彈出框久一點再消失,可以適當(dāng)修改傳入的 duration 變量值。
DestroyWindow后,通知彈出框便消失了,整個 show_toast 的過程結(jié)束。
其實非常簡單,從 CreateWindow 到 DestroyWindow 處理彈出框的各種屬性,然后注銷窗體,完成整個彈出流程。
3.擴(kuò)展觸發(fā)通知
為了擴(kuò)展監(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是對應(yīng)的按鍵的十六進(jìn)制,比如** VK_NUMLOCK 是Num鍵,對應(yīng)的16進(jìn)制代碼是0x90, VK_CAPITAL **是大小寫按鍵,對應(yīng)的十六進(jìn)制代碼是0x14.
變量名是可以用戶自定義的,比如大小寫鍵有些人習(xí)慣稱之為 ** VK_CAPITAL ** ,也有些人喜歡稱之為  ** VK_CAPITAL ** ,都可以,只要其最終對應(yīng)的變量值為十六進(jìn)制的0x14即可。
部分按鍵16進(jìn)制清單如下(完整版可以閱讀原文查看):
| 常數(shù)名稱 | 十六進(jìn)制值 | 對應(yīng)按鍵 | 
|---|---|---|
| VK_BACK | 08 | Backspace鍵 | 
| VK_TAB | 09 | Tab鍵 | 
| VK_CLEAR | 0C | Clear鍵(Num Lock關(guān)閉時的數(shù)字鍵盤5) | 
| VK_RETURN | 0D | Enter鍵 | 
| VK_SHIFT | 10 | Shift鍵 | 
| VK_CONTROL | 11 | Ctrl鍵 | 
| VK_MENU | 12 | Alt鍵 | 
| VK_PAUSE | 13 | Pause鍵 | 
| VK_CAPITAL | 14 | Caps 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)體中,不斷地獲得當(dāng)前按鍵狀態(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)聽并通知的機(jī)制還是非常簡單的,如果我們想要自定義一些按鍵,你只需要在開頭添加對應(yīng)的按鍵的十六進(jì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)
效果如下:

當(dāng)然,圖標(biāo)和標(biāo)題還可以進(jìn)一步優(yōu)化:
比如將Lock Key State這個標(biāo)題用 toast_title 變量替代,默認(rèn)為Lock Key State。這樣在調(diào)用pop_up函數(shù)的時候就能自定義標(biāo)題了,效果如下:

總而言之,能擴(kuò)展的東西非常多,這只是一個學(xué)習(xí)的例子,如果大家感興趣的話可以在 Python實用寶典 公眾號后臺回復(fù) **按鍵觸發(fā)通知 **下載完整源代碼進(jìn)行改造。
我們的文章到此就結(jié)束啦,如果你喜歡今天的Python 實戰(zhàn)教程,請持續(xù)關(guān)注Python實用寶典。
- 
                                開關(guān)
                                +關(guān)注
關(guān)注
20文章
3301瀏覽量
97264 - 
                                WINDOWS
                                +關(guān)注
關(guān)注
4文章
3624瀏覽量
92986 - 
                                鍵盤
                                +關(guān)注
關(guān)注
4文章
868瀏覽量
41460 - 
                                背光燈
                                +關(guān)注
關(guān)注
1文章
12瀏覽量
8046 
發(fā)布評論請先 登錄
一個判斷操作系統(tǒng)的VBScript腳本代碼
windows補(bǔ)丁批量安裝腳本
Windows通過組策略設(shè)置開機(jī)自啟動腳本
基于腳本的windows與linux之間文件傳輸
使用英特爾Windows和Android平板電腦制作音樂
微軟Windows Core OS消息,通知設(shè)置頁面可實現(xiàn)上下功能關(guān)聯(lián)
微軟又被吐槽 竟向Windows 10用戶推送全屏通知
Windows 10 NVMe SSD警告通知
【shell腳本分享】性能指標(biāo)監(jiān)控與通知!
如何用bat腳本代替按鍵調(diào)試STM32WL HSE XO的負(fù)載電容
    
Python簡單制作Windows按鍵通知腳本
    
Python超簡單制作Windows按鍵通知腳本
    
Python 制作按鍵觸發(fā)Windows通知的腳本
    
          
        
        
制作Windows按鍵通知腳本
                
 
           
            
            
                
            
評論