简体   繁体   English

pygame在窗口未聚焦时捕获键盘事件

[英]pygame capture keyboard events when window not in focus

I wrote a simple python script that gives control over the cursor to a joystick.我写了一个简单的 python 脚本,可以控制操纵杆的光标。 My way to find out how this works is documented here .我了解其工作原理的方法记录在此处 Now that works flawlessly but, as soon as I start the script to use the joystick, the mouse is useless, because my python routine sets the value back to its original, whenever a new joystick event comes in.现在它完美无缺,但是,一旦我启动脚本以使用操纵杆,鼠标就无用了,因为每当有新的操纵杆事件出现时,我的 Python 例程都会将该值设置回其原始值。

Thus I want my joystick events to be ignored as long as a key of the keyboard is pressed.因此,只要按下键盘上的一个键,我就希望我的操纵杆事件被忽略。 I came across the pygame.key.get_pressed() method but this seems to work only, if the pygame window is in focus.我遇到了pygame.key.get_pressed()方法,但这似乎只有在 pygame 窗口处于焦点时才有效。 I want this script running in background.我希望这个脚本在后台运行。 Should I start using non-pygame events to listen to the keyboard or are there ways to keep track of the keyboard events analogue to the joystick events, which are recognized in background, via pygame?我应该开始使用非 pygame 事件来收听键盘,还是有办法跟踪键盘事件,类似于通过 pygame 在后台识别的操纵杆事件?

I expect pygame sets up its own "sandbox" so that it's hard to detect input from outside its window.我希望 pygame 设置自己的“沙箱”,以便很难检测到来自其窗口外的输入。 Your previous question indicates that you are also using the win32api module.您之前的问题表明您也在使用win32api模块。 We can use that to detect global key presses.我们可以用它来检测全局按键。

The correct way to detect key presses at the global scope is to set up a keyboard hook using SetWindowsHookEx .在全局范围内检测按键的正确方法是使用SetWindowsHookEx设置键盘挂钩。 Unfortunately, win32api does not expose that method, so we'll have to use a less efficient method.不幸的是,win32api 没有公开该方法,因此我们将不得不使用效率较低的方法。

The GetKeyState method can be used to determine whether a key is down or up. GetKeyState方法可用于确定键是按下还是按下。 You can continuously check the state of a key to see if the user has pressed or released it lately.您可以不断检查某个键的状态,以查看用户最近是否按下或释放了它。

import win32api
import time

def keyWasUnPressed():
    print "enabling joystick..."
    #enable joystick here

def keyWasPressed():
    print "disabling joystick..."
    #disable joystick here

def isKeyPressed(key):
    #"if the high-order bit is 1, the key is down; otherwise, it is up."
    return (win32api.GetKeyState(key) & (1 << 7)) != 0


key = ord('A')

wasKeyPressedTheLastTimeWeChecked = False
while True:
    keyIsPressed = isKeyPressed(key)
    if keyIsPressed and not wasKeyPressedTheLastTimeWeChecked:
        keyWasPressed()
    if not keyIsPressed and wasKeyPressedTheLastTimeWeChecked:
        keyWasUnPressed()
    wasKeyPressedTheLastTimeWeChecked = keyIsPressed
    time.sleep(0.01)

Warning: as with any "while True sleep and then check" loop, this method may use more CPU cycles than the equivalent "set a callback and wait" method.警告:与任何“while True sleep and then check”循环一样,此方法可能比等效的“设置回调并等待”方法使用更多的 CPU 周期。 You can extend the length of the sleep period to ameliorate this, but the key detection will take longer.您可以延长sleep时间的长度来改善这种情况,但关键检测将需要更长的时间。 For example, if you sleep for a full second, it may take up to one second between when you press a key and when the joystick is disabled.例如,如果您睡了整整一秒钟,则在您按下按键和操纵杆被禁用之间可能需要长达一秒钟的时间。

when your window gains or looses focus you get an ACTIVEEVENT .当你的窗口获得或失去焦点时,你会得到一个ACTIVEEVENT It's gain and state attributes tell you which state you've gained or lost.它的gainstate属性告诉您获得或失去了哪个状态。 The easisest solution would probably be to catch this events in your main event loop and use them to keep track weather you have focus or not.最简单的解决方案可能是在您的主事件循环中捕获这些事件,并使用它们来跟踪您是否关注天气。 Then you can just ignore joystick events if you don't have the focus.然后,如果您没有焦点,则可以忽略操纵杆事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM