简体   繁体   English

调整pygame窗口的大小而不会丢失键盘状态

[英]Resize pygame window without losing keyboard state

I'm facing a problem with pygame 1.9.2 based on SDL 1.2.15: the only mean of resizing window programmatically I see is pygame.display.set_mode(...) . 我遇到了基于SDL 1.2.15的pygame 1.9.2的问题:我看到的以编程方式调整窗口大小的唯一方法是pygame.display.set_mode(...) But when I call this method my keyboard state is reset, so all currently pressed keys and modifiers send KEYUP event, repeated keys are stopped too. 但是,当我调用此方法时,我的键盘状态将重置,因此所有当前按下的键和修饰符都会发送KEYUP事件,重复的键也将停止。

When the window is resized manually by user keyboard state is perfectly normal. 当通过用户键盘手动调整窗口大小时,这是完全正常的。 The event queue is paused for the time of resizing, then VIDEORESIZE and VIDEOEXPOSE events come up and keys are still pressed, if they were so. 事件队列在调整大小时暂停,然后出现VIDEORESIZEVIDEOEXPOSE事件,如果仍然如此,则仍然按下键。

There are few questions: 有几个问题:

  1. Is there a way to keep normal keyboard state while resizing window? 有没有办法在调整窗口大小时保持正常的键盘状态?
  2. If not, I would like to at least keep modifier keys but I can not just use key.set_mods() because I am unable to get the moment when user releases key. 如果不是,我至少要保留修饰键,但我不能只使用key.set_mods()因为我无法获得用户释放键的时刻。
  3. At last is there a way to invoke resizing of SDL window directly? 最后有没有一种方法可以直接调用SDL窗口的大小调整?

Example program demonstrates undesired behaviour. 示例程序演示了不良行为。 Left and right arrows resize window to same size, yet if they are pressed, there is only one keypress. 左箭头和右箭头将窗口大小调整为相同大小,但是如果按下它们,则只有一个按键。 Other keys are repeated normally if held. 如果按住其他键,通常会重复。 Output is event log for everything that happens. 输出是所有事件的事件日志。

import pygame
import sys

# same size all the time
size = (200, 200)

pygame.init()
pygame.display.set_mode(size, pygame.RESIZABLE)

# if left or right arrow key is held nothing will happen despite this line
pygame.key.set_repeat(500, 200)

run = True
while run:
    for event in pygame.event.get():
        out = '%s\t%s'%(event.type, str(event.dict))
        if event.type == pygame.QUIT:
            pygame.display.quit()
            run = False
        if event.type == pygame.KEYDOWN:
            # mods are also reset on set_mode() call
            out += ', mods = %i' % (pygame.key.get_mods())
            if event.key == pygame.K_LEFT:
                pygame.display.set_mode(size, pygame.RESIZABLE)
            if event.key == pygame.K_RIGHT:
                pygame.display.set_mode(size, pygame.RESIZABLE)

        print(out)

    pygame.time.Clock().tick(60)

Tested on Win machine but soon will report if linux fails too. 在Win机器上进行了测试,但很快会报告linux是否也会失败。

UPD: I've been digging into source of pygame and can not see why, but the documentation bundled with sources of pygame states, that Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display UPD:我一直在研究pygame的来源,无法理解为什么,但是与pygame的来源捆绑在一起的文档指出, Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display which implies that there is no way to resize window, only to recreate it. Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display窗口Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display ,这意味着无法调整窗口大小 ,只能重新创建窗口。 Seems a little strange to me. 对我来说似乎有些奇怪。

UPD: I have changed my progam behaviour so that resize does not actually happen until user releases keyboard completely. UPD:我已经更改了Progam的行为,以使调整大小直到用户完全释放键盘才真正发生。 It works well and does not break usability. 它运作良好,并且不会破坏可用性。

Nevertheless, it would be great to know if there exists a solution to stated problem. 但是,很高兴知道是否存在针对所述问题的解决方案。

One solution is, like self. 一种解决方案是像自我。 has mentioned, to store the states of the keys so that instead of using only the events, you could ignore this particular key up event. 如前所述,存储键的状态,以便您可以忽略此特定的键向上事件,而不是仅使用事件。 This could, however, have one problem. 但是,这可能会有一个问题。 If you are trying to create a key control to resize the screen, which you probably are doing, then you will also be ignoring the key up event that is real. 如果您试图创建一个按键控件来调整屏幕大小(您可能正在做),那么您也将忽略真实的按键事件。 Because this kind of control is rarely implemented, there does not seem to be any kind of clean solution, like a function to just change the screen, or one to suppress the false key events. 由于很少执行这种控件,因此似乎没有任何干净的解决方案,例如仅更改屏幕的功能或抑制错误按键事件的功能。 However, you could find a way around the key event problem. 但是,您可以找到解决关键事件问题的方法。 There are really two viable solutions. 确实有两个可行的解决方案。 The first one (and probably the worse of the two) is to create a way to identify the fake events, and selectively ignore the key up events. 第一个(可能是两者中更糟的一个)是创建一种方法来识别假事件,并有选择地忽略按键事件。 Probably the easiest way to do this is to resize the screen periodically during a fixed amount of time, so that you can expect a false keyboard event at this time, and ignore it. 可能最简单的方法是在固定时间段内定期调整屏幕大小,以便此时可以预期会出现错误的键盘事件,而忽略它。 Here is an example of the code to block a resize every second (specifically, it assumes a screen update occurs every time the system time has an exact second value, no fractions of a second) for the a key: 这是一个代码示例,该代码每秒钟阻止一次a键的大小调整(具体来说,它假定每次系统时间具有精确的第二个值(不包括秒)时,都会发生屏幕更新):

import pygame
import datetime

a_keydown = False
for event in pygame.event.get():
    if item.type == pygame.KEYDOWN and item.key == pygame.K_a:
        a_keydown = True
        print "keydown event"
    if item.type == pygame.KEYUP and item.key == pygame.K_a:
        if datetime.datetime.now().time()[4] > 15:           #leaves a window of fifteen microseconds for the screen resize, this may need to be adjusted
        a_keydown = False
        print "key up event"

The better of the two solutions is not this, however. 但是,这两种解决方案中最好的不是。 Assuming the keyup event created by set_mode exists soley in python, you could get key events from elsewhere, like pywin32 for example. 假设set_mode创建的keyup事件仅在python中存在,您就可以从其他地方获取键事件,例如pywin32。 Try using the win32api module, and something like the GetKeyState() function for what you need. 尝试使用win32api模块以及诸如GetKeyState()之类的功能来满足您的需求。 This will give you the last known state of a key. 这将为您提供密钥的最后已知状态。 Not quite as convenient as pythons event stream, but it may be your best solution, as pygame doesn't supply an elegant solution to this. 不如pythons事件流那么方便,但这可能是您最好的解决方案,因为pygame对此并不提供完善的解决方案。

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

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