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