]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/demo/KeyEvents.py
Let the text ctrl do the word wrapping, not the source code...
[wxWidgets.git] / wxPython / demo / KeyEvents.py
index 611c51f76e9dc6b8d06c49308129347f69f6cf2d..b0ef7589c31ba7e9cf86e9aee78028d69f9a5368 100644 (file)
@@ -5,109 +5,109 @@ import  wx.lib.mixins.listctrl  as  listmix
 #----------------------------------------------------------------------
 
 keyMap = {
 #----------------------------------------------------------------------
 
 keyMap = {
-    wx.WXK_BACK : "wx.WXK_BACK",
-    wx.WXK_TAB : "wx.WXK_TAB",
-    wx.WXK_RETURN : "wx.WXK_RETURN",
-    wx.WXK_ESCAPE : "wx.WXK_ESCAPE",
-    wx.WXK_SPACE : "wx.WXK_SPACE",
-    wx.WXK_DELETE : "wx.WXK_DELETE",
-    wx.WXK_START : "wx.WXK_START",
-    wx.WXK_LBUTTON : "wx.WXK_LBUTTON",
-    wx.WXK_RBUTTON : "wx.WXK_RBUTTON",
-    wx.WXK_CANCEL : "wx.WXK_CANCEL",
-    wx.WXK_MBUTTON : "wx.WXK_MBUTTON",
-    wx.WXK_CLEAR : "wx.WXK_CLEAR",
-    wx.WXK_SHIFT : "wx.WXK_SHIFT",
-    wx.WXK_ALT : "wx.WXK_ALT",
-    wx.WXK_CONTROL : "wx.WXK_CONTROL",
-    wx.WXK_MENU : "wx.WXK_MENU",
-    wx.WXK_PAUSE : "wx.WXK_PAUSE",
-    wx.WXK_CAPITAL : "wx.WXK_CAPITAL",
-    wx.WXK_PRIOR : "wx.WXK_PRIOR",
-    wx.WXK_NEXT : "wx.WXK_NEXT",
-    wx.WXK_END : "wx.WXK_END",
-    wx.WXK_HOME : "wx.WXK_HOME",
-    wx.WXK_LEFT : "wx.WXK_LEFT",
-    wx.WXK_UP : "wx.WXK_UP",
-    wx.WXK_RIGHT : "wx.WXK_RIGHT",
-    wx.WXK_DOWN : "wx.WXK_DOWN",
-    wx.WXK_SELECT : "wx.WXK_SELECT",
-    wx.WXK_PRINT : "wx.WXK_PRINT",
-    wx.WXK_EXECUTE : "wx.WXK_EXECUTE",
-    wx.WXK_SNAPSHOT : "wx.WXK_SNAPSHOT",
-    wx.WXK_INSERT : "wx.WXK_INSERT",
-    wx.WXK_HELP : "wx.WXK_HELP",
-    wx.WXK_NUMPAD0 : "wx.WXK_NUMPAD0",
-    wx.WXK_NUMPAD1 : "wx.WXK_NUMPAD1",
-    wx.WXK_NUMPAD2 : "wx.WXK_NUMPAD2",
-    wx.WXK_NUMPAD3 : "wx.WXK_NUMPAD3",
-    wx.WXK_NUMPAD4 : "wx.WXK_NUMPAD4",
-    wx.WXK_NUMPAD5 : "wx.WXK_NUMPAD5",
-    wx.WXK_NUMPAD6 : "wx.WXK_NUMPAD6",
-    wx.WXK_NUMPAD7 : "wx.WXK_NUMPAD7",
-    wx.WXK_NUMPAD8 : "wx.WXK_NUMPAD8",
-    wx.WXK_NUMPAD9 : "wx.WXK_NUMPAD9",
-    wx.WXK_MULTIPLY : "wx.WXK_MULTIPLY",
-    wx.WXK_ADD : "wx.WXK_ADD",
-    wx.WXK_SEPARATOR : "wx.WXK_SEPARATOR",
-    wx.WXK_SUBTRACT : "wx.WXK_SUBTRACT",
-    wx.WXK_DECIMAL : "wx.WXK_DECIMAL",
-    wx.WXK_DIVIDE : "wx.WXK_DIVIDE",
-    wx.WXK_F1 : "wx.WXK_F1",
-    wx.WXK_F2 : "wx.WXK_F2",
-    wx.WXK_F3 : "wx.WXK_F3",
-    wx.WXK_F4 : "wx.WXK_F4",
-    wx.WXK_F5 : "wx.WXK_F5",
-    wx.WXK_F6 : "wx.WXK_F6",
-    wx.WXK_F7 : "wx.WXK_F7",
-    wx.WXK_F8 : "wx.WXK_F8",
-    wx.WXK_F9 : "wx.WXK_F9",
-    wx.WXK_F10 : "wx.WXK_F10",
-    wx.WXK_F11 : "wx.WXK_F11",
-    wx.WXK_F12 : "wx.WXK_F12",
-    wx.WXK_F13 : "wx.WXK_F13",
-    wx.WXK_F14 : "wx.WXK_F14",
-    wx.WXK_F15 : "wx.WXK_F15",
-    wx.WXK_F16 : "wx.WXK_F16",
-    wx.WXK_F17 : "wx.WXK_F17",
-    wx.WXK_F18 : "wx.WXK_F18",
-    wx.WXK_F19 : "wx.WXK_F19",
-    wx.WXK_F20 : "wx.WXK_F20",
-    wx.WXK_F21 : "wx.WXK_F21",
-    wx.WXK_F22 : "wx.WXK_F22",
-    wx.WXK_F23 : "wx.WXK_F23",
-    wx.WXK_F24 : "wx.WXK_F24",
-    wx.WXK_NUMLOCK : "wx.WXK_NUMLOCK",
-    wx.WXK_SCROLL : "wx.WXK_SCROLL",
-    wx.WXK_PAGEUP : "wx.WXK_PAGEUP",
-    wx.WXK_PAGEDOWN : "wx.WXK_PAGEDOWN",
-    wx.WXK_NUMPAD_SPACE : "wx.WXK_NUMPAD_SPACE",
-    wx.WXK_NUMPAD_TAB : "wx.WXK_NUMPAD_TAB",
-    wx.WXK_NUMPAD_ENTER : "wx.WXK_NUMPAD_ENTER",
-    wx.WXK_NUMPAD_F1 : "wx.WXK_NUMPAD_F1",
-    wx.WXK_NUMPAD_F2 : "wx.WXK_NUMPAD_F2",
-    wx.WXK_NUMPAD_F3 : "wx.WXK_NUMPAD_F3",
-    wx.WXK_NUMPAD_F4 : "wx.WXK_NUMPAD_F4",
-    wx.WXK_NUMPAD_HOME : "wx.WXK_NUMPAD_HOME",
-    wx.WXK_NUMPAD_LEFT : "wx.WXK_NUMPAD_LEFT",
-    wx.WXK_NUMPAD_UP : "wx.WXK_NUMPAD_UP",
-    wx.WXK_NUMPAD_RIGHT : "wx.WXK_NUMPAD_RIGHT",
-    wx.WXK_NUMPAD_DOWN : "wx.WXK_NUMPAD_DOWN",
-    wx.WXK_NUMPAD_PRIOR : "wx.WXK_NUMPAD_PRIOR",
-    wx.WXK_NUMPAD_PAGEUP : "wx.WXK_NUMPAD_PAGEUP",
-    wx.WXK_NUMPAD_NEXT : "wx.WXK_NUMPAD_NEXT",
-    wx.WXK_NUMPAD_PAGEDOWN : "wx.WXK_NUMPAD_PAGEDOWN",
-    wx.WXK_NUMPAD_END : "wx.WXK_NUMPAD_END",
-    wx.WXK_NUMPAD_BEGIN : "wx.WXK_NUMPAD_BEGIN",
-    wx.WXK_NUMPAD_INSERT : "wx.WXK_NUMPAD_INSERT",
-    wx.WXK_NUMPAD_DELETE : "wx.WXK_NUMPAD_DELETE",
-    wx.WXK_NUMPAD_EQUAL : "wx.WXK_NUMPAD_EQUAL",
-    wx.WXK_NUMPAD_MULTIPLY : "wx.WXK_NUMPAD_MULTIPLY",
-    wx.WXK_NUMPAD_ADD : "wx.WXK_NUMPAD_ADD",
-    wx.WXK_NUMPAD_SEPARATOR : "wx.WXK_NUMPAD_SEPARATOR",
-    wx.WXK_NUMPAD_SUBTRACT : "wx.WXK_NUMPAD_SUBTRACT",
-    wx.WXK_NUMPAD_DECIMAL : "wx.WXK_NUMPAD_DECIMAL",
-    wx.WXK_NUMPAD_DIVIDE : "wx.WXK_NUMPAD_DIVIDE",
+    wx.WXK_BACK : "WXK_BACK",
+    wx.WXK_TAB : "WXK_TAB",
+    wx.WXK_RETURN : "WXK_RETURN",
+    wx.WXK_ESCAPE : "WXK_ESCAPE",
+    wx.WXK_SPACE : "WXK_SPACE",
+    wx.WXK_DELETE : "WXK_DELETE",
+    wx.WXK_START : "WXK_START",
+    wx.WXK_LBUTTON : "WXK_LBUTTON",
+    wx.WXK_RBUTTON : "WXK_RBUTTON",
+    wx.WXK_CANCEL : "WXK_CANCEL",
+    wx.WXK_MBUTTON : "WXK_MBUTTON",
+    wx.WXK_CLEAR : "WXK_CLEAR",
+    wx.WXK_SHIFT : "WXK_SHIFT",
+    wx.WXK_ALT : "WXK_ALT",
+    wx.WXK_CONTROL : "WXK_CONTROL",
+    wx.WXK_MENU : "WXK_MENU",
+    wx.WXK_PAUSE : "WXK_PAUSE",
+    wx.WXK_CAPITAL : "WXK_CAPITAL",
+    #wx.WXK_PRIOR : "WXK_PRIOR",
+    #wx.WXK_NEXT : "WXK_NEXT",
+    wx.WXK_END : "WXK_END",
+    wx.WXK_HOME : "WXK_HOME",
+    wx.WXK_LEFT : "WXK_LEFT",
+    wx.WXK_UP : "WXK_UP",
+    wx.WXK_RIGHT : "WXK_RIGHT",
+    wx.WXK_DOWN : "WXK_DOWN",
+    wx.WXK_SELECT : "WXK_SELECT",
+    wx.WXK_PRINT : "WXK_PRINT",
+    wx.WXK_EXECUTE : "WXK_EXECUTE",
+    wx.WXK_SNAPSHOT : "WXK_SNAPSHOT",
+    wx.WXK_INSERT : "WXK_INSERT",
+    wx.WXK_HELP : "WXK_HELP",
+    wx.WXK_NUMPAD0 : "WXK_NUMPAD0",
+    wx.WXK_NUMPAD1 : "WXK_NUMPAD1",
+    wx.WXK_NUMPAD2 : "WXK_NUMPAD2",
+    wx.WXK_NUMPAD3 : "WXK_NUMPAD3",
+    wx.WXK_NUMPAD4 : "WXK_NUMPAD4",
+    wx.WXK_NUMPAD5 : "WXK_NUMPAD5",
+    wx.WXK_NUMPAD6 : "WXK_NUMPAD6",
+    wx.WXK_NUMPAD7 : "WXK_NUMPAD7",
+    wx.WXK_NUMPAD8 : "WXK_NUMPAD8",
+    wx.WXK_NUMPAD9 : "WXK_NUMPAD9",
+    wx.WXK_MULTIPLY : "WXK_MULTIPLY",
+    wx.WXK_ADD : "WXK_ADD",
+    wx.WXK_SEPARATOR : "WXK_SEPARATOR",
+    wx.WXK_SUBTRACT : "WXK_SUBTRACT",
+    wx.WXK_DECIMAL : "WXK_DECIMAL",
+    wx.WXK_DIVIDE : "WXK_DIVIDE",
+    wx.WXK_F1 : "WXK_F1",
+    wx.WXK_F2 : "WXK_F2",
+    wx.WXK_F3 : "WXK_F3",
+    wx.WXK_F4 : "WXK_F4",
+    wx.WXK_F5 : "WXK_F5",
+    wx.WXK_F6 : "WXK_F6",
+    wx.WXK_F7 : "WXK_F7",
+    wx.WXK_F8 : "WXK_F8",
+    wx.WXK_F9 : "WXK_F9",
+    wx.WXK_F10 : "WXK_F10",
+    wx.WXK_F11 : "WXK_F11",
+    wx.WXK_F12 : "WXK_F12",
+    wx.WXK_F13 : "WXK_F13",
+    wx.WXK_F14 : "WXK_F14",
+    wx.WXK_F15 : "WXK_F15",
+    wx.WXK_F16 : "WXK_F16",
+    wx.WXK_F17 : "WXK_F17",
+    wx.WXK_F18 : "WXK_F18",
+    wx.WXK_F19 : "WXK_F19",
+    wx.WXK_F20 : "WXK_F20",
+    wx.WXK_F21 : "WXK_F21",
+    wx.WXK_F22 : "WXK_F22",
+    wx.WXK_F23 : "WXK_F23",
+    wx.WXK_F24 : "WXK_F24",
+    wx.WXK_NUMLOCK : "WXK_NUMLOCK",
+    wx.WXK_SCROLL : "WXK_SCROLL",
+    wx.WXK_PAGEUP : "WXK_PAGEUP",
+    wx.WXK_PAGEDOWN : "WXK_PAGEDOWN",
+    wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE",
+    wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB",
+    wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER",
+    wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1",
+    wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2",
+    wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3",
+    wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4",
+    wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME",
+    wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT",
+    wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP",
+    wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT",
+    wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN",
+    #wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR",
+    wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP",
+    #wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT",
+    wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN",
+    wx.WXK_NUMPAD_END : "WXK_NUMPAD_END",
+    wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN",
+    wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT",
+    wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE",
+    wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL",
+    wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY",
+    wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD",
+    wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR",
+    wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT",
+    wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL",
+    wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE",
 }
 
 
 }
 
 
@@ -118,11 +118,11 @@ class KeySink(wx.Window):
         wx.Window.__init__(self, parent, -1, style=wx.WANTS_CHARS
                           #| wx.RAISED_BORDER
                           #| wx.SUNKEN_BORDER
         wx.Window.__init__(self, parent, -1, style=wx.WANTS_CHARS
                           #| wx.RAISED_BORDER
                           #| wx.SUNKEN_BORDER
-                          )
+                           , name="sink")
 
         self.SetBackgroundColour(wx.BLUE)
         self.haveFocus = False
 
         self.SetBackgroundColour(wx.BLUE)
         self.haveFocus = False
-        self.callSkip = False
+        self.callSkip = True
         self.logKeyDn = True
         self.logKeyUp = True
         self.logChar = True
         self.logKeyDn = True
         self.logKeyUp = True
         self.logChar = True
@@ -197,21 +197,26 @@ class KeySink(wx.Window):
 #----------------------------------------------------------------------
 
 class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
 #----------------------------------------------------------------------
 
 class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
+    colHeaders = [ "Event Type",
+                   "Key Name", 
+                   "Key Code",   
+                   "Modifiers",
+                   "Unicode",    
+                   "RawKeyCode",
+                   "RawKeyFlags",
+                   ]     
 
     def __init__(self, parent):
         wx.ListCtrl.__init__(self, parent, -1,
                             style = wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES)
         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
 
     def __init__(self, parent):
         wx.ListCtrl.__init__(self, parent, -1,
                             style = wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES)
         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
-        self.InsertColumn(0, "Event Type")
-        self.InsertColumn(1, "Key Name")
-        self.InsertColumn(2, "Key Code")
-        self.InsertColumn(3, "Modifiers")
-        self.InsertColumn(4, "RawKeyCode")
-        self.InsertColumn(5, "RawKeyFlags")
-        self.InsertColumn(6, "")
+        for idx, header in enumerate(self.colHeaders):
+            self.InsertColumn(idx, header)
+        idx += 1
+        self.InsertColumn(idx, "")
 
 
-        for x in range(6):
+        for x in range(idx):
             self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER)
 
         self.SetColumnWidth(1, 125)
             self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER)
 
         self.SetColumnWidth(1, 125)
@@ -221,7 +226,15 @@ class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
         keycode = evt.GetKeyCode()
         keyname = keyMap.get(keycode, None)
         if keyname is None:
         keycode = evt.GetKeyCode()
         keyname = keyMap.get(keycode, None)
         if keyname is None:
-            if keycode < 256:
+            if "unicode" in wx.PlatformInfo:
+                keycode = evt.GetUnicodeKey()
+                if keycode <= 127:
+                    keycode = evt.GetKeyCode()
+                keyname = "\"" + unichr(evt.GetUnicodeKey()) + "\""
+                if keycode < 27:
+                    keyname = "Ctrl-%s" % chr(ord('A') + keycode-1)
+                
+            elif keycode < 256:
                 if keycode == 0:
                     keyname = "NUL"
                 elif keycode < 27:
                 if keycode == 0:
                     keyname = "NUL"
                 elif keycode < 27:
@@ -245,8 +258,9 @@ class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
         self.SetStringItem(id, 1, keyname)
         self.SetStringItem(id, 2, str(keycode))
         self.SetStringItem(id, 3, modifiers)
         self.SetStringItem(id, 1, keyname)
         self.SetStringItem(id, 2, str(keycode))
         self.SetStringItem(id, 3, modifiers)
-        self.SetStringItem(id, 4, str(evt.GetRawKeyCode()))
-        self.SetStringItem(id, 5, str(evt.GetRawKeyFlags()))
+        self.SetStringItem(id, 4, str(evt.GetUnicodeKey()))
+        self.SetStringItem(id, 5, str(evt.GetRawKeyCode()))
+        self.SetStringItem(id, 6, str(evt.GetRawKeyFlags()))
 
         #print ( id, evType, keyname, str(keycode), modifiers, str(evt.GetRawKeyCode()), str(evt.GetRawKeyFlags()))
 
 
         #print ( id, evType, keyname, str(keycode), modifiers, str(evt.GetRawKeyCode()), str(evt.GetRawKeyFlags()))
 
@@ -256,6 +270,32 @@ class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
     def ClearLog(self):
         self.DeleteAllItems()
 
     def ClearLog(self):
         self.DeleteAllItems()
 
+    def CopyLog(self):
+        # build a newline and tab delimited string to put into the clipboard
+        if "unicode" in wx.PlatformInfo:
+            st = u""
+        else:
+            st = ""
+        for h in self.colHeaders:
+            st += h + "\t"
+        st += "\n"
+
+        for idx in range(self.GetItemCount()):
+            for col in range(self.GetColumnCount()):
+                item = self.GetItem(idx, col)
+                st += item.GetText() + "\t"
+            st += "\n"
+
+        data = wx.TextDataObject()
+        data.SetText(st)
+        if wx.TheClipboard.Open():
+            wx.TheClipboard.SetData(data)
+            wx.TheClipboard.Close()
+        else:
+            wx.MessageBox("Unable to open the clipboard", "Error")
+       
+        
+
 
 #----------------------------------------------------------------------
 
 
 #----------------------------------------------------------------------
 
@@ -268,26 +308,35 @@ class TestPanel(wx.Panel):
         self.keysink.SetMinSize((100, 65))
         self.keylog = KeyLog(self)
 
         self.keysink.SetMinSize((100, 65))
         self.keylog = KeyLog(self)
 
-        btn = wx.Button(self, -1, "Clear Log")
+        btn = wx.Button(self, -1, "Clear", style=wx.BU_EXACTFIT)
         self.Bind(wx.EVT_BUTTON, self.OnClearBtn, btn)
         self.Bind(wx.EVT_BUTTON, self.OnClearBtn, btn)
+        btn.SetToolTipString(
+            "Clear the items from the log window")
+
+        btn2 = wx.Button(self, -1, "Copy", style=wx.BU_EXACTFIT)
+        self.Bind(wx.EVT_BUTTON, self.OnCopyBtn, btn2)
+        btn2.SetToolTipString(
+            "Copy the contents of the log window to the clipboard")
 
 
-        cb1 = wx.CheckBox(self, -1, "Call evt.Skip for Key Up/Dn events")
+        cb1 = wx.CheckBox(self, -1, "Call evt.Skip in Key* events")
         self.Bind(wx.EVT_CHECKBOX, self.OnSkipCB, cb1)
         self.Bind(wx.EVT_CHECKBOX, self.OnSkipCB, cb1)
+        cb1.SetValue(True)
 
 
-        cb2 = wx.CheckBox(self, -1, "EVT_KEY_UP")
+        cb2 = wx.CheckBox(self, -1, "KEY_UP")
         self.Bind(wx.EVT_CHECKBOX, self.OnKeyUpCB, cb2)
         cb2.SetValue(True)
 
         self.Bind(wx.EVT_CHECKBOX, self.OnKeyUpCB, cb2)
         cb2.SetValue(True)
 
-        cb3 = wx.CheckBox(self, -1, "EVT_KEY_DOWN")
+        cb3 = wx.CheckBox(self, -1, "KEY_DOWN")
         self.Bind(wx.EVT_CHECKBOX, self.OnKeyDnCB, cb3)
         cb3.SetValue(True)
 
         self.Bind(wx.EVT_CHECKBOX, self.OnKeyDnCB, cb3)
         cb3.SetValue(True)
 
-        cb4 = wx.CheckBox(self, -1, "EVT_CHAR")
+        cb4 = wx.CheckBox(self, -1, "CHAR")
         self.Bind(wx.EVT_CHECKBOX, self.OnCharCB, cb4)
         cb4.SetValue(True)
 
         buttons = wx.BoxSizer(wx.HORIZONTAL)
         buttons.Add(btn, 0, wx.ALL, 4)
         self.Bind(wx.EVT_CHECKBOX, self.OnCharCB, cb4)
         cb4.SetValue(True)
 
         buttons = wx.BoxSizer(wx.HORIZONTAL)
         buttons.Add(btn, 0, wx.ALL, 4)
+        buttons.Add(btn2, 0, wx.ALL, 4)
         buttons.Add(cb1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 6)
         buttons.Add(cb2, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6)
         buttons.Add(cb3, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6)
         buttons.Add(cb1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 6)
         buttons.Add(cb2, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6)
         buttons.Add(cb3, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6)
@@ -304,6 +353,9 @@ class TestPanel(wx.Panel):
     def OnClearBtn(self, evt):
         self.keylog.ClearLog()
 
     def OnClearBtn(self, evt):
         self.keylog.ClearLog()
 
+    def OnCopyBtn(self, evt):
+        self.keylog.CopyLog()
+
     def OnSkipCB(self, evt):
         self.keysink.SetCallSkip(evt.GetInt())
 
     def OnSkipCB(self, evt):
         self.keysink.SetCallSkip(evt.GetInt())