You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中设置Windows屏幕键盘(OSK)位置及事件触发关闭的问题

Python中设置Windows屏幕键盘(OSK)位置及事件触发关闭的问题

嘿,我来帮你搞定这个Windows屏幕键盘(OSK)的位置设置和触发关闭的问题!你的思路方向是对的,但踩了几个Windows系统程序的小坑,我给你一步步捋清楚,再上修改后的可用代码:

先说说现有代码为啥不好使

  1. 窗口匹配不准:你用标题里找"osk"来定位窗口,但不同语言的系统里OSK的标题不一样啊——英文系统是"On-Screen Keyboard",中文是"屏幕键盘",哪能都包含"osk"?其实OSK有个固定的窗口类名OSKMainClass,用这个匹配才靠谱,不会受语言影响。
  2. 固定sleep太死板:等10秒完全没必要,万一OSK1秒就启动好了,你要白等9秒;要是系统卡了10秒还没启动好,那MoveWindow照样没用。不如循环检测,直到找到OSK窗口再操作。
  3. 关闭方式错了:pro.terminate()根本杀不掉OSK!因为你用Popen启动的osk.exe其实是个启动器,它触发OSK显示之后自己就退出了,你存的pro对应的进程早就没了,自然没法通过它终止OSK。得用窗口句柄给OSK发关闭消息才行。

修改后的完整可用代码

import subprocess
import win32gui
import win32con
import time
from subprocess import Popen

# 配置参数,按需调整
OSK_CLASS_NAME = "OSKMainClass"
X_POS = 50
Y_POS = 400
WIDTH = 800
HEIGHT = 600

# 全局存OSK的窗口句柄,打开时记录,关闭时直接用
osk_hwnd = None

def find_osk_window():
    """循环检测直到找到OSK窗口,最多等5秒"""
    global osk_hwnd
    timeout = 5
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        def enum_handler(hwnd, _):
            global osk_hwnd
            # 用固定类名匹配,不受系统语言影响
            if win32gui.GetClassName(hwnd) == OSK_CLASS_NAME and win32gui.IsWindowVisible(hwnd):
                osk_hwnd = hwnd
        
        win32gui.EnumWindows(enum_handler, None)
        if osk_hwnd:
            break  # 找到窗口就退出循环
        time.sleep(0.5)  # 没找到就等0.5秒再查
    return osk_hwnd

def open_keyboard(event=None):
    # 启动OSK,shell=True不是必须的,这里去掉也能跑
    subprocess.Popen("osk.exe")
    # 等待并定位OSK窗口
    if find_osk_window():
        # 移动窗口到指定位置,同时设置尺寸
        win32gui.MoveWindow(osk_hwnd, X_POS, Y_POS, WIDTH, HEIGHT, True)
        print(f"OSK已经移到({X_POS}, {Y_POS}),尺寸设为{WIDTH}x{HEIGHT}啦")
    else:
        print("等了5秒还没找到OSK窗口,是不是权限不够?")

def close_keyboard(event=None):
    global osk_hwnd
    if osk_hwnd and win32gui.IsWindow(osk_hwnd):
        # 给窗口发送关闭消息,和手动点叉效果一样
        win32gui.SendMessage(osk_hwnd, win32con.WM_CLOSE, 0, 0)
        osk_hwnd = None  # 重置句柄,下次打开重新找
        print("OSK已经关闭咯")
    else:
        print("没找到可以关闭的OSK窗口哦")

# 测试用的,你可以删掉换成自己的事件触发逻辑
if __name__ == "__main__":
    open_keyboard()
    input("按回车键关闭OSK...")
    close_keyboard()

关键改动说明

  1. 用窗口类名定位OSK:OSKMainClass是Windows给屏幕键盘留的固定类名,不管系统是英文还是中文,都能精准找到,不会出错。
  2. 动态等待窗口出现:不再死等10秒,最多等5秒,找到窗口就立刻操作,效率高多了。
  3. 正确关闭OSK:通过给OSK窗口发送WM_CLOSE消息来关闭,这才是系统程序的正确关闭方式,完全避开了Popen进程的问题。
  4. 全局句柄管理:打开OSK时把窗口句柄存起来,关闭时直接用,不用再重新枚举所有窗口,省事儿又高效。

额外要注意的点

  • 一定要用管理员权限运行你的Python程序!OSK是系统级程序,移动窗口这类操作需要管理员权限才能生效,不然可能没反应。
  • 多显示器环境下,MoveWindow的坐标是相对于主显示器的,要是想把OSK放到副屏,得自己调整X、Y的数值。
  • OSK是单实例程序,重复调用osk.exe只会显示已有的窗口,不会开新的,所以多次调用open_keyboard也不会重复创建。

备注:内容来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 15:39:32