Files
2026-07-28 03:21:34 +08:00

179 lines
8.6 KiB
Python

# -*- Config : UTF-8 -*-
# Project Name: Termination Generally Use Cyber Virus Puppet Weapons - TLib/T_KeMouse
# Version: 4.2.0
# Build Version: ./TConfig/version.ini
# Author: Veyra
# Description:
# It is responsible for simulating movement, clicking the mouse and listening,
# And can find the corresponding position on the screen through the template picture,
# Theoretically it can also be found from the picture,
# But it needs to make certain modifications to the program and use the matching DLL.
from .T_imports import *
from .T_CDLL import *
class KeMouse:
def __init__(self, cdll: ctypes.CDLL | DLL) -> None:
self.lib: ctypes.CDLL | DLL = cdll
self.lib.CaptureScreenGray.restype = ctypes.POINTER(GrayImage)
self.lib.CaptureScreenGray.argtypes = [ctypes.POINTER(ctypes.c_int)]
self.lib.LoadImageGray.restype = ctypes.POINTER(GrayImage)
self.lib.LoadImageGray.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)]
self.lib.FindTemplateOptimized.restype = MatchResult
self.lib.FindTemplateOptimized.argtypes = [
ctypes.POINTER(GrayImage),
ctypes.POINTER(GrayImage),
ctypes.c_double,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int
]
self.lib.FreeGrayImage.restype = None
self.lib.FreeGrayImage.argtypes = [ctypes.POINTER(GrayImage)]
self.lib.ClickAt.restype = ctypes.c_int
self.lib.ClickAt.argtypes = [ctypes.c_int, ctypes.c_int]
self.lib.Initialize.restype = ctypes.c_int
self.lib.Initialize.argtypes = []
if self.lib.Initialize() != 0: raise RuntimeError("Failed To Init")
self.user32: ctypes.WinDLL = ctypes.WinDLL('user32', use_last_error=True)
self.user32.SendInput.restype = ctypes.wintypes.UINT
self.user32.SendInput.argtypes = (
ctypes.wintypes.UINT,
ctypes.POINTER(Input),
ctypes.c_int
)
self.user32.SetCursorPos.restype = ctypes.wintypes.BOOL
self.user32.SetCursorPos.argtypes = (
ctypes.wintypes.INT,
ctypes.wintypes.INT
)
self.user32.GetCursorPos.restype = ctypes.wintypes.BOOL
self.user32.GetCursorPos.argtypes = (
ctypes.POINTER(ctypes.wintypes.POINT),
)
def CaptureScreen(self) -> typing.Optional[GrayImage]:
ErrorCode: ctypes.c_int = ctypes.c_int(0)
Screen: GrayImage | typing.Any = self.lib.CaptureScreenGray(ctypes.byref(ErrorCode))
if ErrorCode.value != 0 or not Screen: raise RuntimeError(f"Failed To Capture Screen, Error Code: {ErrorCode.value}")
return Screen
def LoadImage(self, FileName: str) -> typing.Optional[GrayImage]:
ErrorCode: ctypes.c_int = ctypes.c_int(0)
try:
Encoded = FileName.encode('utf-8')
Target: GrayImage = self.lib.LoadImageGray(Encoded, ctypes.byref(ErrorCode))
if ErrorCode.value != 0: raise RuntimeError(f"Failed To Load Image, Error Code: {ErrorCode.value}")
if not Target: raise RuntimeError("Returned NULL Pointer")
return Target
except Exception as e: raise RuntimeError(f"Failed To Load Image, Error: {str(e)}")
def FindTemplate(self, Target: str, Threshold: float = 0.9, SearchArea: typing.Optional[typing.Tuple[int, int, int, int]] = None) -> typing.Tuple[typing.Optional[typing.Tuple[int, int]], float]:
try:
Target: str = os.path.abspath(Target)
if not os.path.isfile(Target):
raise FileNotFoundError(Target)
TargetImg: GrayImage = self.LoadImage(Target)
Screen: GrayImage = self.CaptureScreen()
X1: int
Y2: int
X2: int
Y2: int
X1, Y1, X2, Y2 = -1, -1, -1, -1
if SearchArea is not None: X1, Y1, X2, Y2 = SearchArea
Result: MatchResult = self.lib.FindTemplateOptimized(Screen, TargetImg, Threshold, X1, Y1, X2, Y2)
self.lib.FreeGrayImage(TargetImg)
self.lib.FreeGrayImage(Screen)
if Result.error != 0:
if Result.error == 202: return None, Result.confidence
raise RuntimeError(f"ErrorCode: {Result.error}")
return (Result.x, Result.y), Result.confidence
except Exception as e: raise RuntimeError(f"Failed To Find Template, Error: {str(e)}")
def MoveTo(self, X: int, Y: int) -> None:
if not self.user32.SetCursorPos(X, Y): raise ctypes.WinError(ctypes.get_last_error())
def GetPosition(self) -> tuple[int, int]:
Point: ctypes.wintypes.POINT = ctypes.wintypes.POINT()
if not self.user32.GetCursorPos(ctypes.byref(Point)): raise ctypes.WinError(ctypes.get_last_error())
return (Point.x, Point.y)
def Click(self, X: int = None, Y: int = None, Button: str = 'left', Double: bool = False, Delay: float = 0.1) -> bool:
try:
if X is not None and Y is not None:
if not self.user32.SetCursorPos(X, Y): raise ctypes.WinError(ctypes.get_last_error())
Point: ctypes.wintypes.POINT = ctypes.wintypes.POINT()
if not self.user32.GetCursorPos(ctypes.byref(Point)): raise ctypes.WinError(ctypes.get_last_error())
X, Y = Point.x, Point.y
Button = Button.lower()
DownFlag, UpFlag = {
'left': (0x0002, 0x0004), # MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP
'right': (0x0008, 0x0010), # MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP
'middle': (0x0020, 0x0040) # MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP
}.get(Button, (None, None))
if DownFlag is None:
return False
def CreateInput(DwFlags: int) -> Input:
Inp: Input = Input()
Inp.type = 0
Inp.union.mi.dwFlags = DwFlags
Inp.union.mi.dx = X
Inp.union.mi.dy = Y
return Inp
Inputs: list[Input] = []
Inputs.append(CreateInput(DownFlag))
Inputs.append(CreateInput(UpFlag))
if Double:
time.sleep(Delay)
Inputs.append(CreateInput(DownFlag))
Inputs.append(CreateInput(UpFlag))
InputArray = (Input * len(Inputs))(*Inputs)
Sent = self.user32.SendInput(
len(Inputs),
InputArray,
ctypes.sizeof(Input)
)
return Sent == len(Inputs)
except Exception:
return False
def ClickTargetPNG(self, Target: str, Button: str='left', Threshold: float = 0.9, Sleep: float = 0, SearchArea: typing.Optional[typing.Tuple[int, int, int, int]] = None) -> bool:
Pos, Confidence = self.FindTemplate(Target, Threshold, SearchArea)
if not Pos:
return False
_ = self.Click(Pos[0], Pos[1], button=Button)
time.sleep(Sleep)
return _
def ClickTargetPNGAC(self, Target: str, Button: str='left', Threshold: float = 0.9, Sleep: float = 0, SearchArea: typing.Optional[typing.Tuple[int, int, int, int]] = None, Confidence: float = 0.9) -> bool:
Pos, Confidence = self.FindTemplate(Target, Threshold, SearchArea)
if not Pos or Confidence < self.Confidence:
return False
_ = self.Click(Pos[0], Pos[1], button=Button)
time.sleep(Sleep)
return _
def ScreenshotBytes(self) -> bytes:
HDesktop = win32gui.GetDesktopWindow()
Width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
HDC = win32gui.GetWindowDC(HDesktop)
MfcDc = win32ui.CreateDCFromHandle(HDC)
SaveDc = MfcDc.CreateCompatibleDC()
Bitmap = win32ui.CreateBitmap()
Bitmap.CreateCompatibleBitmap(MfcDc, Width, height)
SaveDc.SelectObject(Bitmap)
SaveDc.BitBlt((0, 0), (Width, height), MfcDc, (0, 0), win32con.SRCCOPY)
bmpinfo = Bitmap.GetInfo()
bmpstr = Bitmap.GetBitmapBits(True)
PILIMG = Image.frombuffer(
'RGB',
(bmpinfo['bmWidth'], bmpinfo['bmHeight']),
bmpstr,
'raw',
'BGRX',
0, 1
)
ImgBytes = io.BytesIO()
PILIMG.save(ImgBytes, format='PNG')
p = ImgBytes.getvalue()
win32gui.DeleteObject(Bitmap.GetHandle())
SaveDc.DeleteDC()
MfcDc.DeleteDC()
win32gui.ReleaseDC(HDesktop, HDC)
return p