一.簡介
鼠標軌跡算法是一種模擬人類鼠標操作的程序,它能夠模擬出自然而真實的鼠標移動路徑。
鼠標軌跡算法的底層實現采用C/C++語言,原因在于C/C++提供了高性能的執行能力和直接訪問操作系統底層資源的能力。
鼠標軌跡算法具有以下優勢:
- 模擬人工軌跡:算法能夠模擬出非貝塞爾曲線的自然鼠標移動,避免了機械式的直線移動。
- 適當的停頓/加速/減速:算法能夠根據需要模擬出鼠標的停頓、加速和減速,使得軌跡更加真實。
- 隨機軌跡:在固定兩點間,算法能夠生成不同的隨機軌跡,增加了軌跡的不可預測性。
二.應用場景
- 游戲鼠標軌跡檢測(檢測能過無畏fps類型、傳奇、夢幻等游戲,已經在游戲中驗證)
- 滑塊拖動驗證
- 部分網頁鼠標軌跡檢測
三.支持多種編程語言
1.C++頭文件
/******************************************************************************************/@SDK功能描述:C++鼠標軌跡/******************************************************************************************/#ifndef _SN_SDK_H__
#define _SN_SDK_H__#include <windows.h>enum SN_TRACK_MOVE_TYPE
{TRACK_MOVE_TYPE_NORMAL=0, // 用于常規軌跡 - 普通游戲鼠標軌跡TRACK_MOVE_TYPE_SLIDER, // 用于滑塊軌跡,比常規常規軌跡密度更大 - 滑塊驗證軌跡
};enum SN_TRACK_POINT_TYPE
{TRACK_POINT_TYPE_NORMAL=0, // 默認絕對坐標TRACK_POINT_TYPE_RELATIVE, // 相對坐標
};//返回參數
typedef struct SN_RESULT {int code; //錯誤碼,如果為 0 表示成功,否則表示錯誤號char message[4096]; //錯誤信息,如果為 "OK" 表示成功,否則返回錯誤信息}SN_RESULT;//坐標參數
typedef struct SN_POINT
{int x; //屏幕坐標,左上角(0,0),右下角(1920,1080 - 以實際屏幕為準)int y; //屏幕坐標,左上角(0,0),右下角(1920,1080 - 以實際屏幕為準)}SN_POINT;//軌跡參數
typedef struct SN_POINT_PARAMS
{struct SN_POINT point;//屏幕坐標,左上角(0,0),右下角(1920,1080 - 以實際屏幕為準)int delayTime; //延時時間(單位:毫秒),僅供參考}SN_POINT_PARAMS;/*創建句柄
*
* 參數:
* [in] szKey: 卡密(購買卡密:https://shop.4yuns.com/links/7C9F16B7)
* [in] pOnnxFilePath:設置 onnx 模型文件路徑,如果設置為 NULL,默認和 DLL文件同級目錄
* [out] pResult: 返回錯誤信息,參數pResult.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
* 返回值:成功返回句柄,失敗返回NULL
*
*/
HANDLE WINAPI apiSNCreateHandle(char* szKey, char* pOnnxFilePath, SN_RESULT* pResult);/*設置鼠標移動軌跡參數,調節軌跡密度/速度/軌跡類型,目前可以支持滑塊軌跡/普通軌跡
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
* [in] density: 軌跡密度調節 ,必須大于或者等于 1,默認 5,舉個例子:假如軌跡有 100 個點,累計耗時 1000 毫秒,設置 density 如下:
* - density = 1 時,軌跡有 100/1=100 個點,整個軌跡累計耗時 1000/1=1000 毫秒 (默認 1 倍速度)
* - density = 2 時,軌跡有 100/2=50 個點,整個軌跡累計耗時 1000/2=500 豪秒 (等價 2 倍速度)
* - density = 3 時,軌跡有 100/3=33 個點,整個軌跡累計耗時 1000/3=333 豪秒 (等價 3 倍速度)
* - density = 5 時,軌跡有 100/5=20 個點,整個軌跡累計耗時 1000/5=200 豪秒 (等價 5 倍速度)
* - density = 20 時,軌跡有 100/20=5 個點,整個軌跡累計耗時 1000/20=50 豪秒 (等價 20 倍速度)
*
* [in] type: 軌跡類型(0代表絕對普通軌跡,1代表滑塊軌跡(獲得的軌跡點數比普通軌跡點數更多),具體參考enum SN_TRACK_MOVE_TYPE)
*
* 返回值:返回參數SN_RESULT.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
*/
int WINAPI apiSNSetTrackParams(HANDLE handle, int density=5, int type=0);/*獲取鼠標移動軌跡
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
* [in] startPoint: 開始坐標,左上角(0,0),右下角(1920,1080 - 以實際屏幕為準)
* [in] endPoint: 結束坐標,左上角(0,0),右下角(1920,1080 - 以實際屏幕為準)
* [in] type: 軌跡坐標類型(0代表絕對坐標,1代表相對坐標,具體參考enum SN_TRACK_POINT_TYPE)
* [out] points: 軌跡數組,如果數組中元素 point 出現(10000,10000),表示鼠標軌跡結束
*
* 返回值:返回參數SN_RESULT.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
*/
int WINAPI apiSNMouseMove(HANDLE handle, SN_POINT *startPoint, SN_POINT *endPoint, int type, SN_POINT_PARAMS* points);/*獲取版本號
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
* [out] szVersion: 版本號
*
* 返回值:返回參數SN_RESULT.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
*/
int WINAPI apiSNGetVersion(HANDLE handle, char* szVersion);/*獲取卡密到期時間
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
* [out] pResult: 返回錯誤信息,參數pResult->code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
* 返回值:返回卡密到期時間,失敗返回NULL,錯誤信息請查看參數 pResult->message
*
*/
char* WINAPI apiSNGetKeyExpiresTime(HANDLE handle, SN_RESULT* pResult);/*獲取錯誤信息
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
*
* 返回值:返回參數SN_RESULT.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
*/
int WINAPI apiSNGetError(HANDLE handle);/*釋放句柄(內存)
*
* 參數:
* [in] handle: 句柄(通過調用apiSNCreateHandle得到)
*
* 返回值:返回參數SN_RESULT.code(錯誤碼)如果為 0 表示成功,否則表示錯誤號;
*
*/
int WINAPI apiSNDestroyHandle(HANDLE handle);#endif // !_SN_SDK_H__
2.其他編程語言
為了易于集成和使用,我們將鼠標軌跡算法封裝為DLL(動態鏈接庫)。這種封裝方式不僅保留了算法的性能優勢,還提供了跨平臺和跨語言的兼容性,目前支持編程語言如下:
- C++
- Python
- 易語言
推算軌跡算法耗時均為毫秒級,<= 5ms ,速度超快,fps類型游戲完全無壓力!
3.鼠標軌跡API調用流程圖
注意:如果是多線程,每個線程都需要通過apiSNCreateHandle創建HANDLE句柄,這樣才能多個線程互不影響
4.加載C++鼠標軌跡dll接口
'''@SDK功能描述:鼠標軌跡'''
from ctypes import cdll, Structure, c_int, c_char, c_char_p, POINTER, create_string_buffer
import ctypes
import platform
class SN_RESULT(ctypes.Structure):_fields_ = [("code", ctypes.c_int),("message", ctypes.c_char * 4096)]class SN_POINT(ctypes.Structure):_fields_ = [("x", ctypes.c_int),("y", ctypes.c_int)]class SN_POINT_PARAMS(ctypes.Structure):_fields_ = [("point", SN_POINT),("delayTime", ctypes.c_int)]class SN_MOUSE_TRACK_SDK:def __init__(self, key, onnx_path, dll_path):self.key = key.encode('utf-8')self.onnx_path = onnx_path.encode('utf-8')self.sn_sdk = ctypes.WinDLL(dll_path)self.handle = Noneself.result = SN_RESULT()self._initialize_sdk()def _initialize_sdk(self):self.sn_sdk.apiSNCreateHandle.argtypes = [ctypes.POINTER(ctypes.c_char), ctypes.POINTER(ctypes.c_char),ctypes.POINTER(SN_RESULT)]self.sn_sdk.apiSNCreateHandle.restype = ctypes.c_void_p# 檢測當前是 x64 還是 x86print(platform.architecture())self.handle = self.sn_sdk.apiSNCreateHandle(self.key, self.onnx_path, ctypes.byref(self.result))if self.result.code != 0:print(f"Failed to create handle: {self.result.message.decode('gbk', errors='replace')}")else:print("sn_sdk.apiSNCreateHandle success")def get_version(self):version = ctypes.create_string_buffer(4096)self.sn_sdk.apiSNGetVersion.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_char)]self.sn_sdk.apiSNGetVersion.restype = ctypes.c_intif self.handle is None:print("apiSNCreateHandle fail!")return ""result = self.sn_sdk.apiSNGetVersion(self.handle, version)if result != 0:raise Exception(f"Failed to get version: {result}")return version.value.decode()def set_track_params(self, density, other_param):self.sn_sdk.apiSNSetTrackParams.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]self.sn_sdk.apiSNSetTrackParams.restype = ctypes.c_intreturn self.sn_sdk.apiSNSetTrackParams(self.handle, density, other_param)def get_key_expires_time(self):self.sn_sdk.apiSNGetKeyExpiresTime.argtypes = [ctypes.c_void_p, ctypes.POINTER(SN_RESULT)]self.sn_sdk.apiSNGetKeyExpiresTime.restype = ctypes.c_char_pif self.handle is None:print("apiSNCreateHandle fail!")return ""return self.sn_sdk.apiSNGetKeyExpiresTime(self.handle, ctypes.byref(self.result))def move_mouse(self, start_point, end_point, type, num_points=4096):points_array = (SN_POINT_PARAMS * num_points)()self.sn_sdk.apiSNMouseMove.argtypes = [ctypes.c_void_p, POINTER(SN_POINT), POINTER(SN_POINT), ctypes.c_int,POINTER(SN_POINT_PARAMS)]self.sn_sdk.apiSNMouseMove.restype = ctypes.c_intif self.handle is None:print("apiSNCreateHandle fail!")# 強制給 points_array 賦值points_array[0].point.x = 10000 # 設置 X 坐標points_array[0].point.y = 10000 # 設置 Y 坐標points_array[0].delayTime = 0 # 設置延遲時間return points_arrayresult_code = self.sn_sdk.apiSNMouseMove(self.handle, start_point, end_point, type, points_array)if result_code != 0:print(f"Failed to move mouse start_point:{start_point.x},{start_point.y} end_point:{end_point.x},{end_point.y} ,Error core:{result_code}")# 強制給 points_array 賦值points_array[0].point.x = 10000 # 設置 X 坐標points_array[0].point.y = 10000 # 設置 Y 坐標points_array[0].delayTime = 0 # 設置延遲時間return points_arraydef destroy_handle(self):self.sn_sdk.apiSNDestroyHandle.argtypes = [ctypes.c_void_p]self.sn_sdk.apiSNDestroyHandle.restype = ctypes.c_intreturn self.sn_sdk.apiSNDestroyHandle(self.handle)if __name__ == "__main__":#from sn_mouse_track import SN_MOUSE_TRACK_SDK, SN_POINT# 初始化 SDK - 只需要創建一次sdk = SN_MOUSE_TRACK_SDK(key="SNKJUMWwseUjELLDsmvxPH1WYNcZAUDbWdYdEgWjUhxL",onnx_path="d://SNTrack.onnx",dll_path="d://SNSDK.dll")# 獲取版本號version = sdk.get_version()print("SDK Version:", version)# 設置軌跡參數 ,詳細參數解釋參考 SNSDK.hsdk.set_track_params(density=5, other_param=0)# 獲取卡密到期時間expires_time = sdk.get_key_expires_time()print("Key expires time:", expires_time)# 模擬鼠標移動 - 通過設置開始和結束位置,不停獲取軌跡(僅僅只是演示代碼,只獲取一次軌跡)while True:start_point = SN_POINT(100, 100)end_point = SN_POINT(800, 800)points_array = sdk.move_mouse(start_point, end_point, type=0)# 打印軌跡點for i, point in enumerate(points_array):if point.point.x == 10000 and point.point.y == 10000:breakprint(f"Point {i}: ({point.point.x}, {point.point.y}, {point.delayTime})")# 僅僅只是演示代碼,只獲取一次軌跡break# 銷毀句柄sdk.destroy_handle()'''
('64bit', 'WindowsPE')
sn_sdk.apiSNCreateHandle success
SDK Version: 1.0
Key expires time: b'2026-02-04 10:39:38'
Point 0: (100, 100, 0)
Point 1: (110, 102, 1)
Point 2: (135, 105, 2)
Point 3: (175, 111, 8)
Point 4: (224, 135, 8)
Point 5: (276, 153, 5)
Point 6: (307, 165, 2)
Point 7: (352, 188, 9)
Point 8: (377, 201, 8)
Point 9: (404, 221, 5)
Point 10: (422, 236, 5)
Point 11: (441, 252, 2)
Point 12: (460, 270, 9)
Point 13: (482, 293, 8)
Point 14: (506, 317, 7)
Point 15: (531, 342, 1)
Point 16: (553, 374, 2)
Point 17: (582, 417, 9)
Point 18: (604, 448, 8)
Point 19: (622, 476, 5)
Point 20: (638, 498, 1)
Point 21: (648, 514, 3)
Point 22: (658, 528, 8)
Point 23: (667, 543, 7)
Point 24: (678, 563, 5)
Point 25: (687, 578, 1)
Point 26: (697, 598, 2)
Point 27: (710, 622, 9)
Point 28: (719, 638, 8)
Point 29: (728, 657, 5)
Point 30: (735, 671, 1)
Point 31: (743, 686, 2)
Point 32: (752, 705, 9)
Point 33: (761, 721, 8)
Point 34: (769, 737, 5)
Point 35: (776, 751, 2)
Point 36: (784, 767, 9)
Point 37: (792, 783, 2)
Point 38: (796, 793, 9)
Point 39: (799, 800, 24)Process finished with exit code 0'''
5.云盤源碼下載
- 百度云盤
- 夸克云盤
- 123云盤
云盤目錄介紹:
demo - 包含各種編程語言的demo
dll - 分別是x86和x64平臺所需要的dll/lib/h文件
windows 鼠標軌跡測試工具 - exe測試鼠標軌跡效果( demo 中的 c++ 工程編譯后的exe可執行文件)
四.效果演示
1.開始坐標為(100,100),結束坐標為(800,800),通過調用接口獲得 4 條鼠標軌跡
2.開始坐標為(1000,100),結束坐標為(800,800),通過調用接口獲得 2 條鼠標軌跡
?
五.常見問題
1.是否支持多線程
支持
2.如何使用多線程
參考前面的《2.鼠標軌跡API調用流程圖》,多線程和單線程類似;如果是多線程,那么每個線程都需要通過apiSNCreateHandle創建HANDLE句柄,這樣才能多個線程互不影響
3.如何判斷軌跡結束
可以通過循環判斷得到的軌跡坐標,如果當前坐標的X值和Y值都是1000的情況下,默認軌跡結束
(之前的判斷是(-1,-1)作為軌跡結束的標記,現在修改為(10000,10000)作為軌跡結束標記,目的是為了兼容相對坐標)
4.鼠標軌跡設置相對坐標
在函數 apiSNMouseMove 中 type 參數,0 為 絕對坐標 ; 1 為相對坐標
5.如何調節點的密集程度
在(2024.12.22)SDK2.0版本中新增接口 apiSNSetTrackParams 中的 density 參數可以用來調節軌跡密度,舉個例子:
- density = 1 時,默認軌跡有 100 個點,整個軌跡累計耗時 1000 毫秒 (默認 1 倍速度)
- density = 2 時,軌跡有 100/2=50 個點,整個軌跡累計耗時 500?毫秒 (等價 2 倍速度)
- density = 3 時,軌跡有 100/3=33 個點,整個軌跡累計耗時 333 毫秒 (等價 3 倍速度)
- density = 5 時,軌跡有 100/5=20 個點,整個軌跡累計耗時 200 毫秒 (等價 5 倍速度)
不同的游戲需要的軌跡密度不一樣,類似 fps 游戲,鼠標滑動軌跡比較快,density 可以設置為 5 或者更高 ; 類似魔獸世界或者夢幻,density 可以調節為 2 或者 3或者5
6.滑塊驗證軌跡
在函數 apiSNSetTrackParams 中 type 參數,0 為普通鼠標軌跡 ; 1 為滑塊軌跡
普通鼠標貴和滑塊軌跡區別:滑塊軌跡比普通鼠標軌跡坐標點更多(相同的開始/結束坐標),點與點之間更加密集,軌跡的開始和結束暫停/加速更加明顯
六.更新日志
- 2024.02.06 c++ 模擬人工鼠標軌跡demo
- 2024.06.06 python 模擬人工鼠標軌跡demo
- 2024.06.25 新增錯誤日志信息
- 2024.07.15 優化水平/垂直軌跡
- 2024.08.20 優化部分軌跡可能出現負數的問題
- 2024.09.19 優化部分軌跡延遲時間為0的情況(可能會造成鼠標瞬移)
- 2024.09.21 修復部分水平/垂直軌跡出現負數的情況
- 2024.09.28 新增易語言demo
- 2024.11.01 修改接口,兼容易語言代碼
- 2024.11.17 支持移動軌跡為相對坐標(默認是軌跡是絕對坐標)
- 2024.12.15 新增文字識別OCR,支持編程語言如下:
- Python
- 易語言
- C語言
- C++
- 2024.12.22 優化鼠標軌跡
- 新增滑塊軌跡
- 優化鼠標軌跡 - 支持密度調節
- 2024.12.29
- 修復鼠標軌跡可能會崩潰的問題
- 修復OCR文字識別失敗問題(帶有中文路徑的圖片)