wx.KeyboardState

I’m trying to use the Control key to modify what happens when I click a button (which copies some info from a text control). However, it doesn’t appear to actually detect the status of the modifier keys at all.

Sample code:

    def handleCopyUIDButton(self, evt):
        evt.Skip()

        uid = self.uid.GetValue()

        if self.kbs.GetModifiers() == wx.MOD_CONTROL:
            print("ctl on")
        else:
            print("ctl off")

I’m initializing the keyboard state class in the init of the panel that this method belongs to:

self.kbs = wx.KeyboardState()

The documentation is kind of skimpy on specifics so I expected it would be straightforward, but turns out, not so much.

I have tried a number of ways to get the state of the keys, including the above, using ControlDown() (which is advised against), and looking at the actual properties (which are always zero’d).

Probably a simple solution, but I’m not seeing it. Any hints?

This is a bit tricky I’m afraid.
Fist of all, I’m not sure if you already got this part right, but just in case: if you bind a button to EVT_BUTTON as usual, you are catching a CommandEvent, which has no knowledge of any keyboard modifiers.
The event you want to catch is really a MouseEvent: if you check its inheritance diagram, you’ll see that MouseEvent, indeed, has KeyboardState as one of its ancestors: bingo!
So, you will have to bind the button to EVT_LEFT_DOWN or (much better) to EVT_LEFT_UP to access this whole keyboard thing. Don’t forget to Skip the event in the callback, to let the next CommanEvent trigger.

Second, this is not how KeyboardState is supposed to work. You don’t have to create an empty instance by yourself. If you catch the right MouseEvent, then the event is already carrying all the KeyboardState info you need, since it derives from it. All you have to do is to ask directly to the event instance: specifically, you call KeyboardState.GetModifiers on the event instance.
This is a working example of what you want:

class Main(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k)
        p = wx.Panel(self)
        b = wx.Button(p, -1, 'clic', pos=(10, 10))
        b.Bind(wx.EVT_LEFT_UP, self.onclic)
        
    def onclic(self, evt):
        evt.Skip()
        mods = evt.GetModifiers() # THIS is how you call wx.KeyboardState.GetModifiers()
        if mods == wx.MOD_CONTROL:
            print('Control')
        elif mods == wx.MOD_CONTROL|wx.MOD_SHIFT:
            print('Control + Shift')
        elif evt.HasAnyModifiers(): # again, this is really wx.KeyboardState.HasAnyModifiers()
            print('Some other modifier')
        else:
            print('No modifier')
 
app = wx.App()
Main(None).Show()
app.MainLoop()

edit: KeyboardState comes with a few handy shortcuts like HasAnyModifiers, ControlDown etc. You can use those if you want, instad of checking GetModifiers. But, again, on the event instance: ie, “if evt.ControlDown(): …”

try

test_evt_key_down.py (579 Bytes)

@ricpol ,

Wow, that feels kinda non-intuitive, but it works! I don’t think I would have found that without your help, thanks!

Problem solved, all is right in the world. :slight_smile: