ipad模拟xz玩osu 2 延迟1ms 网页外设

https://wwamf.lanzouu.com/iqtds3fmgewd 密码:cxnh

https://www.bilibili.com/video/BV1xyidB4EBk

玩起来比原理那版相应快多了

python 复制代码
import sys
import os
import time
from datetime import datetime
import ctypes
from ctypes import wintypes
import threading

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from flask import Flask, render_template_string
from flask_socketio import SocketIO, emit
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
app.config['SECRET_KEY'] = 'your-secret-key-for-socketio'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')

# 用于跟踪按键状态
key_states = {
    'x': False,
    'z': False
}

# Windows API 键盘事件常量
INPUT_KEYBOARD = 1
KEYEVENTF_SCANCODE = 0x0008
KEYEVENTF_KEYUP = 0x0002

# 虚拟键码和扫描码映射
KEY_CODES = {
    'x': {'vk': 0x58, 'scan': 0x2D},  # X键的虚拟键码和扫描码
    'z': {'vk': 0x5A, 'scan': 0x2C}   # Z键的虚拟键码和扫描码
}

def send_win_key_event(key, is_keyup=False):
    """使用Windows API发送按键事件,兼容游戏"""
    try:
        # 加载user32.dll
        user32 = ctypes.WinDLL('user32', use_last_error=True)
        
        # 定义INPUT结构
        class KEYBDINPUT(ctypes.Structure):
            _fields_ = (("wVk", wintypes.WORD),
                        ("wScan", wintypes.WORD),
                        ("dwFlags", wintypes.DWORD),
                        ("time", wintypes.DWORD),
                        ("dwExtraInfo", ctypes.POINTER(wintypes.ULONG)))
        
        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", ctypes.POINTER(wintypes.ULONG)))
        
        class INPUT_union(ctypes.Union):
            _fields_ = (("ki", KEYBDINPUT),
                        ("mi", MOUSEINPUT),
                        ("hi", HARDWAREINPUT))
        
        class INPUT(ctypes.Structure):
            _fields_ = (("type", wintypes.DWORD),
                        ("union", INPUT_union))
        
        # 获取键码信息
        key_info = KEY_CODES.get(key.lower())
        if not key_info:
            return {"status": "error", "message": f"不支持的键: {key}"}
        
        # 设置标志
        flags = KEYEVENTF_KEYUP
        if not is_keyup:
            flags = 0  # 按下键时不设置KEYEVENTF_KEYUP标志
        
        # 添加扫描码标志
        flags |= KEYEVENTF_SCANCODE
        
        # 创建输入事件
        inputs = INPUT(
            type=INPUT_KEYBOARD,
            union=INPUT_union(
                ki=KEYBDINPUT(
                    wVk=key_info['vk'],
                    wScan=key_info['scan'],
                    dwFlags=flags,
                    time=0,
                    dwExtraInfo=None
                )
            )
        )
        
        # 发送输入事件
        result = user32.SendInput(1, ctypes.byref(inputs), ctypes.sizeof(INPUT))
        
        action = "释放" if is_keyup else "按下"
        return {"status": "success", "message": f"成功{action}{key.upper()}键 (使用扫描码)"}
        
    except Exception as e:
        return {"status": "error", "message": str(e)}

def fast_key_down(key):
    """快速按下键"""
    return send_win_key_event(key, is_keyup=False)

def fast_key_up(key):
    """快速释放键"""
    return send_win_key_event(key, is_keyup=True)

# HTML模板
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XZ键控制面板</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            height: 100vh;
            display: flex;
            font-family: Arial, sans-serif;
            overflow: hidden;
            background-color: #f0f0f0;
        }
        
        .half {
            width: 50%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            transition: background-color 0.1s;
            user-select: none;
        }
        
        .x-half {
            background-color: #ffcccc;
            border-right: 2px solid #ccc;
        }
        
        .z-half {
            background-color: #ccccff;
        }
        
        .half.active {
            opacity: 0.7;
        }
        
        .key-label {
            font-size: 8em;
            font-weight: bold;
            color: #333;
        }
        
        .instructions {
            margin-top: 20px;
            font-size: 1.2em;
            color: #666;
            text-align: center;
        }
        
        .status {
            margin-top: 20px;
            font-size: 1.2em;
            color: #333;
            text-align: center;
        }
        
        .response-time {
            margin-top: 10px;
            font-size: 0.9em;
            color: #888;
            text-align: center;
        }
        
        .pressed {
            background-color: #ff9999 !important;
        }
        
        .z-pressed {
            background-color: #9999ff !important;
        }
    </style>
</head>
<body>
    <div class="half x-half" id="xHalf">
        <div class="key-label">X</div>
        <div class="instructions">点击按住或松开X键</div>
        <div class="status" id="xStatus">状态: 未按下</div>
        <div class="response-time" id="xResponseTime">响应时间: -- ms</div>
    </div>
    
    <div class="half z-half" id="zHalf">
        <div class="key-label">Z</div>
        <div class="instructions">点击按住或松开Z键</div>
        <div class="status" id="zStatus">状态: 未按下</div>
        <div class="response-time" id="zResponseTime">响应时间: -- ms</div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <script>
        // 按键状态
        let keyStates = {
            x: false,
            z: false
        };
        
        // 记录请求时间的对象
        let requestTimes = {};
        
        // 获取DOM元素
        const xHalf = document.getElementById('xHalf');
        const zHalf = document.getElementById('zHalf');
        const xStatus = document.getElementById('xStatus');
        const zStatus = document.getElementById('zStatus');
        const xResponseTime = document.getElementById('xResponseTime');
        const zResponseTime = document.getElementById('zResponseTime');
        
        // 连接到Socket.IO服务器
        const socket = io();
        
        // 更新按键状态显示(仅本地UI更新,立即响应)
        function updateStatus() {
            xStatus.textContent = `状态: ${keyStates.x ? '按下' : '未按下'}`;
            
            // 立即更新视觉效果,无需等待服务器响应
            if (keyStates.x) {
                xHalf.classList.add('pressed');
            } else {
                xHalf.classList.remove('pressed');
            }
        }
        
        function updateZStatus() {
            zStatus.textContent = `状态: ${keyStates.z ? '按下' : '未按下'}`;
            
            // 立即更新视觉效果,无需等待服务器响应
            if (keyStates.z) {
                zHalf.classList.add('z-pressed');
            } else {
                zHalf.classList.remove('z-pressed');
            }
        }
        
        // Socket.IO事件监听器
        socket.on('connect', function() {
            console.log('已连接到服务器');
        });
        
        socket.on('key_state_update', function(states) {
            console.log('收到按键状态更新:', states);
            // 从服务器同步状态(主要用于保持一致性)
            keyStates.x = states.x;
            keyStates.z = states.z;
            updateStatus();
            updateZStatus();
        });
        
        // 记录请求时间并发送按键操作到服务器
        function sendKeyAction(action, key) {
            const requestId = Date.now() + '_' + Math.random();
            requestTimes[requestId] = Date.now();
            
            // 发送数据到服务器,包含请求ID
            socket.emit('key_control', {
                action: action,
                key: key,
                requestId: requestId
            });
        }
        
        // 接收服务器响应并计算响应时间
        socket.on('key_response', function(data) {
            if (data.requestId && requestTimes[data.requestId]) {
                const responseTime = Date.now() - requestTimes[data.requestId];
                
                // 更新对应的响应时间显示
                if (data.key === 'x') {
                    xResponseTime.textContent = `响应时间: ${responseTime} ms`;
                } else if (data.key === 'z') {
                    zResponseTime.textContent = `响应时间: ${responseTime} ms`;
                }
                
                // 清理请求时间记录
                delete requestTimes[data.requestId];
                
                console.log(`${data.key.toUpperCase()}键操作响应时间: ${responseTime}ms`);
            }
        });
        
        // 为X区域添加事件监听器
        xHalf.addEventListener('mousedown', function(e) {
            e.preventDefault();
            if (!keyStates.x) {
                // 立即更新UI状态
                keyStates.x = true;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('down', 'x');
            }
        });
        
        xHalf.addEventListener('mouseup', function() {
            if (keyStates.x) {
                // 立即更新UI状态
                keyStates.x = false;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'x');
            }
        });
        
        xHalf.addEventListener('mouseleave', function() {
            // 鼠标离开区域,也应释放按键
            if (keyStates.x) {
                // 立即更新UI状态
                keyStates.x = false;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'x');
            }
        });
        
        // 为Z区域添加事件监听器
        zHalf.addEventListener('mousedown', function(e) {
            e.preventDefault();
            if (!keyStates.z) {
                // 立即更新UI状态
                keyStates.z = true;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('down', 'z');
            }
        });
        
        zHalf.addEventListener('mouseup', function() {
            if (keyStates.z) {
                // 立即更新UI状态
                keyStates.z = false;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'z');
            }
        });
        
        zHalf.addEventListener('mouseleave', function() {
            // 鼠标离开区域,也应释放按键
            if (keyStates.z) {
                // 立即更新UI状态
                keyStates.z = false;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'z');
            }
        });
        
        // 触摸设备支持
        xHalf.addEventListener('touchstart', function(e) {
            e.preventDefault();
            if (!keyStates.x) {
                // 立即更新UI状态
                keyStates.x = true;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('down', 'x');
            }
        });
        
        xHalf.addEventListener('touchend', function(e) {
            e.preventDefault();
            if (keyStates.x) {
                // 立即更新UI状态
                keyStates.x = false;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'x');
            }
        });
        
        xHalf.addEventListener('touchcancel', function() {
            // 触摸取消,释放按键
            if (keyStates.x) {
                // 立即更新UI状态
                keyStates.x = false;
                updateStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'x');
            }
        });
        
        zHalf.addEventListener('touchstart', function(e) {
            e.preventDefault();
            if (!keyStates.z) {
                // 立即更新UI状态
                keyStates.z = true;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('down', 'z');
            }
        });
        
        zHalf.addEventListener('touchend', function(e) {
            e.preventDefault();
            if (keyStates.z) {
                // 立即更新UI状态
                keyStates.z = false;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'z');
            }
        });
        
        zHalf.addEventListener('touchcancel', function() {
            // 触摸取消,释放按键
            if (keyStates.z) {
                // 立即更新UI状态
                keyStates.z = false;
                updateZStatus();
                
                // 然后发送请求到服务器
                sendKeyAction('up', 'z');
            }
        });
        
        // 页面加载时获取初始状态
        window.onload = function() {
            updateStatus();
            updateZStatus();
        };
    </script>
</body>
</html>
'''

@app.route('/')
def index():
    """主页,提供HTML界面"""
    return render_template_string(HTML_TEMPLATE)

@socketio.on('key_control')
def handle_key_control(data):
    """处理按键控制请求"""
    action = data.get('action')
    key = data.get('key', '').lower()
    request_id = data.get('requestId')
    
    if key in ['x', 'z']:
        start_time = time.time()
        
        if action == 'down':
            result = fast_key_down(key)
            key_states[key] = True
        elif action == 'up':
            result = fast_key_up(key)
            key_states[key] = False
        else:
            result = {"status": "error", "message": "不支持的操作"}
        
        # 记录处理时间
        processing_time = (time.time() - start_time) * 1000  # 转换为毫秒
        print(f"{key.upper()}键 {action} 操作处理时间: {processing_time:.2f}ms")
        
        # 包含请求ID和按键信息的响应
        result['requestId'] = request_id
        result['key'] = key
        
        # 广播更新后的状态给所有连接的客户端
        socketio.emit('key_state_update', key_states)
        
        # 发送操作结果给发送者
        emit('key_response', result)

@socketio.on('get_key_state')
def handle_get_key_state():
    """获取当前按键状态"""
    emit('key_state_update', key_states)

if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)