#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PPT遥控器电脑端应用
支持Windows和MacOS系统
使用WebSocket接收手机端控制命令，通过模拟键盘按键控制PPT翻页
"""

import asyncio
import platform
import socket
import os
import threading
import json
import time
import websockets

# 根据操作系统选择不同的键盘控制方法
system = platform.system()
# UDP广播相关配置
UDP_BROADCAST_PORT = 5000
UDP_BROADCAST_INTERVAL = 2  # 广播间隔（秒）

def get_local_ip():
    """获取本地IP地址"""
    try:
        # 创建一个UDP套接字连接到外部服务器
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception as e:
        print(f"获取IP地址失败: {e}")
        return "127.0.0.1"

def press_key(key):
    """根据操作系统模拟键盘按键"""
    if system == "Darwin":  # MacOS
        # 使用AppleScript模拟键盘按键
        script = f'''
        tell application "System Events"
            key code {get_key_code(key)}
        end tell
        '''
        os.system(f"osascript -e '{script}'")
    elif system == "Windows":
        # 使用ctypes调用Windows API模拟键盘按键
        import ctypes
        user32 = ctypes.WinDLL('user32', use_last_error=True)
        
        # 定义键盘事件常量
        KEYEVENTF_KEYDOWN = 0x0000
        KEYEVENTF_KEYUP = 0x0002
        
        # 获取虚拟键码
        vk_code = get_vk_code(key)
        
        # 按下键
        user32.keybd_event(vk_code, 0, KEYEVENTF_KEYDOWN, 0)
        # 释放键
        user32.keybd_event(vk_code, 0, KEYEVENTF_KEYUP, 0)
    else:
        print(f"不支持的操作系统: {system}")

def get_key_code(key):
    """获取MacOS的键码"""
    key_codes = {
        "right": 124,
        "left": 123,
        "f5": 96,
        "esc": 53
    }
    return key_codes.get(key, 0)

def get_vk_code(key):
    """获取Windows的虚拟键码"""
    vk_codes = {
        "right": 0x27,
        "left": 0x25,
        "f5": 0x74,
        "esc": 0x1B
    }
    return vk_codes.get(key, 0)

async def handle_client(websocket):
    """处理客户端连接"""
    try:
        # 获取客户端地址
        client_address = websocket.remote_address
        print(f"新客户端已连接: {client_address}")
        
        # 发送欢迎消息
        await websocket.send("电脑端已就绪，等待控制命令")
        
        # 接收消息循环
        async for message in websocket:
            print(f"收到来自 {client_address} 的消息: {message}")
            
            # 根据消息执行相应的PPT控制操作
            if message == "next":
                # 下一页：按右箭头键
                print("执行下一页操作")
                press_key("right")
            elif message == "prev":
                # 上一页：按左箭头键
                print("执行上一页操作")
                press_key("left")
            elif message == "start":
                # 开始播放：按F5键
                print("执行开始播放操作")
                press_key("f5")
            elif message == "stop":
                # 停止播放：按Esc键
                print("执行停止播放操作")
                press_key("esc")
            else:
                print(f"未知命令: {message}")
                
    except Exception as e:
        print(f"客户端连接异常: {e}")
    finally:
        print(f"客户端已断开连接: {client_address}")

def start_udp_broadcast(local_ip, ws_port):
    """启动UDP广播服务"""
    # 创建UDP套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    
    # 准备广播数据
    broadcast_data = json.dumps({
        "type": "ppt_remote_server",
        "ip": local_ip,
        "port": ws_port,
        "name": socket.gethostname(),
        "system": system
    })
    
    print(f"UDP广播已启动，端口: {UDP_BROADCAST_PORT}")
    
    try:
        while True:
            # 发送广播
            sock.sendto(broadcast_data.encode('utf-8'), ('255.255.255.255', UDP_BROADCAST_PORT))
            time.sleep(UDP_BROADCAST_INTERVAL)
    except Exception as e:
        print(f"UDP广播异常: {e}")
    finally:
        sock.close()

async def start_server():
    """启动WebSocket服务器"""
    # 获取本地IP地址
    local_ip = get_local_ip()
    port = 8765
    
    print(f"=== PPT遥控器电脑端 ===")
    print(f"系统: {platform.system()} {platform.release()}")
    print(f"本地IP地址: {local_ip}")
    print(f"WebSocket服务器端口: {port}")
    print(f"UDP广播端口: {UDP_BROADCAST_PORT}")
    print(f"请确保手机和电脑在同一局域网内")
    print(f"手机端请连接到: ws://{local_ip}:{port}")
    print("按 Ctrl+C 停止服务器")
    print("=" * 50)
    
    # 启动UDP广播线程
    broadcast_thread = threading.Thread(
        target=start_udp_broadcast,
        args=(local_ip, port),
        daemon=True
    )
    broadcast_thread.start()
    
    # 创建WebSocket服务器
    async with websockets.serve(handle_client, local_ip, port):
        await asyncio.Future()  # 无限运行

if __name__ == "__main__":
    import websockets
    try:
        asyncio.run(start_server())
    except KeyboardInterrupt:
        print("\n服务器已停止")