1.灵感来源
最近想起来之前看见过的一个桌面宠物,会在屏幕的一小部分区域显示一只猫,当用户点击键盘和鼠标的时候,那只猫也会有相应的动作。百般搜索找到那个桌宠软件的名字叫Bongo Cat Mver。回想这个软件的时候,我把BongoCat当成了桌面壁纸软件(然而并不是),既然记错了,那就将错就错吧,做一个可以和用户键盘鼠标交互的桌面壁纸。
2.设计思路
首先选择使用Python开发,之后的实现思路就是监听用户键盘输入,监听用户鼠标点击,在触发相应的事件后修改桌面壁纸,关于桌面壁纸的图片来自于Bongo Cat Mver软件的截屏。
3.准备壁纸
壁纸图片是由Bongo Cat Mver软件运行后通过截屏所得。在用户键盘按下“q,w,e,r,a,s,d,1,2,3,4,5,6,7”按键、鼠标左右键和猫咪待机时,对那只猫的动作进行截屏,总共18张图片,保存到img文件夹。相同的截图动作要重复18次,就想到了用代码来完成截图保存操作,每个图片的名称都由相应的KeyCode来命名,如a.jpg。
import sys
import ctypes
import os
from pynput.keyboard import Key, Listener
import getpass
import shutil
from PIL import ImageGrabkey_list = ['1','2','3','4','5','6','7','a','d','e','q','r','w','s', 'Key.space']
#监听用户键盘输入,有输入时进行全屏截图
def on_press(key):key_char = str(key).replace('\'','')if key_char in key_list:if key_char.isalpha():key_char = key_char.lower()file_path = 'img/' + key_char + '.jpg'abs_path = os.path.abspath(file_path)#这里进行全屏截图pic = ImageGrab.grab()#指定保存图片的位置,可以是当前.py文件的相对路径pic.save(abs_path)#当点击9时进行猫咪待机截屏if key_char not in key_list and key_char == '9':file_path = 'img/start.jpg'abs_path = os.path.abspath(file_path)print(abs_path)pic = ImageGrab.grab()pic.save(abs_path)#为了偷懒,懒得加上鼠标监听,这里当用户按住鼠标右键,再点击数字8时,进行猫咪点击鼠标右键的动作截屏if key_char not in key_list and key_char == '8':file_path = 'img/right.jpg'abs_path = os.path.abspath(file_path)print(abs_path)pic = ImageGrab.grab()pic.save(abs_path)#为了偷懒,懒得加上鼠标监听,这里当用户按住鼠标左键,再点击数字0时,进行猫咪点击鼠标左键的动作截屏if key_char not in key_list and key_char == '0':file_path = 'img/left.jpg'abs_path = os.path.abspath(file_path)print(abs_path)pic = ImageGrab.grab()pic.save(abs_path)def on_release(key):#直接返回True代表不做处理,如果返回False,则无法继续监听用户键盘输入return Trueif __name__ == '__main__':#定义用户键盘监听器with Listener(on_press = on_press, on_release=on_release) as listener:#开始监听listener.join()
关于为什么键盘按键只收集“q,w,e,r,a,s,d,1,2,3,4,5,6,7”,是因为Bongo Cat Mver的鼠标键盘模式只响应这些按键,而我又不会画图......。如果有想法,大家可以画出猫咪点击其他按键的图片。
在运行截图程序前要确定Bongo Cat Mver正常运行,另外点击每个按键的时间不能太短,因为程序截图需要时间执行,如果点击过快,截图只能截到猫咪抬手的图片。
在获得18张全屏图片后,需要裁剪出图片中的猫咪部分,如下图
如果手动截图的话,每张图片的裁剪边界容易产生误差,并且很麻烦,所以这里也是使用了代码来帮助我们裁剪图片(代码真好用),从img文件夹获取全屏截图文件,裁剪后保存到format文件夹中,查看裁剪图片正常后将文件夹改名为resources文件夹(个人习惯,可以不改)。
from PIL import Image
import os#获取img文件夹的全部截图文件
for root, dirs, files in os.walk('img'):#循环遍历每一个截图文件for file in files:#如果是以.jpg结尾的文件,就进行裁剪if os.path.splitext(file)[-1] == '.jpg':img = Image.open("./img/"+file)#img.crop()参数需要一个长度为4的元组,代表裁剪的左,上,右,下四个坐标cropped = img.crop((400, 180, 2520, 1400))#将截取的文件保存到format文件夹cropped.save("./format/"+file)
4.监听用户键盘,鼠标输入
准备好图片后,要在恰当的时机显示恰当的壁纸,恰当的时机指的就是用户键盘和鼠标输入的时机,所以我们需要用Python监听键盘和鼠标的输入,这里使用的是Python的pynput模块。
from pynput.keyboard import Key, Listener
import pynputif __name__ == '__main__':#将猫咪的待机动作设置成初始壁纸start_file = 'resources/start.jpg'abs_path = os.path.abspath(start_file)ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0) # 设置桌面壁纸#添加鼠标监听器mlistener = pynput.mouse.Listener(on_click=on_click)mlistener.start()#添加键盘监听器with Listener(on_press = on_press, on_release=on_release) as listener:listener.join()
关于同时监听键盘和鼠标,不能同时使用两个with语句,因为监听器的join()方法会阻塞程序,这样就只有第一个设置的监听器会起作用,所以鼠标监听器使用的是start()非阻塞方法。
然后自定义on_click(鼠标点击),on_press(键盘按下), on_release(键盘释放)动作发生时的壁纸响应动作。
#鼠标点击时调用该方法
def on_click(x,y,button,pressed):#pressed为True代表用户手指按下鼠标,为False代表用户手指抬起if pressed:#获取鼠标按键的名称,用以区分单机左键还是右键buttonName = str(button)if buttonName == "Button.left":file_path = 'resources/left.jpg'elif buttonName == "Button.right":file_path = 'resources/right.jpg'abs_path = os.path.abspath(file_path)ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0) # 设置桌面壁纸else:#当用户手指抬起,壁纸恢复为猫咪的待机动作start_file = 'resources/start.jpg'abs_path = os.path.abspath(start_file)ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0) # 设置桌面壁纸#键盘按下时调用该方法
def on_press(key):key_char = str(key).replace('\'','')if key_char in key_list:if key_char.isalpha():#防止用户锁定大写,resources文件夹找不到相应图片,转为小写key_char = key_char.lower()#这里通过KeyCode拼接图片路径,也就是为什么图片名称要以KeyCode命名的原因file_path = 'resources/' + key_char + '.jpg'abs_path = os.path.abspath(file_path)ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0) # 设置桌面壁纸#键盘按键松开调用该方法
def on_release(key):#当键盘按键释放,壁纸恢复为猫咪的待机动作start_file = 'resources/start.jpg'abs_path = os.path.abspath(start_file)ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0) # 设置桌面壁纸
最核心的一句设置桌面壁纸的代码是
ctypes.windll.user32.SystemParametersInfoW(20, 0, abs_path, 0)
第一个参数20就代表设置系统的壁纸参数,第三个参数指的是壁纸的绝对路径,这里不能使用相对路径,不然壁纸会被设置为纯黑色。
5.丰富一点细节
在程序启动时,将原本的壁纸保存到resources文件夹,毕竟Bongo Cat Mver放大后能看见像素点(如果有画画高手可以替换Bongo Cat Mver的资源图片为高清的),关闭程序后可以找到原来的壁纸文件。
import getpass
import osdef Get_Background_Path():old_name = "C:/Users/" + getpass.getuser() + "/AppData/Roaming/Microsoft/Windows/Themes/CachedFiles"old_name = old_name + "/" + os.listdir(old_name)[0]resources_path = os.path.abspath('resources')new_name = resources_path + "/back.jpg"shutil.copyfile(old_name, new_name)
6.代码目录
7.运行效果
python桌面壁纸键盘鼠标交互
虽然壁纸的像素并不高,但是已经有了实现思路,只要有高清的图片,就可以替换资源。