| 1 | |
| 2 | import wx |
| 3 | import wx.lib.mixins.listctrl as listmix |
| 4 | |
| 5 | #---------------------------------------------------------------------- |
| 6 | |
| 7 | keyMap = { |
| 8 | wx.WXK_BACK : "wx.WXK_BACK", |
| 9 | wx.WXK_TAB : "wx.WXK_TAB", |
| 10 | wx.WXK_RETURN : "wx.WXK_RETURN", |
| 11 | wx.WXK_ESCAPE : "wx.WXK_ESCAPE", |
| 12 | wx.WXK_SPACE : "wx.WXK_SPACE", |
| 13 | wx.WXK_DELETE : "wx.WXK_DELETE", |
| 14 | wx.WXK_START : "wx.WXK_START", |
| 15 | wx.WXK_LBUTTON : "wx.WXK_LBUTTON", |
| 16 | wx.WXK_RBUTTON : "wx.WXK_RBUTTON", |
| 17 | wx.WXK_CANCEL : "wx.WXK_CANCEL", |
| 18 | wx.WXK_MBUTTON : "wx.WXK_MBUTTON", |
| 19 | wx.WXK_CLEAR : "wx.WXK_CLEAR", |
| 20 | wx.WXK_SHIFT : "wx.WXK_SHIFT", |
| 21 | wx.WXK_ALT : "wx.WXK_ALT", |
| 22 | wx.WXK_CONTROL : "wx.WXK_CONTROL", |
| 23 | wx.WXK_MENU : "wx.WXK_MENU", |
| 24 | wx.WXK_PAUSE : "wx.WXK_PAUSE", |
| 25 | wx.WXK_CAPITAL : "wx.WXK_CAPITAL", |
| 26 | wx.WXK_PRIOR : "wx.WXK_PRIOR", |
| 27 | wx.WXK_NEXT : "wx.WXK_NEXT", |
| 28 | wx.WXK_END : "wx.WXK_END", |
| 29 | wx.WXK_HOME : "wx.WXK_HOME", |
| 30 | wx.WXK_LEFT : "wx.WXK_LEFT", |
| 31 | wx.WXK_UP : "wx.WXK_UP", |
| 32 | wx.WXK_RIGHT : "wx.WXK_RIGHT", |
| 33 | wx.WXK_DOWN : "wx.WXK_DOWN", |
| 34 | wx.WXK_SELECT : "wx.WXK_SELECT", |
| 35 | wx.WXK_PRINT : "wx.WXK_PRINT", |
| 36 | wx.WXK_EXECUTE : "wx.WXK_EXECUTE", |
| 37 | wx.WXK_SNAPSHOT : "wx.WXK_SNAPSHOT", |
| 38 | wx.WXK_INSERT : "wx.WXK_INSERT", |
| 39 | wx.WXK_HELP : "wx.WXK_HELP", |
| 40 | wx.WXK_NUMPAD0 : "wx.WXK_NUMPAD0", |
| 41 | wx.WXK_NUMPAD1 : "wx.WXK_NUMPAD1", |
| 42 | wx.WXK_NUMPAD2 : "wx.WXK_NUMPAD2", |
| 43 | wx.WXK_NUMPAD3 : "wx.WXK_NUMPAD3", |
| 44 | wx.WXK_NUMPAD4 : "wx.WXK_NUMPAD4", |
| 45 | wx.WXK_NUMPAD5 : "wx.WXK_NUMPAD5", |
| 46 | wx.WXK_NUMPAD6 : "wx.WXK_NUMPAD6", |
| 47 | wx.WXK_NUMPAD7 : "wx.WXK_NUMPAD7", |
| 48 | wx.WXK_NUMPAD8 : "wx.WXK_NUMPAD8", |
| 49 | wx.WXK_NUMPAD9 : "wx.WXK_NUMPAD9", |
| 50 | wx.WXK_MULTIPLY : "wx.WXK_MULTIPLY", |
| 51 | wx.WXK_ADD : "wx.WXK_ADD", |
| 52 | wx.WXK_SEPARATOR : "wx.WXK_SEPARATOR", |
| 53 | wx.WXK_SUBTRACT : "wx.WXK_SUBTRACT", |
| 54 | wx.WXK_DECIMAL : "wx.WXK_DECIMAL", |
| 55 | wx.WXK_DIVIDE : "wx.WXK_DIVIDE", |
| 56 | wx.WXK_F1 : "wx.WXK_F1", |
| 57 | wx.WXK_F2 : "wx.WXK_F2", |
| 58 | wx.WXK_F3 : "wx.WXK_F3", |
| 59 | wx.WXK_F4 : "wx.WXK_F4", |
| 60 | wx.WXK_F5 : "wx.WXK_F5", |
| 61 | wx.WXK_F6 : "wx.WXK_F6", |
| 62 | wx.WXK_F7 : "wx.WXK_F7", |
| 63 | wx.WXK_F8 : "wx.WXK_F8", |
| 64 | wx.WXK_F9 : "wx.WXK_F9", |
| 65 | wx.WXK_F10 : "wx.WXK_F10", |
| 66 | wx.WXK_F11 : "wx.WXK_F11", |
| 67 | wx.WXK_F12 : "wx.WXK_F12", |
| 68 | wx.WXK_F13 : "wx.WXK_F13", |
| 69 | wx.WXK_F14 : "wx.WXK_F14", |
| 70 | wx.WXK_F15 : "wx.WXK_F15", |
| 71 | wx.WXK_F16 : "wx.WXK_F16", |
| 72 | wx.WXK_F17 : "wx.WXK_F17", |
| 73 | wx.WXK_F18 : "wx.WXK_F18", |
| 74 | wx.WXK_F19 : "wx.WXK_F19", |
| 75 | wx.WXK_F20 : "wx.WXK_F20", |
| 76 | wx.WXK_F21 : "wx.WXK_F21", |
| 77 | wx.WXK_F22 : "wx.WXK_F22", |
| 78 | wx.WXK_F23 : "wx.WXK_F23", |
| 79 | wx.WXK_F24 : "wx.WXK_F24", |
| 80 | wx.WXK_NUMLOCK : "wx.WXK_NUMLOCK", |
| 81 | wx.WXK_SCROLL : "wx.WXK_SCROLL", |
| 82 | wx.WXK_PAGEUP : "wx.WXK_PAGEUP", |
| 83 | wx.WXK_PAGEDOWN : "wx.WXK_PAGEDOWN", |
| 84 | wx.WXK_NUMPAD_SPACE : "wx.WXK_NUMPAD_SPACE", |
| 85 | wx.WXK_NUMPAD_TAB : "wx.WXK_NUMPAD_TAB", |
| 86 | wx.WXK_NUMPAD_ENTER : "wx.WXK_NUMPAD_ENTER", |
| 87 | wx.WXK_NUMPAD_F1 : "wx.WXK_NUMPAD_F1", |
| 88 | wx.WXK_NUMPAD_F2 : "wx.WXK_NUMPAD_F2", |
| 89 | wx.WXK_NUMPAD_F3 : "wx.WXK_NUMPAD_F3", |
| 90 | wx.WXK_NUMPAD_F4 : "wx.WXK_NUMPAD_F4", |
| 91 | wx.WXK_NUMPAD_HOME : "wx.WXK_NUMPAD_HOME", |
| 92 | wx.WXK_NUMPAD_LEFT : "wx.WXK_NUMPAD_LEFT", |
| 93 | wx.WXK_NUMPAD_UP : "wx.WXK_NUMPAD_UP", |
| 94 | wx.WXK_NUMPAD_RIGHT : "wx.WXK_NUMPAD_RIGHT", |
| 95 | wx.WXK_NUMPAD_DOWN : "wx.WXK_NUMPAD_DOWN", |
| 96 | wx.WXK_NUMPAD_PRIOR : "wx.WXK_NUMPAD_PRIOR", |
| 97 | wx.WXK_NUMPAD_PAGEUP : "wx.WXK_NUMPAD_PAGEUP", |
| 98 | wx.WXK_NUMPAD_NEXT : "wx.WXK_NUMPAD_NEXT", |
| 99 | wx.WXK_NUMPAD_PAGEDOWN : "wx.WXK_NUMPAD_PAGEDOWN", |
| 100 | wx.WXK_NUMPAD_END : "wx.WXK_NUMPAD_END", |
| 101 | wx.WXK_NUMPAD_BEGIN : "wx.WXK_NUMPAD_BEGIN", |
| 102 | wx.WXK_NUMPAD_INSERT : "wx.WXK_NUMPAD_INSERT", |
| 103 | wx.WXK_NUMPAD_DELETE : "wx.WXK_NUMPAD_DELETE", |
| 104 | wx.WXK_NUMPAD_EQUAL : "wx.WXK_NUMPAD_EQUAL", |
| 105 | wx.WXK_NUMPAD_MULTIPLY : "wx.WXK_NUMPAD_MULTIPLY", |
| 106 | wx.WXK_NUMPAD_ADD : "wx.WXK_NUMPAD_ADD", |
| 107 | wx.WXK_NUMPAD_SEPARATOR : "wx.WXK_NUMPAD_SEPARATOR", |
| 108 | wx.WXK_NUMPAD_SUBTRACT : "wx.WXK_NUMPAD_SUBTRACT", |
| 109 | wx.WXK_NUMPAD_DECIMAL : "wx.WXK_NUMPAD_DECIMAL", |
| 110 | wx.WXK_NUMPAD_DIVIDE : "wx.WXK_NUMPAD_DIVIDE", |
| 111 | } |
| 112 | |
| 113 | |
| 114 | #---------------------------------------------------------------------- |
| 115 | |
| 116 | class KeySink(wx.Window): |
| 117 | def __init__(self, parent): |
| 118 | wx.Window.__init__(self, parent, -1, style=wx.WANTS_CHARS |
| 119 | #| wx.RAISED_BORDER |
| 120 | #| wx.SUNKEN_BORDER |
| 121 | ) |
| 122 | |
| 123 | self.SetBackgroundColour(wx.BLUE) |
| 124 | self.haveFocus = False |
| 125 | self.callSkip = False |
| 126 | self.logKeyDn = True |
| 127 | self.logKeyUp = True |
| 128 | self.logChar = True |
| 129 | |
| 130 | self.Bind(wx.EVT_PAINT, self.OnPaint) |
| 131 | self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) |
| 132 | self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) |
| 133 | self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) |
| 134 | |
| 135 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
| 136 | self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) |
| 137 | self.Bind(wx.EVT_CHAR, self.OnChar) |
| 138 | |
| 139 | |
| 140 | def SetCallSkip(self, skip): |
| 141 | self.callSkip = skip |
| 142 | |
| 143 | def SetLogKeyUp(self, val): |
| 144 | self.logKeyUp = val |
| 145 | |
| 146 | def SetLogKeyDn(self, val): |
| 147 | self.logKeyDn = val |
| 148 | |
| 149 | def SetLogChar(self, val): |
| 150 | self.logChar = val |
| 151 | |
| 152 | |
| 153 | def OnPaint(self, evt): |
| 154 | dc = wx.PaintDC(self) |
| 155 | rect = self.GetClientRect() |
| 156 | dc.SetTextForeground(wx.WHITE) |
| 157 | dc.DrawLabel("Click here and then press some keys", |
| 158 | rect, wx.ALIGN_CENTER | wx.ALIGN_TOP) |
| 159 | if self.haveFocus: |
| 160 | dc.SetTextForeground(wx.GREEN) |
| 161 | dc.DrawLabel("Have Focus", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) |
| 162 | else: |
| 163 | dc.SetTextForeground(wx.RED) |
| 164 | dc.DrawLabel("Need Focus!", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) |
| 165 | |
| 166 | |
| 167 | def OnSetFocus(self, evt): |
| 168 | self.haveFocus = True |
| 169 | self.Refresh() |
| 170 | |
| 171 | def OnKillFocus(self, evt): |
| 172 | self.haveFocus = False |
| 173 | self.Refresh() |
| 174 | |
| 175 | def OnMouse(self, evt): |
| 176 | if evt.ButtonDown(): |
| 177 | self.SetFocus() |
| 178 | |
| 179 | |
| 180 | def OnKeyDown(self, evt): |
| 181 | if self.logKeyDn: |
| 182 | self.GetParent().keylog.LogKeyEvent("KeyDown", evt) |
| 183 | if self.callSkip: |
| 184 | evt.Skip() |
| 185 | |
| 186 | def OnKeyUp(self, evt): |
| 187 | if self.logKeyUp: |
| 188 | self.GetParent().keylog.LogKeyEvent("KeyUp", evt) |
| 189 | if self.callSkip: |
| 190 | evt.Skip() |
| 191 | |
| 192 | def OnChar(self, evt): |
| 193 | if self.logChar: |
| 194 | self.GetParent().keylog.LogKeyEvent("Char", evt) |
| 195 | |
| 196 | |
| 197 | #---------------------------------------------------------------------- |
| 198 | |
| 199 | class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): |
| 200 | |
| 201 | def __init__(self, parent): |
| 202 | wx.ListCtrl.__init__(self, parent, -1, |
| 203 | style = wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES) |
| 204 | listmix.ListCtrlAutoWidthMixin.__init__(self) |
| 205 | |
| 206 | self.InsertColumn(0, "Event Type") |
| 207 | self.InsertColumn(1, "Key Name") |
| 208 | self.InsertColumn(2, "Key Code") |
| 209 | self.InsertColumn(3, "Modifiers") |
| 210 | self.InsertColumn(4, "Unicode") |
| 211 | self.InsertColumn(5, "RawKeyCode") |
| 212 | self.InsertColumn(6, "RawKeyFlags") |
| 213 | self.InsertColumn(7, "") |
| 214 | |
| 215 | for x in range(7): |
| 216 | self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER) |
| 217 | |
| 218 | self.SetColumnWidth(1, 125) |
| 219 | |
| 220 | |
| 221 | def LogKeyEvent(self, evType, evt): |
| 222 | keycode = evt.GetKeyCode() |
| 223 | keyname = keyMap.get(keycode, None) |
| 224 | if keyname is None: |
| 225 | if keycode < 256: |
| 226 | if keycode == 0: |
| 227 | keyname = "NUL" |
| 228 | elif keycode < 27: |
| 229 | keyname = "Ctrl-%s" % chr(ord('A') + keycode-1) |
| 230 | else: |
| 231 | keyname = "\"%s\"" % chr(keycode) |
| 232 | else: |
| 233 | keyname = "unknown (%s)" % keycode |
| 234 | |
| 235 | modifiers = "" |
| 236 | for mod, ch in [(evt.ControlDown(), 'C'), |
| 237 | (evt.AltDown(), 'A'), |
| 238 | (evt.ShiftDown(), 'S'), |
| 239 | (evt.MetaDown(), 'M')]: |
| 240 | if mod: |
| 241 | modifiers += ch |
| 242 | else: |
| 243 | modifiers += '-' |
| 244 | |
| 245 | id = self.InsertStringItem(self.GetItemCount(), evType) |
| 246 | self.SetStringItem(id, 1, keyname) |
| 247 | self.SetStringItem(id, 2, str(keycode)) |
| 248 | self.SetStringItem(id, 3, modifiers) |
| 249 | self.SetStringItem(id, 4, str(evt.GetUnicodeKey())) |
| 250 | self.SetStringItem(id, 5, str(evt.GetRawKeyCode())) |
| 251 | self.SetStringItem(id, 6, str(evt.GetRawKeyFlags())) |
| 252 | |
| 253 | #print ( id, evType, keyname, str(keycode), modifiers, str(evt.GetRawKeyCode()), str(evt.GetRawKeyFlags())) |
| 254 | |
| 255 | self.EnsureVisible(id) |
| 256 | |
| 257 | |
| 258 | def ClearLog(self): |
| 259 | self.DeleteAllItems() |
| 260 | |
| 261 | |
| 262 | #---------------------------------------------------------------------- |
| 263 | |
| 264 | |
| 265 | class TestPanel(wx.Panel): |
| 266 | def __init__(self, parent, log): |
| 267 | self.log = log |
| 268 | wx.Panel.__init__(self, parent, -1, style=0) |
| 269 | self.keysink = KeySink(self) |
| 270 | self.keysink.SetMinSize((100, 65)) |
| 271 | self.keylog = KeyLog(self) |
| 272 | |
| 273 | btn = wx.Button(self, -1, "Clear Log") |
| 274 | self.Bind(wx.EVT_BUTTON, self.OnClearBtn, btn) |
| 275 | |
| 276 | cb1 = wx.CheckBox(self, -1, "Call evt.Skip for Key Up/Dn events") |
| 277 | self.Bind(wx.EVT_CHECKBOX, self.OnSkipCB, cb1) |
| 278 | |
| 279 | cb2 = wx.CheckBox(self, -1, "EVT_KEY_UP") |
| 280 | self.Bind(wx.EVT_CHECKBOX, self.OnKeyUpCB, cb2) |
| 281 | cb2.SetValue(True) |
| 282 | |
| 283 | cb3 = wx.CheckBox(self, -1, "EVT_KEY_DOWN") |
| 284 | self.Bind(wx.EVT_CHECKBOX, self.OnKeyDnCB, cb3) |
| 285 | cb3.SetValue(True) |
| 286 | |
| 287 | cb4 = wx.CheckBox(self, -1, "EVT_CHAR") |
| 288 | self.Bind(wx.EVT_CHECKBOX, self.OnCharCB, cb4) |
| 289 | cb4.SetValue(True) |
| 290 | |
| 291 | buttons = wx.BoxSizer(wx.HORIZONTAL) |
| 292 | buttons.Add(btn, 0, wx.ALL, 4) |
| 293 | buttons.Add(cb1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 6) |
| 294 | buttons.Add(cb2, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) |
| 295 | buttons.Add(cb3, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) |
| 296 | buttons.Add(cb4, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) |
| 297 | |
| 298 | sizer = wx.BoxSizer(wx.VERTICAL) |
| 299 | sizer.Add(self.keysink, 0, wx.GROW) |
| 300 | sizer.Add(buttons) |
| 301 | sizer.Add(self.keylog, 1, wx.GROW) |
| 302 | |
| 303 | self.SetSizer(sizer) |
| 304 | |
| 305 | |
| 306 | def OnClearBtn(self, evt): |
| 307 | self.keylog.ClearLog() |
| 308 | |
| 309 | def OnSkipCB(self, evt): |
| 310 | self.keysink.SetCallSkip(evt.GetInt()) |
| 311 | |
| 312 | def OnKeyUpCB(self, evt): |
| 313 | self.keysink.SetLogKeyUp(evt.GetInt()) |
| 314 | |
| 315 | def OnKeyDnCB(self, evt): |
| 316 | self.keysink.SetLogKeyDn(evt.GetInt()) |
| 317 | |
| 318 | def OnCharCB(self, evt): |
| 319 | self.keysink.SetLogChar(evt.GetInt()) |
| 320 | |
| 321 | |
| 322 | #---------------------------------------------------------------------- |
| 323 | |
| 324 | def runTest(frame, nb, log): |
| 325 | win = TestPanel(nb, log) |
| 326 | return win |
| 327 | |
| 328 | #---------------------------------------------------------------------- |
| 329 | |
| 330 | |
| 331 | |
| 332 | overview = """<html><body> |
| 333 | <h2><center>wxKeyEvents</center></h2> |
| 334 | |
| 335 | This demo simply catches all key events and prints info about them. |
| 336 | It is meant to be used as a compatibility test for cross platform work. |
| 337 | |
| 338 | </body></html> |
| 339 | """ |
| 340 | |
| 341 | |
| 342 | |
| 343 | if __name__ == '__main__': |
| 344 | import sys,os |
| 345 | import run |
| 346 | run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) |
| 347 | |