对于键盘没有背光的同学,大小写切换或控制Num键切换时没有任何提示。经常需要试探性地输入一些字符来判断开关是否打开。体验很Oops。于是,有人想到了自制脚本的窍门。一旦触发大写开关或者Num键开关,windows通知提示:https://github.com/skate1512/...\_Keys\_Notification今天我们来试试这个脚本,另外,基于这个项目,我们可以也可以将其扩展成一个脚本,当任何按钮被触发或切换时执行windows通知:1.在开始之前,您必须确保计算机上已成功安装Python和pip。如果没有,请访问这篇文章:超详细的Python安装指南进行安装。如果使用Python进行数据分析,可以直接安装Anaconda:Python数据分析挖掘的好帮手——Anaconda,内置Python和pip。另外,推荐大家使用VSCode编辑器,因为可以在编辑器下方的终端中运行命令安装依赖模块:Python编程最佳搭档——VSCode详解指南。Windows环境打开Cmd(开始-运行-CMD),苹果系统环境打开Terminal(command+空格输入Terminal),输入安装依赖的命令:pipinstallwin10toast另外我们需要下载作者的代码,如果可以联通GitHub,请到以下地址下载:https://github.com/skate1512/...\_Keys\_Notification如果连接不上GitHub,或者网速慢,请后台回复Python实战宝典公众号:按键触发须知下载本文完整源码。2.源码使用与分析2.1源码使用笔者的项目可以在Toggle\_Keys\_Notification项目中运行notify.py来启动监听:pythonnotify.py启动后,点击大小写切换键,触发通知方式代码运行正常:2.2源码分析本项目通过win32gui和win32con实现弹出toast通知功能。核心\_show\_toast代码位于toast.py中。以下是该函数的部分代码分析:注册和创建窗口:`message_map={WM_DESTROY:self.on_destroy,}``#RegisterWindow``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``#窗口格式``style=WS_OVERLAPPED|WS_SYSMENU``#创建窗口``self.hwnd=CreateWindow(self.classAtom,"Taskbar",style,``0,0,CW_USEDEFAULT,``CW_USEDEFAULT,``0,0,self.hinst,None)`的`UpdateWindow(self.hwnd)`使用的win32模块分析如下。GetModuleHandle:获取应用程序或动态链接库的模块句柄。WM\_DESTROY:关闭程序。RegisterClass:保存定义好的Window属性。WS\_OVERLAPPED:重叠窗口,这种风格的窗口有标题栏和边框。WS\_SYSMENU:StylewithSYSTEM菜单栏CW\_USEDEFAULT:使用系统默认位置CreateWindow这个函数的参数非常多,甚至还有百度百科详细分析每个参数的具体作用。有兴趣的可以去:https://baike.baidu.com/item/...了解了win32的这些模块名的含义后,就很容易理解上面代码的逻辑了。图标加载和任务栏图标显示配置:`#icon``ificon_pathisnotNone:``#geticonaddress``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)``exceptase:``logging.error("图标({})有一些问题:{}"``.format(icon_path,e))``hicon=LoadIcon(0,IDI_APPLICATION)``#taskbaricon``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,"BalloonTooltip",msg,200,title,NIIF_ICON_MASK)``#等待一段时间后销毁``sleep(duration)``DestroyWindow(self.hwnd)``UnregisterClass(self.wc.lpszClassName,None)`这部分代码控制了通知弹窗的显示和销毁,如果你想让通知弹窗在一段时间后消失,可以适当修改duration变量的值。DestroyWindow之后,通知弹窗-up框消失,整个show\_toast过程结束。其实很简单。从CreateWindow到DestroyWindow,处理弹出框的各种属性,然后注销窗体,完成整个弹出过程。3.扩展触发通知为了扩展监听的key,能够监听key的触发,需要了解notify.py是如何检测key变化的。获取键状态:`keyboard=ctypes.WinDLL("User32.dll")``VK_NUMLOCK=0x90``VK_CAPITAL=0x14``defget_capslock_state():``"""返回当前大写锁定状态(开/关)"""``如果keyboard.GetKeyState(VK_CAPITAL)返回“CapsLockOn”,否则“CapsLockOff”``defget_numlock_state():``"""返回当前的NumLock状态(开/关)"""``return"NumLockOn"ifkeyboard.GetKeyState(VK_NUMLOCK)else"NumLockOff"`可以看到按键状态是通过keyboard.GetKeyState(XXXX)获取的。而这个XXXX就是对应按键的十六进制,比如VK\_NUMLOCK是Num键,对应的十六进制编码是0x90,VK\_CAPITAL是按键的大小写,对应的十六进制编码是0x14。变量名用户可自定义。比如有些人习惯称它为VK\_CAPITAL,有些人喜欢称它为VK\_CAPITAL。没关系,只要最终对应的变量值为十六进制的0x14即可。能。部分键的十六进制列表如下(可阅读原文查看完整版):常量名十六进制值对应键VK\_BACK08退格键VK\_TAB09Tab键VK\_CLEAR0C清除键(数字小键盘5时NumLockisoff)VK\_RETURN0DEnterKeyVK\_SHIFT10ShiftkeyVK\_CONTROL11CtrlkeyVK\_MENU12AltkeyVK\_PA??USE13PausekeyVK\_CAPITAL14CapsLockkey再来看看监控逻辑:`caps_curr=get_capslock_state()``num_curr=get_numlock_state()``whileTrue:``caps_change=get_capslock_state()``num_change=get_numlock_state()``ifcaps_curr!=caps_change:``ifcaps_change=="CapsLockOn":``pop_up("CapsLockOn","CapsLock_On.ico")``else:``pop_up("CapsLockOff","CapsLock_Off.ico")``caps_curr=caps_change``time.sleep(0.1)``ifnum_curr!=num_change:``ifnum_change=="NumLockOn":`pop_up("NumLockOn","NumLock_On.ico")``else:``pop_up("NumLockOff","NumLock_Off.ico")``num_curr=num_change``时间.睡眠(0。2)`在第一次开始运行监控脚本时,首先获取按钮的状态。在循环体中,您不断获取当前按钮状态。如果状态改变,则触发pop\_up函数,弹出我们刚才提到的show\_toast函数:`defpop_up(body,icon):``"""状态改变时生成Pop-up通知"""``通知cation=ToastNotifier()``notification.show_toast("LockKeyState",body,icon_path="assets\\"+icon,duration=1.5)`整个监听和通知机制很简单,如果我们要定义有些按键,只需要在开头加上相应按键的十六进制代码,再加上一些监控功能即可。比如我们要监听ESC键被按下:VK\_ESCAPE\=0x1B,使用键盘模块添加一个钩子函数,Listeningforkeys:`importkeyboardaskb``defhook_esc(button):``"""如果ESC按钮被按下,则发出警报"""``esc_button=kb.KeyboardEvent('down',VK_ESCAPE,'ESC')``ifbutton.event_type=='down'andesc_button.name==button.name:``pop_up("ESCPressed","CapsLock_On.ico")``#backfilltoNoneaftertapping``button.event_type=None`然后在循环体中加入判断逻辑:kb.hook(hook_esc)效果如下:当然icon和title还可以进一步优化:比如把titleLockKeyState换成toast\_title变量,默认是LockKeyState。这样调用pop\_up函数的时候就可以自定义title了,效果如下:总而言之,可以展开的东西很多。这只是一个学习示例。感兴趣的可以在Python实战宝典后台回复公众号击键触发通知下载完整源码进行改造。这是我们文章的结尾。如果喜欢今天的Python实战教程,请继续关注Python实战宝典。有问题可以在公众号后台回复:进群,回答对应的红字验证信息,进入互助群提问。原创不易,希望大家能在下方点赞观看支持我继续创作,谢谢!点击下方阅读原文,更好的阅读体验Python实战宝典(pythondict.com)不只是合集欢迎关注公众号:Python实战宝典
