Python中设置Windows屏幕键盘(OSK)位置及事件触发关闭的问题
Python中设置Windows屏幕键盘(OSK)位置及事件触发关闭的问题
嘿,我来帮你搞定这个Windows屏幕键盘(OSK)的位置设置和触发关闭的问题!你的思路方向是对的,但踩了几个Windows系统程序的小坑,我给你一步步捋清楚,再上修改后的可用代码:
先说说现有代码为啥不好使
- 窗口匹配不准:你用标题里找"osk"来定位窗口,但不同语言的系统里OSK的标题不一样啊——英文系统是"On-Screen Keyboard",中文是"屏幕键盘",哪能都包含"osk"?其实OSK有个固定的窗口类名
OSKMainClass,用这个匹配才靠谱,不会受语言影响。 - 固定sleep太死板:等10秒完全没必要,万一OSK1秒就启动好了,你要白等9秒;要是系统卡了10秒还没启动好,那MoveWindow照样没用。不如循环检测,直到找到OSK窗口再操作。
- 关闭方式错了:
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()
关键改动说明
- 用窗口类名定位OSK:
OSKMainClass是Windows给屏幕键盘留的固定类名,不管系统是英文还是中文,都能精准找到,不会出错。 - 动态等待窗口出现:不再死等10秒,最多等5秒,找到窗口就立刻操作,效率高多了。
- 正确关闭OSK:通过给OSK窗口发送
WM_CLOSE消息来关闭,这才是系统程序的正确关闭方式,完全避开了Popen进程的问题。 - 全局句柄管理:打开OSK时把窗口句柄存起来,关闭时直接用,不用再重新枚举所有窗口,省事儿又高效。
额外要注意的点
- 一定要用管理员权限运行你的Python程序!OSK是系统级程序,移动窗口这类操作需要管理员权限才能生效,不然可能没反应。
- 多显示器环境下,
MoveWindow的坐标是相对于主显示器的,要是想把OSK放到副屏,得自己调整X、Y的数值。 - OSK是单实例程序,重复调用
osk.exe只会显示已有的窗口,不会开新的,所以多次调用open_keyboard也不会重复创建。
备注:内容来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

