Hi there
There are two ways to get key events: EVT_KEY_DOWN
and EVT_CHAR_HOOK
.
Both trigger wx.KeyEvent
but the behavior during mouse capture is different.
During mouse capture, EVT_KEY_DOWN
triggers the event but EVT_CHAR_HOOK
does not.
Is there any reason for this design? Or does anyone know it?
If not, I’d like to propose that the EVT_CHAR_HOOK
can trigger the key event even while the mouse is captured.
The reason is as follows:
Recently, the wxagg backend of matplotlib has changed the key event binder from EVT_KEY_DOWN
to EVT_CHAR_HOOK
since 3.4.
This allows you to get key events of so-called navigation keys [alt], [Tab], and [Left | Right | Up | Down].
This change is nice, however, when you start capturing the mouse (i.e. dragging), the key event will no longer be triggered.
This will cause undesired behaviors for me. For example, if you press a key while dragging, say [ESC] key to cancel dragging, the key event does not come and the dragging state cannot be canceled.
I don’t think this depends on OS.
I added a sample code to see this action. (Please substitute ‘Vippi.png’ to appropriate image file)
Code Example (click to expand)
import wx
class TestPanel(wx.Panel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._org = None
vippi = wx.Bitmap('Vippi.png')
self.canvas = wx.Panel(self, size=vippi.GetSize()) # to get keys
## self.canvas = wx.StaticBitmap(self, bitmap=vippi) # no focus, no keys
def on_paint(evt):
dc = wx.PaintDC(self.canvas)
dc.DrawBitmap(vippi, 0, 0, False)
evt.Skip()
self.canvas.Bind(wx.EVT_PAINT, on_paint)
self.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.canvas.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMove)
def on_keys(evt):
print(evt.EventType, evt.KeyCode)
evt.Skip()
self.canvas.Bind(wx.EVT_KEY_DOWN, on_keys) # 10057 - ok while capturing
self.canvas.Bind(wx.EVT_CHAR_HOOK, on_keys) # 10055 - no while capturing
def OnLeftDown(self, evt):
self._org = evt.Position
self.canvas.CaptureMouse()
evt.Skip()
def OnLeftUp(self, evt):
self._org = None
if self.canvas.HasCapture():
self.canvas.ReleaseMouse()
evt.Skip()
def OnMouseMove(self, evt):
if self._org is not None:
self.canvas.Position += evt.Position - self._org
evt.Skip()
if __name__ == "__main__":
app = wx.App()
frm = wx.Frame(None)
panel = TestPanel(frm)
frm.Show()
app.MainLoop()