import time
import ctypes
from ctypes import wintypes
import struct

user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32

# SendInput structures
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", wintypes.WORD),
                ("wScan", wintypes.WORD),
                ("dwFlags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", wintypes.DWORD),
                ("wParamL", wintypes.WORD),
                ("wParamH", wintypes.WORD)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", wintypes.LONG),
                ("dy", wintypes.LONG),
                ("mouseData", wintypes.DWORD),
                ("dwFlags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                ("mi", MouseInput),
                ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", wintypes.DWORD),
                ("ii", Input_I)]

INPUT_KEYBOARD = 1
KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP = 0x0002
KEYEVENTF_UNICODE = 0x0004
KEYEVENTF_SCANCODE = 0x0008

def send_scancode_down(scan):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput(0, scan, KEYEVENTF_SCANCODE, 0, ctypes.pointer(extra))
    x = Input(ctypes.c_ulong(INPUT_KEYBOARD), ii_)
    user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def send_scancode_up(scan):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput(0, scan, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0, ctypes.pointer(extra))
    x = Input(ctypes.c_ulong(INPUT_KEYBOARD), ii_)
    user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def read_xyz():
    pid = 43084
    h = kernel32.OpenProcess(0x0010, False, pid)
    if not h: return None
    buf = ctypes.create_string_buffer(12)
    br = ctypes.c_size_t()
    kernel32.ReadProcessMemory(h, ctypes.c_void_p(0x2AF791A0550), buf, 12, ctypes.byref(br))
    kernel32.CloseHandle(h)
    return struct.unpack("<fff", buf.raw)

def main():
    hwnd = user32.FindWindowW("POEWindowClass", None)
    if not hwnd: hwnd = user32.FindWindowW(None, "Path of Exile 2")
    user32.SetForegroundWindow(hwnd)
    time.sleep(0.1)

    xyz0 = read_xyz()
    print(f"XYZ Before: {xyz0}")

    # PS/2 Scan codes:
    # W = 0x11, A = 0x1E, S = 0x1F, D = 0x20
    print("Holding 'W' (scancode 0x11) for 1000ms via SendInput(KEYEVENTF_SCANCODE)...")
    send_scancode_down(0x11)
    time.sleep(1.0)
    send_scancode_up(0x11)
    print("Released 'W'")

    time.sleep(0.2)
    xyz1 = read_xyz()
    print(f"XYZ After: {xyz1}")

    dx = xyz1[0] - xyz0[0]
    dy = xyz1[1] - xyz0[1]
    print(f"Delta: dX={dx:.2f}, dY={dy:.2f}")

if __name__ == '__main__':
    main()
