1#!/usr/bin/env python 2 3import wx 4import wx.lib.mixins.listctrl as listmix 5from six import unichr 6 7#---------------------------------------------------------------------- 8 9keyMap = { 10 wx.WXK_BACK : "WXK_BACK", 11 wx.WXK_TAB : "WXK_TAB", 12 wx.WXK_RETURN : "WXK_RETURN", 13 wx.WXK_ESCAPE : "WXK_ESCAPE", 14 wx.WXK_SPACE : "WXK_SPACE", 15 wx.WXK_DELETE : "WXK_DELETE", 16 wx.WXK_START : "WXK_START", 17 wx.WXK_LBUTTON : "WXK_LBUTTON", 18 wx.WXK_RBUTTON : "WXK_RBUTTON", 19 wx.WXK_CANCEL : "WXK_CANCEL", 20 wx.WXK_MBUTTON : "WXK_MBUTTON", 21 wx.WXK_CLEAR : "WXK_CLEAR", 22 wx.WXK_SHIFT : "WXK_SHIFT", 23 wx.WXK_ALT : "WXK_ALT", 24 wx.WXK_MENU : "WXK_MENU", 25 wx.WXK_PAUSE : "WXK_PAUSE", 26 wx.WXK_CAPITAL : "WXK_CAPITAL", 27 #wx.WXK_PRIOR : "WXK_PRIOR", 28 #wx.WXK_NEXT : "WXK_NEXT", 29 wx.WXK_END : "WXK_END", 30 wx.WXK_HOME : "WXK_HOME", 31 wx.WXK_LEFT : "WXK_LEFT", 32 wx.WXK_UP : "WXK_UP", 33 wx.WXK_RIGHT : "WXK_RIGHT", 34 wx.WXK_DOWN : "WXK_DOWN", 35 wx.WXK_SELECT : "WXK_SELECT", 36 wx.WXK_PRINT : "WXK_PRINT", 37 wx.WXK_EXECUTE : "WXK_EXECUTE", 38 wx.WXK_SNAPSHOT : "WXK_SNAPSHOT", 39 wx.WXK_INSERT : "WXK_INSERT", 40 wx.WXK_HELP : "WXK_HELP", 41 wx.WXK_NUMPAD0 : "WXK_NUMPAD0", 42 wx.WXK_NUMPAD1 : "WXK_NUMPAD1", 43 wx.WXK_NUMPAD2 : "WXK_NUMPAD2", 44 wx.WXK_NUMPAD3 : "WXK_NUMPAD3", 45 wx.WXK_NUMPAD4 : "WXK_NUMPAD4", 46 wx.WXK_NUMPAD5 : "WXK_NUMPAD5", 47 wx.WXK_NUMPAD6 : "WXK_NUMPAD6", 48 wx.WXK_NUMPAD7 : "WXK_NUMPAD7", 49 wx.WXK_NUMPAD8 : "WXK_NUMPAD8", 50 wx.WXK_NUMPAD9 : "WXK_NUMPAD9", 51 wx.WXK_MULTIPLY : "WXK_MULTIPLY", 52 wx.WXK_ADD : "WXK_ADD", 53 wx.WXK_SEPARATOR : "WXK_SEPARATOR", 54 wx.WXK_SUBTRACT : "WXK_SUBTRACT", 55 wx.WXK_DECIMAL : "WXK_DECIMAL", 56 wx.WXK_DIVIDE : "WXK_DIVIDE", 57 wx.WXK_F1 : "WXK_F1", 58 wx.WXK_F2 : "WXK_F2", 59 wx.WXK_F3 : "WXK_F3", 60 wx.WXK_F4 : "WXK_F4", 61 wx.WXK_F5 : "WXK_F5", 62 wx.WXK_F6 : "WXK_F6", 63 wx.WXK_F7 : "WXK_F7", 64 wx.WXK_F8 : "WXK_F8", 65 wx.WXK_F9 : "WXK_F9", 66 wx.WXK_F10 : "WXK_F10", 67 wx.WXK_F11 : "WXK_F11", 68 wx.WXK_F12 : "WXK_F12", 69 wx.WXK_F13 : "WXK_F13", 70 wx.WXK_F14 : "WXK_F14", 71 wx.WXK_F15 : "WXK_F15", 72 wx.WXK_F16 : "WXK_F16", 73 wx.WXK_F17 : "WXK_F17", 74 wx.WXK_F18 : "WXK_F18", 75 wx.WXK_F19 : "WXK_F19", 76 wx.WXK_F20 : "WXK_F20", 77 wx.WXK_F21 : "WXK_F21", 78 wx.WXK_F22 : "WXK_F22", 79 wx.WXK_F23 : "WXK_F23", 80 wx.WXK_F24 : "WXK_F24", 81 wx.WXK_NUMLOCK : "WXK_NUMLOCK", 82 wx.WXK_SCROLL : "WXK_SCROLL", 83 wx.WXK_PAGEUP : "WXK_PAGEUP", 84 wx.WXK_PAGEDOWN : "WXK_PAGEDOWN", 85 wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE", 86 wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB", 87 wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER", 88 wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1", 89 wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2", 90 wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3", 91 wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4", 92 wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME", 93 wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT", 94 wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP", 95 wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT", 96 wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN", 97 #wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR", 98 wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP", 99 #wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT", 100 wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN", 101 wx.WXK_NUMPAD_END : "WXK_NUMPAD_END", 102 wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN", 103 wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT", 104 wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE", 105 wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL", 106 wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY", 107 wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD", 108 wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR", 109 wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT", 110 wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL", 111 wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE", 112 113 wx.WXK_WINDOWS_LEFT : "WXK_WINDOWS_LEFT", 114 wx.WXK_WINDOWS_RIGHT : "WXK_WINDOWS_RIGHT", 115 wx.WXK_WINDOWS_MENU : "WXK_WINDOWS_MENU", 116 117 wx.WXK_SPECIAL1 : "WXK_SPECIAL1", 118 wx.WXK_SPECIAL2 : "WXK_SPECIAL2", 119 wx.WXK_SPECIAL3 : "WXK_SPECIAL3", 120 wx.WXK_SPECIAL4 : "WXK_SPECIAL4", 121 wx.WXK_SPECIAL5 : "WXK_SPECIAL5", 122 wx.WXK_SPECIAL6 : "WXK_SPECIAL6", 123 wx.WXK_SPECIAL7 : "WXK_SPECIAL7", 124 wx.WXK_SPECIAL8 : "WXK_SPECIAL8", 125 wx.WXK_SPECIAL9 : "WXK_SPECIAL9", 126 wx.WXK_SPECIAL10 : "WXK_SPECIAL10", 127 wx.WXK_SPECIAL11 : "WXK_SPECIAL11", 128 wx.WXK_SPECIAL12 : "WXK_SPECIAL12", 129 wx.WXK_SPECIAL13 : "WXK_SPECIAL13", 130 wx.WXK_SPECIAL14 : "WXK_SPECIAL14", 131 wx.WXK_SPECIAL15 : "WXK_SPECIAL15", 132 wx.WXK_SPECIAL16 : "WXK_SPECIAL16", 133 wx.WXK_SPECIAL17 : "WXK_SPECIAL17", 134 wx.WXK_SPECIAL18 : "WXK_SPECIAL18", 135 wx.WXK_SPECIAL19 : "WXK_SPECIAL19", 136} 137 138if 'wxMac' in wx.PlatformInfo: 139 keyMap[wx.WXK_RAW_CONTROL] = 'WXK_RAW_CONTROL' 140 keyMap[wx.WXK_CONTROL] = "WXK_CONTROL" 141 keyMap[wx.WXK_COMMAND] = "WXK_COMMAND" 142else: 143 keyMap[wx.WXK_COMMAND] = "WXK_COMMAND" 144 keyMap[wx.WXK_CONTROL] = "WXK_CONTROL" 145 146 147#---------------------------------------------------------------------- 148 149class KeySink(wx.Window): 150 def __init__(self, parent): 151 wx.Window.__init__(self, parent, -1, style=wx.WANTS_CHARS 152 #| wx.RAISED_BORDER 153 #| wx.SUNKEN_BORDER 154 , name="sink") 155 156 self.SetBackgroundColour(wx.BLUE) 157 self.haveFocus = False 158 self.callSkip = True 159 self.logKeyDn = True 160 self.logKeyUp = True 161 self.logChar = True 162 163 self.Bind(wx.EVT_PAINT, self.OnPaint) 164 self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) 165 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) 166 self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) 167 168 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) 169 self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) 170 self.Bind(wx.EVT_CHAR, self.OnChar) 171 172 173 def SetCallSkip(self, skip): 174 self.callSkip = skip 175 176 def SetLogKeyUp(self, val): 177 self.logKeyUp = val 178 179 def SetLogKeyDn(self, val): 180 self.logKeyDn = val 181 182 def SetLogChar(self, val): 183 self.logChar = val 184 185 186 def OnPaint(self, evt): 187 dc = wx.PaintDC(self) 188 rect = self.GetClientRect() 189 dc.SetTextForeground(wx.WHITE) 190 dc.DrawLabel("Click here and then press some keys", 191 rect, wx.ALIGN_CENTER | wx.ALIGN_TOP) 192 if self.haveFocus: 193 dc.SetTextForeground(wx.GREEN) 194 dc.DrawLabel("Have Focus", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) 195 else: 196 dc.SetTextForeground(wx.RED) 197 dc.DrawLabel("Need Focus!", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) 198 199 200 def OnSetFocus(self, evt): 201 self.haveFocus = True 202 self.Refresh() 203 204 def OnKillFocus(self, evt): 205 self.haveFocus = False 206 self.Refresh() 207 208 def OnMouse(self, evt): 209 if evt.ButtonDown(): 210 self.SetFocus() 211 212 213 def OnKeyDown(self, evt): 214 if self.logKeyDn: 215 self.GetParent().keylog.LogKeyEvent("KeyDown", evt) 216 if self.callSkip: 217 evt.Skip() 218 219 def OnKeyUp(self, evt): 220 if self.logKeyUp: 221 self.GetParent().keylog.LogKeyEvent("KeyUp", evt) 222 if self.callSkip: 223 evt.Skip() 224 225 def OnChar(self, evt): 226 if self.logChar: 227 self.GetParent().keylog.LogKeyEvent("Char", evt) 228 229 230#---------------------------------------------------------------------- 231 232class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): 233 colHeaders = [ "Event Type", 234 "Key Name", 235 "Key Code", 236 "Modifiers", 237 "Unicode", 238 "UniChr", 239 "RawKeyCode", 240 "RawKeyFlags", 241 ] 242 243 def __init__(self, parent): 244 wx.ListCtrl.__init__(self, parent, -1, 245 style = wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES) 246 listmix.ListCtrlAutoWidthMixin.__init__(self) 247 248 for idx, header in enumerate(self.colHeaders): 249 self.InsertColumn(idx, header) 250 idx += 1 251 self.InsertColumn(idx, "") 252 253 for x in range(idx): 254 self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER) 255 256 self.SetColumnWidth(1, 125) 257 258 259 def LogKeyEvent(self, evType, evt): 260 keycode = evt.GetKeyCode() 261 keyname = keyMap.get(keycode, None) 262 263 if keyname is None: 264 if keycode < 256: 265 if keycode == 0: 266 keyname = "NUL" 267 elif keycode < 27: 268 keyname = u"Ctrl-%s" % unichr(ord('A') + keycode-1) 269 else: 270 keyname = u"\"%s\"" % unichr(keycode) 271 else: 272 keyname = u"(%s)" % keycode 273 274 UniChr = '' 275 if "unicode" in wx.PlatformInfo: 276 UniChr = "\"" + unichr(evt.GetUnicodeKey()) + "\"" 277 278 modifiers = "" 279 for mod, ch in [(evt.ControlDown(), 'C'), 280 (evt.AltDown(), 'A'), 281 (evt.ShiftDown(), 'S'), 282 (evt.MetaDown(), 'M'), 283 (evt.RawControlDown(), 'R'),]: 284 if mod: 285 modifiers += ch 286 else: 287 modifiers += '-' 288 289 id = self.InsertItem(self.GetItemCount(), evType) 290 self.SetItem(id, 1, keyname) 291 self.SetItem(id, 2, str(keycode)) 292 self.SetItem(id, 3, modifiers) 293 self.SetItem(id, 4, str(evt.GetUnicodeKey())) 294 self.SetItem(id, 5, UniChr) 295 self.SetItem(id, 6, str(evt.GetRawKeyCode())) 296 self.SetItem(id, 7, str(evt.GetRawKeyFlags())) 297 298 self.EnsureVisible(id) 299 300 301 def ClearLog(self): 302 self.DeleteAllItems() 303 304 def CopyLog(self): 305 # build a newline and tab delimited string to put into the clipboard 306 if "unicode" in wx.PlatformInfo: 307 st = u"" 308 else: 309 st = "" 310 for h in self.colHeaders: 311 st += h + "\t" 312 st += "\n" 313 314 for idx in range(self.GetItemCount()): 315 for col in range(self.GetColumnCount()): 316 item = self.GetItem(idx, col) 317 st += item.GetText() + "\t" 318 st += "\n" 319 320 data = wx.TextDataObject() 321 data.SetText(st) 322 if wx.TheClipboard.Open(): 323 wx.TheClipboard.SetData(data) 324 wx.TheClipboard.Close() 325 else: 326 wx.MessageBox("Unable to open the clipboard", "Error") 327 328 329 330 331#---------------------------------------------------------------------- 332 333 334class TestPanel(wx.Panel): 335 def __init__(self, parent, log): 336 self.log = log 337 wx.Panel.__init__(self, parent, -1, style=0) 338 self.keysink = KeySink(self) 339 self.keysink.SetMinSize((100, 65)) 340 self.keylog = KeyLog(self) 341 342 btn = wx.Button(self, -1, "Clear", style=wx.BU_EXACTFIT) 343 self.Bind(wx.EVT_BUTTON, self.OnClearBtn, btn) 344 btn.SetToolTip( 345 "Clear the items from the log window") 346 347 btn2 = wx.Button(self, -1, "Copy", style=wx.BU_EXACTFIT) 348 self.Bind(wx.EVT_BUTTON, self.OnCopyBtn, btn2) 349 btn2.SetToolTip( 350 "Copy the contents of the log window to the clipboard") 351 352 cb1 = wx.CheckBox(self, -1, "Call evt.Skip in Key* events") 353 self.Bind(wx.EVT_CHECKBOX, self.OnSkipCB, cb1) 354 cb1.SetValue(True) 355 356 cb2 = wx.CheckBox(self, -1, "KEY_UP") 357 self.Bind(wx.EVT_CHECKBOX, self.OnKeyUpCB, cb2) 358 cb2.SetValue(True) 359 360 cb3 = wx.CheckBox(self, -1, "KEY_DOWN") 361 self.Bind(wx.EVT_CHECKBOX, self.OnKeyDnCB, cb3) 362 cb3.SetValue(True) 363 364 cb4 = wx.CheckBox(self, -1, "CHAR") 365 self.Bind(wx.EVT_CHECKBOX, self.OnCharCB, cb4) 366 cb4.SetValue(True) 367 368 buttons = wx.BoxSizer(wx.HORIZONTAL) 369 buttons.Add(btn, 0, wx.ALL, 4) 370 buttons.Add(btn2, 0, wx.ALL, 4) 371 buttons.Add(cb1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 6) 372 buttons.Add(cb2, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) 373 buttons.Add(cb3, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) 374 buttons.Add(cb4, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) 375 376 sizer = wx.BoxSizer(wx.VERTICAL) 377 sizer.Add(self.keysink, 0, wx.GROW) 378 sizer.Add(buttons) 379 sizer.Add(self.keylog, 1, wx.GROW) 380 381 self.SetSizer(sizer) 382 383 384 def OnClearBtn(self, evt): 385 self.keylog.ClearLog() 386 387 def OnCopyBtn(self, evt): 388 self.keylog.CopyLog() 389 390 def OnSkipCB(self, evt): 391 self.keysink.SetCallSkip(evt.GetInt()) 392 393 def OnKeyUpCB(self, evt): 394 self.keysink.SetLogKeyUp(evt.GetInt()) 395 396 def OnKeyDnCB(self, evt): 397 self.keysink.SetLogKeyDn(evt.GetInt()) 398 399 def OnCharCB(self, evt): 400 self.keysink.SetLogChar(evt.GetInt()) 401 402 403#---------------------------------------------------------------------- 404 405def runTest(frame, nb, log): 406 win = TestPanel(nb, log) 407 return win 408 409#---------------------------------------------------------------------- 410 411 412 413overview = """<html><body> 414<h2><center>wxKeyEvents</center></h2> 415 416This demo simply catches all key events and prints info about them. 417It is meant to be used as a compatibility test for cross platform work. 418 419</body></html> 420""" 421 422 423 424if __name__ == '__main__': 425 import sys,os 426 import run 427 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) 428 429