按键精灵python脚本_Python 假装自己是按键精灵
按键精灵作为一款模拟鼠标以及键盘操作的软件来说,其有着相当强大的功能。然而可惜的是,按键精灵使用相当过时的VB语言,同时其语法还是老版本的语法,新版VB的特性并不能完全的支持。这使得我有一种想用python来实现的冲动。
下面是我使用按键精灵模拟鼠标点击玩别踩白块的视频。从视频中可以看出来,按键精灵提供的窗口api性能并不算的上太好。(也许是因为我没有进行优化吧)。但是我将整个逻辑搬到python上,并提供了自己所写的api后,速度有了很大的提升。(视频)下面我来简单的谈谈如何使用python完成按键精灵的部分功能。
首先是完成窗口的获取以及窗口大小的判断。这里我不使用python提供的api,而是通过直接加载windows的dll文件来实现的。用的是python提供的ctypes。
获取窗口:
User32 = ctypes.windll.LoadLibrary("User32.dll")
User32.FindWindowW.argtypes=[ctypes.wintypes.LPCWSTR,ctypes.wintypes.LPCWSTR]
User32.FindWindowW.restypes=[ctypes.wintypes.HWND]
wHWND = User32.FindWindowW(None,'Bluestacks App Player')
以及定义窗口大小结构体:
class CRECT(Structure):
_fields_ = [ ("left",c_long),
("top",c_long),
("right",c_long),
("bottom",c_long)]
获取窗口大小:
rect = CRECT()
User32.GetWindowRect.argtypes=[ctypes.wintypes.HWND,ctypes.wintypes.c_void_p]
if not User32.GetWindowRect(wHWND,byref(rect)):
exit(1)
移动鼠标:
def SetCursePos(x,y):
User32.SetCursorPos.argtypes=[ctypes.wintypes.c_int,ctypes.wintypes.c_int]
User32.SetCursorPos(int(x),int(y))
模拟鼠标事件:
def EmuCursorEvent(x,y,event,Abs):
User32.mouse_event.argtypes=[ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.c_void_p]#ULONG_PTR
if Abs:
User32.mouse_event(event|0x8000,x,y,0,None)
else:
User32.mouse_event(event,x,y,0,None)
模拟鼠标点击:
def EmuCursorClick(x,y):
SetCursePos(x,y)
#EmuCursorEvent(x,y,MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP,True)
EmuCursorEvent(0,0,MOUSEEVENTF_LEFTDOWN,False)
time.sleep(0.01)
EmuCursorEvent(0,0,MOUSEEVENTF_LEFTUP,False)
接下来是实现一个速度更快的GetPixel功能。我选择使用GDI的方法,对窗口进行截图,在窗口内使用GetDIBits的方法实现特定位置单点以及多点颜色的查询。新建一个VC++项目,指定生成dll文件,其核心实现部分为:
1. 截屏
SCREENFUNCTION_API HBITMAP __stdcall GetWindowImg(HWND hWnd)
{
HDC dcSrc = GetWindowDC(hWnd);
RECT wRect = { 0, };
GetWindowRect(hWnd, &wRect);
long dwWidth = wRect.right - wRect.left;
long dwHigh = wRect.bottom - wRect.top;
HDC dcDest = CreateCompatibleDC(dcSrc);
HBITMAP hBitmap = CreateCompatibleBitmap(dcSrc, dwWidth, dwHigh);
HGDIOBJ hObj = SelectObject(dcDest, hBitmap);
if (!BitBlt(dcDest, 0, 0, dwWidth, dwHigh, dcSrc, 0, 0, SRCCOPY))
{
OutputDebugString(L"Error While Copy Image!");
}
SelectObject(dcDest, hObj);
DeleteDC(dcDest);
ReleaseDC(hWnd, dcSrc);
return hBitmap;
}
2.单一像素查找:
SCREENFUNCTION_API DWORD32 __stdcall GetWindowPixel(HWND hWnd,int x, int y) {
HBITMAP m_bmp = GetWindowImg(hWnd);
BITMAP bmp;
GetObject(m_bmp, sizeof(BITMAP), &bmp);
HDC hdc = GetDC(NULL);
PBYTE pBits = NULL;
BITMAPINFO bi = { 0, };
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = bmp.bmWidth;
bi.bmiHeader.biHeight = -bmp.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = bmp.bmBitsPixel;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
if (!GetDIBits(hdc, m_bmp, 0, bmp.bmHeight, pBits, &bi, DIB_RGB_COLORS))
{
OutputDebugString(L"Error While Get Header Size");
return 0;
}
pBits = (PBYTE)malloc(bi.bmiHeader.biSizeImage);
ZeroMemory(pBits, bi.bmiHeader.biSizeImage);
if (!GetDIBits(hdc, m_bmp, 0, bmp.bmHeight, pBits, &bi, DIB_RGB_COLORS))
{
free(pBits);
pBits = NULL;
}
int offset = (y - 1)*bmp.bmWidth + x - 1;//可能越界 添加越界检查
DWORD32 RGB = 0;
if (offset > bi.bmiHeader.biSizeImage >> 2 || offset < 0) {
RGB = 0;
OutputDebugString(L"Access Violation!");
}
else
RGB = *((PDWORD32)(pBits)+offset);
free(pBits);
pBits = NULL;
return RGB;
}
3.多像素查找:
SCREENFUNCTION_API int __stdcall GetWindowMultiPixel(HWND hWnd, PINT PosArr, PDWORD32 pRGB)
{
//PosArr end with 0
if (PosArr == NULL)
return 0;
int bufferlen = 0;
while (*(PosArr + bufferlen))
bufferlen++;
if (pRGB == NULL)
{
return (bufferlen + 2)/2;
}
int x, y;
x = 0;
y = 0;
HBITMAP m_bmp = GetWindowImg(hWnd);
BITMAP bmp;
GetObject(m_bmp, sizeof(BITMAP), &bmp);
HDC hdc = GetDC(NULL);
PBYTE pBits = NULL;
BITMAPINFO bi = { 0, };
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = bmp.bmWidth;
bi.bmiHeader.biHeight = -bmp.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = bmp.bmBitsPixel;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
if (!GetDIBits(hdc, m_bmp, 0, bmp.bmHeight, pBits, &bi, DIB_RGB_COLORS))
{
OutputDebugString(L"Error While Get Header Size");
return 0;
}
pBits = (PBYTE)malloc(bi.bmiHeader.biSizeImage);
ZeroMemory(pBits, bi.bmiHeader.biSizeImage);
if (!GetDIBits(hdc, m_bmp, 0, bmp.bmHeight, pBits, &bi, DIB_RGB_COLORS))
{
free(pBits);
pBits = NULL;
}
for (int i = 0; i < bufferlen >> 1; i++)
{
x = *(PosArr + 2 * i);
y = *(PosArr + 2 * i + 1);
int offset = (y - 1)*bmp.bmWidth + x - 1;//可能越界 添加越界检查
DWORD32 RGB = 0;
if (offset > bi.bmiHeader.biSizeImage >> 2 || offset < 0) {
RGB = 0;
OutputDebugString(L"Access Violation!");
}
else
RGB = *((PDWORD32)(pBits)+offset);
*(pRGB + i) = RGB;
}
free(pBits);
pBits = NULL;
return 1;
}
完成后就可以使用ctype调用了。准备工作完成,下面就直接用python调用,获取特定点位置上的颜色,非白色就发送点击指令。然后循环等待下一个黑色块的到来。同时设定定时时间,若长时间依旧是这个颜色,证明游戏结束,直接退出。代码如下:
WindowFunction = ctypes.windll.LoadLibrary("E:\\Python Hack\\DLL\\ScreenFunction.dll")
DllGetPixel = WindowFunction.GetWindowPixel
DllGetPixel.argtypes=[ctypes.wintypes.HWND,ctypes.wintypes.c_int,ctypes.wintypes.c_int]
DllGetPixel.restypes=[ctypes.wintypes.c_uint32]
DllGetMultiPixel = WindowFunction.GetWindowMultiPixel
DllGetMultiPixel.argtypes=[ctypes.wintypes.HWND,ctypes.wintypes.c_void_p,ctypes.wintypes.c_void_p]
DllGetMultiPixel.restypes=[ctypes.wintypes.c_int]
cMulti = (ctypes.wintypes.c_int * 17)(Pos0.x,Pos0.y,Pos1.x,Pos1.y,Pos2.x,Pos2.y,Pos3.x,Pos3.y,
Pos0.x,Pos0.y-5,Pos1.x,Pos1.y-5,Pos2.x,Pos2.y-5,Pos3.x,Pos3.y-5,
0)
dwLen = DllGetMultiPixel(wHWND,byref(cMulti),None)
RGB = (ctypes.wintypes.DWORD * dwLen)()
quit = False
while not quit:
DllGetMultiPixel(wHWND,byref(cMulti),byref(RGB))
flag = 0
if not RGB[0] == 0xfff5f5f5 or not RGB[4] == 0xfff5f5f5:
EmuCursorClick(rect.left+Pos0.x,rect.top+Pos0.y)
flag = 1
elif not RGB[1] == 0xfff5f5f5 or not RGB[5] == 0xfff5f5f5:
EmuCursorClick(rect.left+Pos1.x,rect.top+Pos1.y)
flag = 2
elif not RGB[2] == 0xfff5f5f5 or not RGB[6] == 0xfff5f5f5:
EmuCursorClick(rect.left+Pos2.x,rect.top+Pos2.y)
flag = 3
elif not RGB[3] == 0xfff5f5f5 or not RGB[7] == 0xfff5f5f5:
EmuCursorClick(rect.left+Pos3.x,rect.top+Pos3.y)
flag = 4
cot = 0
if flag == 0:
quit=True
elif flag == 1:
RGB0 = DllGetPixel(wHWND,Pos0.x,Pos0.y) & 0xffffffff
while not RGB0 == 0xfff5f5f5:
time.sleep(0.05)
cot += 1
if cot > 20:
quit=True
break
RGB0 = DllGetPixel(wHWND,Pos0.x,Pos0.y) & 0xffffffff
elif flag == 2:
RGB1 = DllGetPixel(wHWND,Pos1.x,Pos1.y) & 0xffffffff
while not RGB1 == 0xfff5f5f5:
time.sleep(0.05)
cot += 1
if cot > 20:
quit=True
break
RGB1 = DllGetPixel(wHWND,Pos1.x,Pos1.y) & 0xffffffff
elif flag == 3:
RGB2 = DllGetPixel(wHWND,Pos2.x,Pos2.y) & 0xffffffff
while not RGB2 == 0xfff5f5f5:
time.sleep(0.05)
cot += 1
if cot > 20:
quit=True
break
RGB2 = DllGetPixel(wHWND,Pos2.x,Pos2.y) & 0xffffffff
elif flag == 4:
RGB3 = DllGetPixel(wHWND,Pos3.x,Pos3.y) & 0xffffffff
while not RGB3 == 0xfff5f5f5:
time.sleep(0.05)
cot += 1
if cot > 20:
quit=True
break
RGB3 = DllGetPixel(wHWND,Pos3.x,Pos3.y) & 0xffffffff
print 'end'
OK 收工。虽然整个代码风格不像python,更像是脚本化的C语言。但是,谁管哪?好使就行。
python初学,在此留下笔记。
按键精灵python脚本_Python 假装自己是按键精灵相关推荐
- 手机编写python脚本_Python 脚本利用adb 进行手机控制
一. adb 相关命令: 1. 关闭adb服务:adb kill-server 2. 启动adb服务 adb start-server 3. 查询当前运行的所有设备 adb devices 4. ...
- 网页运行python脚本_python脚本和网页有何区别
Python是一种计算机程序设计语言,一种面向对象的动态类型语言,一种脚本语言.最初被设计用于编写自动化脚本(shell)的,常用于各种服务器的维护和自动化运行.它具有丰富和强大的库.它常被昵称为胶水 ...
- python 脚本_python脚本如何同时运行多个
当我们想一次运行多个py脚本的时候你想到了什么应用场景了吗?当你想同时并行的处理一些对象时你有什么好方法吗?下面我就简单的总结一些这方面的小技巧,方便大家根据情况灵活处理. 1 用一个py脚本运行多个 ...
- pycharm定时运行python脚本_Python脚本用于定时关闭网易云音乐PC客户端
本文主要讲述如何使用Python在指定的秒数后关闭Windows上运行的程序(此程序以网易云音乐为例).本文的背景是昨晚发现网易云音乐的PC客户端没有定时关闭的功能,可以使用Python编写一个简单的 ...
- windows双击运行python脚本_Python脚本不能通过双击Windows来执行
对于这样的项目结构:/tumblr /tumblr /module_foo __init__.py submodule_foo.py /module_bar __init__.py submodule ...
- 生物信息学python脚本_Python生物信息学数据管理
内容简介 本书实例意在解决生物学问题,通过"编程技法"的形式,涵盖尽可能多的组织.分析.表现结果的策略.在每章结尾都会有为生物研究者设计的编程题目,适合教学和自学.本书由六部分组成 ...
- 自动化办公python脚本_Python自动化办公
在公司购买的OA系统上,很多功能都是软件商开发好的,如果有什么自定义的需求,也很难实现.现实情况下需要将一个工单的各类信息汇总整理为一份Excel,看似简单的需求,却需要在OA系统上反复点击多次,人工 ...
- 自动打卡python脚本_python实现腾讯文档自动打卡教程
明明365天都不得不待在家里面,居然还要天天去腾讯文档打卡,烦死人了. 天天都填一样的内容,重复无意义的事情,时间就是金钱,浪费人时间约等于谋财害命呀. 所以参考了网络上的代码,并做了改进,用pyt ...
- dnf自动刷图python脚本_python+selenium自动化登录dnf11周年活动界面领取奖励登录部分采坑总结[1]...
背景: Dnf的周年庆活动之一,游戏在6月22日 06:00~6月23日 06:00之间登陆过游戏后可以于6月25日 16:00~7月04日 06:00领取奖励 目标:连续四天自动运行脚本,自动领取所 ...
- 一元二次方程python脚本_Python实现求解一元二次方程的方法示例
本文实例讲述了Python实现求解一元二次方程的方法.分享给大家供大家参考,具体如下: 1. 引入math包 2. 定义返回的对象 3. 判断b*b-4ac的大小 具体计算代码如下: # -*- co ...
最新文章
- ubuntu18安装virtualbox
- 框架、文档、视图类之间的调用关系
- google nexus5x 刷机抓包逆向环境配置(三)
- 你必须知道的10个提高Canvas性能技巧
- mysql为什么使用b 树作为索引_为什么Mysql用B+树作为索引
- 史上最难高考数学,全国平均26分...
- bh1750采集流程图_重大更新:STM32空气监测仪,OneNET物联网平台实时查看(原理图、PCB源文件、程序源码等)...
- 贪婪洞窟2服务器维护,《贪婪洞窟2》11月30日更新维护多久 贪婪洞窟2更新维护公告...
- 正则表达式学习笔记,电话号码、电子邮件、汉字、数字、字母的筛选
- brackets ubuntu
- Delphi中Chrome Chromium、Cef3学习笔记(三)
- python面板数据分析代码_用python预处理面板数据(续)
- Linux篇:Shell脚本实现Gitlab双备份
- 让代码不运行的快捷键html5,使用 vscode 实现写代码双手不用离开键盘
- matlab 去除水印,初試 Matlab 之去除水印
- layui form.js select的扩展插件(转自Author:@贤心)
- proxy代理服务器,实现跨域
- 计算机凭证打印格式设置,打印凭证怎么设置纸张
- 我用Python实现自动化办公,美女同事投来羡慕的眼神,而后···
- Ubuntu20.4环境下,Android11(R)源码,下载,编译,Pixel4刷机