小隐的博客

人生在世,笑饮一生
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

随手写了街机一键发招的代码

Posted on 2025-04-17 08:50  隐客  阅读(22)  评论(0)    收藏  举报
import sys
import os
import threading
import time
import ctypes
import re
from pynput import keyboard as kb
 


  

 

controller = kb.Controller()
pressed_keys = set()
active_key = None

combo_lock = threading.Lock()
is_game_active = False
combo_enabled = True
 

DIGIT_VK_MAP = {
    48: '0',
    49: '1',
    50: '2',
    51: '3',
    52: '4',
    53: '5',
}

GAME_WINDOW_TITLE = "西游释厄传SUPER"  # 修改成你游戏窗口名字的一部分

 
# --------------------------
# 窗口前置变化监控(不使用sleep)

def win_event_proc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
    global is_game_active
    title = ctypes.create_unicode_buffer(512)
    ctypes.windll.user32.GetWindowTextW(hwnd, title, 512)
    is_game_active = (GAME_WINDOW_TITLE in title.value)

def start_window_watcher():
    WINEVENT_OUTOFCONTEXT = 0x0000
    EVENT_SYSTEM_FOREGROUND = 0x0003

    user32 = ctypes.windll.user32
    ole32 = ctypes.windll.ole32
    ole32.CoInitialize(0)

    WinEventProcType = ctypes.WINFUNCTYPE(
        None, ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD,
        ctypes.wintypes.HWND, ctypes.wintypes.LONG,
        ctypes.wintypes.LONG, ctypes.wintypes.DWORD,
        ctypes.wintypes.DWORD)

    event_proc = WinEventProcType(win_event_proc)

    hook = user32.SetWinEventHook(
        EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 0,
        event_proc, 0, 0, WINEVENT_OUTOFCONTEXT)

    if hook == 0:
        print("SetWinEventHook failed")
        return

    import pythoncom
    pythoncom.PumpMessages()

threading.Thread(target=start_window_watcher, daemon=True).start()

# --------------------------

def find_super_files():
    return [f for f in os.listdir('.') if f.lower().startswith('super')]

def load_combos_from_file(filepath):
    try:
        with open(filepath, 'r', encoding='mbcs', errors='ignore') as f:
            content = f.read()
    except:
        print(f"无法读取文件: {filepath}")
        return {}

    combos = {}
    blocks = re.findall(r"\[(.*?)\]", content, re.DOTALL)

    for block in blocks:
        lines = block.strip().splitlines()
        if '||||' in lines:
            try:
                key_line_index = lines.index('||||') + 1
                key_line = lines[key_line_index]
                key_match = re.search(r"\((\d+)\)", key_line)
                if not key_match:
                    continue
                key_char = chr(int(key_match.group(1))).lower()

                second_pipe_index = lines.index('||||', key_line_index)
                action_lines = lines[second_pipe_index + 1:]

                sequence = []
                for line in action_lines:
                    match = re.match(r"([\d.]+)\|([v\^])\|([A-Z])", line.strip())
                    if match:
                        delay = float(match.group(1))
                        action = match.group(2)
                        key = match.group(3).lower()
                        sequence.append((delay, action, key))

                combos[key_char] = sequence
            except Exception as e:
                print(f"解析失败: {e}")
    return combos

def perform_combo(sequence, key):
    global active_key
    with combo_lock:
        if active_key and active_key != key:
            return
        active_key = key
        for delay, action, k in sequence:
            time.sleep(delay)
            if action == 'v':
                controller.press(k)
            elif action == '^':
                controller.release(k)
        active_key = None

def start_listener(initial_combos, script_files):
    current_combos = initial_combos
    combo_enabled = True

    def on_press(key):
        nonlocal current_combos, combo_enabled

        if key == kb.Key.f12:
            
            msg="按下 F12,程序退出"
            print(msg)
 
            time.sleep(3.5)
            return False

        if key in (kb.Key.ctrl_l, kb.Key.ctrl_r):
            pressed_keys.add('ctrl')

        elif isinstance(key, kb.KeyCode) and key.vk in DIGIT_VK_MAP:
            digit = DIGIT_VK_MAP[key.vk]
            pressed_keys.add(digit)

            if 'ctrl' in pressed_keys:
                if digit == '0':
                    combo_enabled = not combo_enabled
                    state = "启用" if combo_enabled else "停用"
                    msg=f"\n>>> 连招功能已{state} <<<"
                    print(msg)
 
                    return

                combo_enabled = True
                idx = int(digit) - 1
                if idx < len(script_files):
                    new_file = script_files[idx]
                    print(f"\n切换脚本: {new_file}")
                    current_combos = load_combos_from_file(new_file)
                    msg=f"热键重新加载完毕(来自 {new_file})"
                    print(msg)
 

                    for k in current_combos:
                        print(f"[{k.upper()}] 就绪")

                return

        elif isinstance(key, kb.KeyCode) and key.char:
            if not is_game_active or not combo_enabled:
                return
            k = key.char.lower()
            if k in current_combos and active_key is None:
                threading.Thread(target=perform_combo, args=(current_combos[k], k), daemon=True).start()

    def on_release(key):
        if key in (kb.Key.ctrl_l, kb.Key.ctrl_r):
            pressed_keys.discard('ctrl')
        elif isinstance(key, kb.KeyCode) and key.vk in DIGIT_VK_MAP:
            pressed_keys.discard(DIGIT_VK_MAP[key.vk])

    with kb.Listener(on_press=on_press, on_release=on_release) as listener:
        # notification.notify( message="连招系统已启动,按 F12 退出,Ctrl+数字键(1~5)切换脚本",timeout=1 )
 
        print("连招系统已启动,按 F12 退出,Ctrl+数字键(1~5)切换脚本")
        listener.join()

def main():
    script_files = find_super_files()
    if not script_files:
        print("未找到任何 super 开头的脚本文件")
        sys.exit(1)

    print("可用脚本列表:")
    for idx, name in enumerate(script_files):
        print(f"{idx+1}. {name}")
    msg=f"\n默认加载第一个脚本: {script_files[0]}"
    print(msg)
 


    combos = load_combos_from_file(script_files[0])
    if not combos:
        print("没有加载任何连招配置")
    else:
        for k in combos:
            print(f"热键 [{k.upper()}] 已就绪")

 
    start_listener(combos, script_files)

if __name__ == "__main__":
 
    main()

 

 

 

配置文件的内容示例:

[
Q左上跑
||||
Q(81)
||||
0.000|v|W|87|17|0->
0.001|v|A|65|30|0->
0.020|^|W|87|17|0->
0.000|^|A|65|30|0->
0.051|v|W|87|17|0->
0.000|v|A|65|30|0->
0.020|^|W|87|17|0->
0.000|^|A|65|30|0->
0.051|v|W|87|17|0->
0.000|v|A|65|30|0->
0.020|^|W|87|17|0->
0.000|^|A|65|30|0->
0.051|v|W|87|17|0->
0.000|v|A|65|30|0->
0.020|^|W|87|17|0->
0.000|^|A|65|30|0->


]

 

QQ交流