[Not a bug, solved] Bug with "-up" events?

After running Panda with PStats, i.e. when the main window is not active, it generates “-up” event for all buttons. Is it normal or bug? I have actions bound on releasing some buttons, so, these actions are performed without intention.

EDIT: I have found, that “-up” events are sent every time I switch from the Panda’s main 3D window to the PStats window.

Here is the test code:

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject

class Test(DirectObject):
    def __init__(self):
        self.accept("1-up", self.upEvent)

    def upEvent(self):
        frame = globalClock.getFrameCount()
        print "'-up' event generated:", frame

test = Test()

run()

Run it, and then switch to any other window and back to Panda.
Even more, looking closely, I found that it even generates two events, not one! Here is the output:

Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
:util(warning): Adjusting global clock's real time by 1.17559e-005 seconds.
:util(warning): Adjusting global clock's real time by -0.0396634 seconds.
DirectStart: Starting the game.
Warning: DirectNotify: category 'Interval' already exists
'-up' event generated: 241
'-up' event generated: 241
'-up' event generated: 329
'-up' event generated: 329
'-up' event generated: 415
'-up' event generated: 415

It’s the default behavior for Windows, and not yet implemented on Linux. The purpose is to manage the keypress state upon switching windows.
It’s in winGraphicsWindow.cxx :

#ifndef WANT_NEW_FOCUS_MANAGMENT
        if (!_lost_keypresses) 
        {
          // Record the current state of the keyboard when the focus is
          // lost, so we can check it for changes when we regain focus.
          GetKeyboardState(_keyboard_state);
          if (windisplay_cat.is_debug()) {
            // Report the set of keys that are held down at the time of
            // the killfocus event.
            for (int i = 0; i < num_virtual_keys; i++) 
            {
              if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) 
              {
                if ((_keyboard_state[i] & 0x80) != 0) 
                {
                  windisplay_cat.debug()
                    << "on killfocus, key is down: " << i
                    << " (" << lookup_key(i) << ")\n";
                }
              }
            }
          }

          if (!hold_keys_across_windows) 
          {
            // If we don't want to remember the keystate while the
            // window focus is lost, then generate a keyup event
            // right now for each key currently held.
            double message_time = get_message_time();
            for (int i = 0; i < num_virtual_keys; i++) 
            {
              if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) 
              {
                if ((_keyboard_state[i] & 0x80) != 0) 
                {
                  handle_keyrelease(lookup_key(i), message_time);
                  _keyboard_state[i] &= ~0x80;
                }
              }
            }
          }
          
          // Now set the flag indicating that some keypresses from now
          // on may be lost.
          _lost_keypresses = true;
        }
#else // WANT_NEW_FOCUS_MANAGMENT
        {
            double message_time = get_message_time();
            int i;
            for (i = 0; i < num_virtual_keys; i++) {
              ButtonHandle bh = lookup_key(i);
              if(bh != ButtonHandle::none()) {
                handle_keyrelease(bh,message_time);
              }
            }
            memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys);

            // Also up the mouse buttons.
            for (i = 0; i < MouseButton::num_mouse_buttons; ++i) {
              handle_keyrelease(MouseButton::button(i), message_time);
            }
            handle_keyrelease(MouseButton::wheel_up(), message_time);
            handle_keyrelease(MouseButton::wheel_down(), message_time);

            _lost_keypresses = true;
        }
#endif // WANT_NEW_FOCUS_MANAGMENT

WANT_NEW_FOCUS_MANAGMENT is defined by default. So, as you can see, what happens is all keys -up events will be thrown if panda window loses its focus. Recording the keys states should behave better than just throwing all release events, but this is just my opinion, and I’ve never tried to undef WANT_NEW_FOCUS_MANAGMENT.

I don’t know if there is any config var to control this behavior.
I found this is frustrating too, so I created this simple -up events silencer, which is triggered by “window-event” event :

mutedUpEvents=[]
focusLost=0

def rescueUpEvents(win):
    global mutedUpEvents,focusLost
    props= win.getProperties()
    minimized=props.getMinimized()
    foreground=props.getForeground()
    if not focusLost and (minimized or not foreground):
       print 'FOCUS LOST'
       mutedUpEvents=[]
       focusLost=1
       for e in messenger.getEvents():
           if e[-3:]=='-up':
              mutedUpEvents.append((e,messenger.whoAccepts(e).copy()))
       for e,listeners in mutedUpEvents:
           for l in listeners:
               messenger.ignore(e,l)
    elif not base.mainWinMinimized:
       print 'FOCUS GAINED'
       focusLost=0
       for e,listeners in mutedUpEvents:
           for o,m in listeners.items():
               messenger.accept(e,o,*m)

And you need to catch “window-event” event :

accept('window-event',rescueUpEvents)

Actually, I think this is not a bug, but a feature. Since Panda3D can’t grab keyboard events anymore when the keyboard focus is out of the window, you would get very strange bugs when somebody changed the key status and focused back to Panda3D’s window (as you might remember the bug that your keyboard events didnt work anymore when you used alt+tab to switch to another window.)

I see. Anyway, this must be clearly explained in the manual. In my case I spent the whole day try to understand why my application quietly exits when I run PStats. Not knowing about this “feature”, I coded such function that closes my application on “escape-up”… He-he :laughing:
ynjh_jo, thank you for the code! Now everything is fine.

PS: I will add this “feature” to the manual later tonight.

Sorry, it’s not that good. I tried to rapidly minimize/restore by clicking the panda window bar in taskbar, and it failed too soon.
The updated code should work better, though there isn’t any guarantee.

this breaks printscreen-up because it only has an up key. I get print screen every time some one focuses out of the window. Can we change it for this key? Or is there a better work around?

Undoubtedly there is a better workaround. I never did like this one.

David

also we can keep all up events. And when user focuses away we get only those up events that had a down event before…

this sounds like the best solution for me

is it an Xorg issue on linux or something WM-dependent?