[python] 羅技動態(tài)鏈接驅動庫DLL 控制 鍵鼠
- 最近在玩搬磚游戲晶核, 每天有很多重復繁瑣的"打卡"操作, 得知隔壁御三家游戲就有大佬做了自動收割的輔助工具,我就想模仿寫一個.
- 不過大佬們寫的開源工具厲害得多,加了神經網絡自動識別,實現(xiàn)尋路和點擊功能.我目前最多就是實現(xiàn)一個簡單連點器加色塊識別而已,而且這種原始手動的方法很不方便,我原本還想著寫個表格導入操作功能.最后也不了了之了.太懶了.
- << Python調用羅技驅動實現(xiàn)功能 >> https://www.python100.com/html/1S27NYQO8H34.html
- << FPS游戲自動槍械識別+壓槍(以PUBG為例) >> https://blog.csdn.net/weixin_37827742/article/details/124242964
- << AimLab OPENCV開源(包含Sendinput + Fov等代碼) >> https://www.bilibili.com/video/BV1q34y1e7ic/
一、準備工作
- 需要安裝
python 3.8.10 64位
帶IDLE
的版本. 因為我會使用pyautogui
來獲取屏幕分辨率等操作,使用tkinter
來創(chuàng)建簡易彈窗提示操作; - 如果你只需要控制鼠標的話就不需要上述2個軟件包,不然最好和我一樣的python版本,32位或是版本太新太久都不支持
pyautogui
,或者使用其他軟件包代替也可以.tkinter
軟件包是安裝IDLE
時自帶的,不能手動安裝,只能通過安裝IDLE
來安裝,很奇怪.我嘗試了很久得出這樣一個個結論. - 本教程使用的是動態(tài)鏈接驅動庫是羅技的
LGS_9.02.65_x64_Logitech.exe
版本, 注意不能是其他版本,不然對不上,先安裝這個驅動程序,那動態(tài)鏈接庫才有效果.安裝完成后的軟件界面是這樣的:
- 最后在程序中加載
dll
文件, 就可以驅動鍵鼠了.該軟件只需要開機打開一次即可.打開后退出也會繼續(xù)生效.但是關機重啟后又失效,所以開機后要打開一次,之后關閉退出就行. - 另外關于
dll
文件,第一次接觸的人可能不懂是什么,沒關系,因為我也不懂是啥.不過不影響使用,dll
有點像別人打包好的庫,具有一些函數,你導入到自己的.py后,就可以直接使用這些函數.使用一些工具depends22_x64
可以查看dll
打包了什么函數,這里我只會通過名字和實踐猜測每個函數的功能.
- 注意!!! 不同地方下載的
dll
文件可能是不同人打包的,可能函數名或函數功能不太一樣.
二、開始敲代碼
1. 框架
- 先寫個基本框架, 里面包含了開頭注釋, 軟件包導入, 打印函數打包, pid函數打包, 主函數打包; 一個等待填寫的空類;
"""
時間 : 2023年12月30日 07:34:48
作者 : Lovely_him
說明 : 興趣使然
"""
#!/usr/bin/env python3
import sys
import win32api
import os # 獲取文件路徑
import time # 獲取時間和延時
import ctypes # 調用dll文件
import tkinter as tk # python 內置庫,需要安裝時勾選安裝IDE才會安裝,坑爹
import threading # 多線程
import pyautogui # 獲取屏幕鼠標坐標
import random # 隨機數
def print_tkui(strs):
""" 打包控制臺輸出 """
print(strs)
class PID:
"""PID"""
def __init__(self, P=0.35, I=0, D=0):
"""PID"""
self.kp = P # 比例
self.ki = I # 積分
self.kd = D # 微分
self.uPrevious = 0 # 上一次控制量
self.uCurent = 0 # 這一次控制量
self.setValue = 0 # 目標值
self.lastErr = 0 # 上一次差值
self.errSum = 0 # 所有差值的累加
self.errSumLimit = 10 # 近兩次的差值累加
def pidPosition(self, setValue, curValue):
"""位置式 PID 輸出控制量"""
self.setValue = setValue # 更新目標值
err = self.setValue - curValue # 計算差值, 作為比例項
dErr = err - self.lastErr # 計算近兩次的差值, 作為微分項
self.errSum += err # 累加這一次差值,作為積分項
outPID = (self.kp * err) + (self.ki * self.errSum) + (self.kd * dErr) # PID
self.lastErr = err # 保存這一次差值,作為下一次的上一次差值
return outPID # 輸出
def pidIncrease(self, setValue, curValue):
"""增量式 PID 輸出控制量的差值"""
self.uCurent = self.pidPosition(setValue, curValue) # 計算位置式
outPID = self.uCurent - self.uPrevious # 計算差值
self.uPrevious = self.uCurent # 保存這一次輸出量
return outPID # 輸出
class LOGITECH:
"""羅技動態(tài)鏈接庫"""
pass
def Mymain():
""" 主函數 """
pass
if __name__ == "__main__":
""" 主運行 """
Mymain()
2. 導入
- 然后開始往空類里填寫內容, 第一步導入
dll
文件,直接寫在類的開頭,只要這個類被導入,那就導入文件作準備.注意,我還添加了幾個局部的常量,用于判斷后續(xù)的保護措施. - 記得注意路徑是否正確,還有提前打開羅技驅動軟件.成功執(zhí)行運行就會有以下提示
class LOGITECH:
"""羅技動態(tài)鏈接庫"""
try:
file_path = os.path.abspath(os.path.dirname(__file__)) # 當前路徑
dll = ctypes.CDLL(f'{file_path}/logitech_driver.dll') # 打開路徑文件
state = (dll.device_open() == 1) # 啟動, 并返回是否成功
WAIT_TIME = 0.5 # 等待時間
RANDOM_NUM = 0.1 # 最大時間隨機數
if not state:
print('錯誤, 未找到GHUB或LGS驅動程序')
except FileNotFoundError:
print(f'錯誤, 找不到DLL文件')
def __init__(self) -> None:
pass
3. 鼠標點擊
- 然后開始逐一打包調用
dll
庫內的函數,實現(xiàn)功能; 先是鼠標按下和松開,合并為點擊的功能;為了模擬真實點擊,我加了按下后隨機延時再松開.
@classmethod
def mouse_down(self, code):
""" 鼠標按下 code: 左 中 右 """
if not self.state:
return
print_tkui(f'按下{code}鍵')
if code == '左':
code = 1
elif code == '中':
code = 2
elif code == '右':
code = 3
else: # 默認
code = 1
self.dll.mouse_down(code)
@classmethod
def mouse_up(self, code):
""" 鼠標松開 code: 左 中 右 """
if not self.state:
return
print_tkui(f'松開{code}鍵')
if code == '左':
code = 1
elif code == '中':
code = 2
elif code == '右':
code = 3
else: # 默認
code = 1
self.dll.mouse_up(code)
@classmethod
def mouse_click(self, code, wait_time=0):
""" 鼠標點擊 code: 左 中 右 """
if wait_time == 0: # 如果沒有規(guī)定等待時間
wait_time = self.WAIT_TIME # 默認等待時間
if wait_time != 0: # 如果等待時間不是0
wait_time += random.uniform(0, self.RANDOM_NUM)
time.sleep(wait_time) # 延時時間,秒,生成隨機小數0~1.0
if not self.state:
return
print_tkui(f'等待{wait_time:.2f}秒后, 點擊{code}鍵')
if code == '左':
code = 1
elif code == '中':
code = 2
elif code == '右':
code = 3
else: # 默認
code = 1
self.dll.mouse_down(code)
time.sleep(random.uniform(0, self.RANDOM_NUM)) # 延時時間,秒,生成隨機小數0~1.0
self.dll.mouse_up(code)
4. 鍵盤點擊
- 和鼠標點擊相似, 鍵盤點擊也一樣, 有按下和松開組合.
@classmethod
def key_down(self, code):
"""鍵盤下去 code: 'a'-'z':A-Z, '0'-'9':0-9"""
if not self.state:
return
print_tkui(f'按下{code}鍵')
self.dll.key_down(code)
@classmethod
def key_up(self, code):
"""鍵盤起來 code: 'a'-'z':A-Z, '0'-'9':0-9"""
if not self.state:
return
print_tkui(f'松開{code}鍵')
self.dll.key_up(code)
@classmethod
def key_click(self, code, wait_time=0, time_down=0):
"""鍵盤點擊 code: 'a'-'z':A-Z, '0'-'9':0-9"""
if wait_time == 0: # 如果沒有規(guī)定等待時間
wait_time = self.WAIT_TIME # 默認等待時間
if wait_time != 0: # 如果等待時間不是0
wait_time += random.uniform(0, self.RANDOM_NUM)
time.sleep(wait_time) # 延時時間,秒,生成隨機小數0~1.0
if time_down != 0: # 如果有長按時間,就會變成長按
wait_time = 0
if not self.state: # 保護措施
return
print_tkui(f'等待{wait_time:.2f}秒后, 點擊{code}鍵, 長按時間{time_down:.2f}')
self.dll.key_down(code)
time.sleep(wait_time + time_down +random.uniform(0, self.RANDOM_NUM)) # 延時時間,秒,生成隨機小數0~1.0, 不可以延時,
self.dll.key_up(code)
5. 鼠標移動
- 然后是比較抽象的鼠標移動, 它的函數輸入是移動量, 就是模擬實際鼠標的移動距離, 而不是屏幕鼠標的移動距離. 屏幕鼠標的移動距離受電腦設置的鼠標速度, 和實際鼠標的cpi有很大關系. 實際我們使用的時候, 肯定只希望以屏幕作為參考系,在屏幕上以坐標移動.所以我打包了一下,使用pid自動調節(jié)的方式,實現(xiàn)輸入屏幕坐標,鼠標移動到相應坐標位置;
@classmethod
def mouse_move(self, end_xy, wait_time=0, min_xy=2, min_time=0.1):
"""
等待多久后 緩慢移動 \n
end_x 絕對橫坐標 \n
end_y 絕對縱坐標 \n
time_s 等待時間 \n
min_xy 最小移動控制量 \n
min_time 最小移動時間 \n
"""
if wait_time == 0: # 如果沒有規(guī)定等待時間
wait_time = self.WAIT_TIME # 默認等待時間
if wait_time != 0: # 如果等待時間不是0
wait_time += random.uniform(0, self.RANDOM_NUM)
time.sleep(wait_time) # 延時時間,秒,生成隨機小數0~1.0
if not self.state: # 保護措施
return
end_x, end_y = end_xy
print_tkui(f'等待{wait_time:.2f}秒后, 移動到坐標{(end_x, end_y)}')
pid_x = PID() # 創(chuàng)建pid對象
pid_y = PID()
while True: # 循環(huán)控制鼠標直到重合坐標
time.sleep(min_time) # 延時時間,秒,生成隨機小數0~1.0
new_x, new_y = pyautogui.position() # 獲取當前鼠標位置
move_x = pid_x.pidPosition(end_x, new_x) # 經過pid計算鼠標運動量
move_y = pid_y.pidPosition(end_y, new_y)
# print(f'x={new_x}, y={new_y}, xd={move_x}, yd={move_y}')
if end_x == new_x and end_y == new_y: # 如果重合就退出循環(huán)
break
if move_x > 0 and move_x < (min_xy): # 限制正最小值
move_x = (min_xy)
elif move_x < 0 and move_x > -(min_xy): # 限制負最小值
move_x = -(min_xy)
else:
move_x = int(move_x) # 需要輸入整數,小數會報錯
if move_y > 0 and move_y < (min_xy):
move_y = (min_xy)
elif move_y < 0 and move_y > -(min_xy):
move_y = -(min_xy)
else:
move_y = int(move_y)
self.dll.moveR(move_x, move_y, True) # 貌似有第三個參數,但是沒試出來什么用
6. 鼠標滾輪
- 同理, 最后還有一個鼠標滾輪的滾動, 它也是模擬滾動量, 這個就不太好跟蹤, 因為不同頁面滾動范圍不一樣, 而且這個功能用得很少. 我考慮的是在有滾動條的情況下,使用鼠標點擊滾動條或拖拽滾動條, 是更加穩(wěn)妥的操作,所以我只寫了個簡單的調用;
@classmethod
def mouse_scroll(self, num):
""" 鼠標滾輪 num : 正數向下, 負數向上 """
if not self.state:
return
if num > 0:
str_scroll = '下'
elif num < 0:
str_scroll = '上'
else: # 保護措施
return
print_tkui(f'滾輪{str_scroll}轉動{num}單位')
self.dll.scroll(num) # 鼠標滾輪
7. 總結
-
自此,
dll
驅動庫內的0~9序號,10個函數中, 后8個函數的功能都實現(xiàn)了.第0個delay
,應該是延時,使用python自帶的更加方便,所以沒有用. 第1個device_close
應該是和第2個device_open
相對應的,屬于關閉模塊,但我嘗試了一下沒成功,考慮到別人寫的例程,也是一開始就導入了dll
并調用了dll.device_open
,后續(xù)并沒有考慮關閉,也不需要關閉,所以我也寫在類開頭,導入類就導入dll
并打開,不考慮關閉. -
大致功能就上面這些了, 然后使用最原始的方式實現(xiàn)連點器功能.我原本還打算寫個連點器操作表格導入功能, 將操作羅列,然后執(zhí)行持續(xù)識別表格,開始設置的操作.我嘗試一下后就放棄了,這種方法太原始了,現(xiàn)在應該采用更加智能的ai識別才對.而不是輸入固定坐標點移動.文章來源:http://www.zghlxwxcb.cn/news/detail-827477.html
-
筆記到這里, 結束.文章來源地址http://www.zghlxwxcb.cn/news/detail-827477.html
到了這里,關于[python] 羅技動態(tài)鏈接驅動庫DLL 控制 鍵鼠的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!