diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj
index 27c14d534f9fbc13db2f0e84d8dad0a8c0e89d84..e5d651dda01de65816d2eec00c35d84090c6ecca 100644
--- a/mac/Audacity.xcodeproj/project.pbxproj
+++ b/mac/Audacity.xcodeproj/project.pbxproj
@@ -1664,7 +1664,7 @@
 		1707407A0988F1BB008541CC /* libsoundtouch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsoundtouch.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		170740960988F2F7008541CC /* libportmixer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libportmixer.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		170740D40988F820008541CC /* libvorbis.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libvorbis.a; sourceTree = BUILT_PRODUCTS_DIR; };
-		174D9026098C78AF00D5909F /* CommandManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = CommandManager.cpp; sourceTree = "<group>"; tabWidth = 3; };
+		174D9026098C78AF00D5909F /* CommandManager.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 30; indentWidth = 3; path = CommandManager.cpp; sourceTree = "<group>"; tabWidth = 3; };
 		174D9027098C78AF00D5909F /* CommandManager.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = CommandManager.h; sourceTree = "<group>"; tabWidth = 3; };
 		174D902A098C78AF00D5909F /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; tabWidth = 3; };
 		174D902B098C78AF00D5909F /* Keyboard.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = Keyboard.h; sourceTree = "<group>"; tabWidth = 3; };
diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp
index b949fb7c55fa1ee7add1999fc150777b8df35ca3..d4b3ebc1d145f436cba72863d07d7e84634b89d8 100644
--- a/src/AudacityApp.cpp
+++ b/src/AudacityApp.cpp
@@ -231,9 +231,6 @@ It handles initialization and termination by subclassing wxApp.
 ////////////////////////////////////////////////////////////
 
 DEFINE_EVENT_TYPE(EVT_OPEN_AUDIO_FILE);
-DEFINE_EVENT_TYPE(EVT_CAPTURE_KEYBOARD);
-DEFINE_EVENT_TYPE(EVT_RELEASE_KEYBOARD);
-DEFINE_EVENT_TYPE(EVT_CAPTURE_KEY);
 
 #ifdef __WXGTK__
 static void wxOnAssert(const wxChar *fileName, int lineNumber, const wxChar *msg)
@@ -1099,16 +1096,16 @@ void AudacityApp::GenerateCrashReport(wxDebugReport::Context ctx)
 }
 #endif
 
-#if defined(__WXGTK__)
-// On wxGTK, there's a focus issue where dialogs do not automatically pass focus
-// to the first child.  This means that you can use the keyboard to navigate within
-// the dialog.  Watching for the ACTIVATE event allows us to set the focus ourselves
-// when each dialog opens.
-//
-// See bug #57
-//
 int AudacityApp::FilterEvent(wxEvent & event)
 {
+#if !wxCHECK_VERSION(3, 0, 0) && defined(__WXGTK__)
+   // On wxGTK, there's a focus issue where dialogs do not automatically pass focus
+   // to the first child.  This means that you can use the keyboard to navigate within
+   // the dialog.  Watching for the ACTIVATE event allows us to set the focus ourselves
+   // when each dialog opens.
+   //
+   // See bug #57
+   //
    if (event.GetEventType() == wxEVT_ACTIVATE)
    {
       wxActivateEvent & e = (wxActivateEvent &) event;
@@ -1118,10 +1115,11 @@ int AudacityApp::FilterEvent(wxEvent & event)
          ((wxWindow *)e.GetEventObject())->SetFocus();
       }
    }
+   break;
+#endif
 
-   return -1;
+   return Event_Skip;
 }
-#endif
 
 AudacityApp::AudacityApp()
 {
@@ -1152,11 +1150,6 @@ bool AudacityApp::OnInit()
    mChecker = NULL;
    mIPCServ = NULL;
 
-#if defined(__WXGTK__)
-   // Workaround for bug 154 -- initialize to false
-   inKbdHandler = false;
-#endif
-
 #if defined(__WXMAC__)
    // Disable window animation
    wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
diff --git a/src/AudacityApp.h b/src/AudacityApp.h
index 6a7e338bb9ec4001a3fd88a8992fea78d99328ec..3f65f3d8275188ae01c30d9bc7e17837bd947f6e 100644
--- a/src/AudacityApp.h
+++ b/src/AudacityApp.h
@@ -51,11 +51,6 @@ extern bool gIsQuitting;
 // Asynchronous open
 DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_OPEN_AUDIO_FILE, -1);
 
-// Keyboard capture support
-DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_CAPTURE_KEYBOARD, -1);
-DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_RELEASE_KEYBOARD, -1);
-DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_CAPTURE_KEY, -1);
-
 // Flags used in command handling.
 
 // These flags represent the majority of the states that affect
@@ -108,9 +103,7 @@ class AudacityApp:public wxApp {
    virtual int OnExit(void);
    virtual void OnFatalException();
 
-#if defined(__WXGTK__)
    int FilterEvent(wxEvent & event);
-#endif
 
    void InitLang( const wxString & lang );
 
@@ -207,12 +200,6 @@ class AudacityApp:public wxApp {
    void GenerateCrashReport(wxDebugReport::Context ctx);
 #endif
 
-#if defined(__WXGTK__)
-   /** \brief This flag is set true when in a keyboard event handler.
-    * Used to work around a hang issue with ibus (bug 154) */
-   bool inKbdHandler;
-#endif
-
  private:
    CommandHandler *mCmdHandler;
    FileHistory *mRecentFiles;
diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp
index b5fd452a46339e177ca2eba72052588059dea638..560490632540fbe42230b1b4b2bca8b45316b461 100644
--- a/src/LabelTrack.cpp
+++ b/src/LabelTrack.cpp
@@ -1085,20 +1085,7 @@ bool LabelTrack::PasteSelectedText(double sel0, double sel1)
 /// @return true if the text data is available in the clipboard, false otherwise
 bool LabelTrack::IsTextClipSupported()
 {
-#if defined(__WXGTK__)
-   // AWD: work-around for bug 154: do not call wxClipboard::IsSupported()
-   // when handling a keyboard event
-   if (!wxGetApp().inKbdHandler) {
-#endif
-
-      return wxTheClipboard->IsSupported(wxDF_TEXT);
-
-#if defined (__WXGTK__)
-   }
-
-   // In keyboard handler; return false for now
-   return false;
-#endif
+   return wxTheClipboard->IsSupported(wxDF_TEXT);
 }
 
 
@@ -1607,18 +1594,22 @@ bool LabelTrack::CaptureKey(wxKeyEvent & event)
 {
    // Cache the keycode
    int keyCode = event.GetKeyCode();
+
    // Check for modifiers -- this does what wxKeyEvent::HasModifiers() should
    // do (it checks Control instead of CMD on Mac)
    bool hasMods = ((event.GetModifiers() & (wxMOD_CMD | wxMOD_ALT)) != 0);
+   if (hasMods) {
+      return false;
+   }
 
    if (mSelIndex >= 0) {
-      if (IsGoodLabelEditKey(keyCode) && !hasMods) {
+      if (IsGoodLabelEditKey(keyCode)) {
          return true;
       }
    }
    else
    {
-      if( IsGoodLabelFirstKey(keyCode) && !hasMods)
+      if (IsGoodLabelFirstKey(keyCode))
       {
          AudacityProject * pProj = GetActiveProject();
 
@@ -1631,14 +1622,16 @@ bool LabelTrack::CaptureKey(wxKeyEvent & event)
             double t0, t1;
             pProj->GetPlayRegion(&t0, &t1);
             if (pProj->mViewInfo.selectedRegion.t0() == t0 &&
-                pProj->mViewInfo.selectedRegion.t1() == t1)
+                pProj->mViewInfo.selectedRegion.t1() == t1) {
                return false;
+            }
          }
 
          // If there's a label there already don't capture
          if( GetLabelIndex(pProj->mViewInfo.selectedRegion.t0(),
-                           pProj->mViewInfo.selectedRegion.t1()) != wxNOT_FOUND )
+                           pProj->mViewInfo.selectedRegion.t1()) != wxNOT_FOUND ) {
             return false;
+         }
 
          return true;
       }
@@ -1830,7 +1823,9 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
          break;
 
       default:
-         event.Skip();
+         if (!IsGoodLabelEditKey(keyCode)) {
+            event.Skip();
+         }
          break;
       }
    }
@@ -1872,7 +1867,9 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
          break;
 
       default:
-         event.Skip();
+         if (!IsGoodLabelFirstKey(keyCode)) {
+            event.Skip();
+         }
          break;
       }
    }
@@ -2699,7 +2696,10 @@ bool LabelTrack::IsGoodLabelFirstKey(int keyCode)
                   && keyCode != WXK_SPACE && keyCode != WXK_DELETE && keyCode != WXK_RETURN) ||
           (keyCode >= WXK_NUMPAD0 && keyCode <= WXK_DIVIDE) ||
           (keyCode >= WXK_NUMPAD_EQUAL && keyCode <= WXK_NUMPAD_DIVIDE) ||
-          (keyCode > WXK_COMMAND);
+#if defined(__WXMAC__)
+          (keyCode > WXK_RAW_CONTROL) ||
+#endif
+          (keyCode > WXK_WINDOWS_MENU);
 }
 
 /// This returns true for keys we capture for label editing.
@@ -2715,7 +2715,10 @@ bool LabelTrack::IsGoodLabelEditKey(int keyCode)
           (keyCode >= WXK_NUMPAD_SPACE && keyCode <= WXK_NUMPAD_ENTER) ||
           (keyCode >= WXK_NUMPAD_HOME && keyCode <= WXK_NUMPAD_END) ||
           (keyCode >= WXK_NUMPAD_DELETE && keyCode <= WXK_NUMPAD_DIVIDE) ||
-          keyCode > WXK_COMMAND;
+#if defined(__WXMAC__)
+          (keyCode > WXK_RAW_CONTROL) ||
+#endif
+          (keyCode > WXK_WINDOWS_MENU);
 }
 
 /// Sorts the labels in order of their starting times.
diff --git a/src/Menus.cpp b/src/Menus.cpp
index 75eb5256a5c97dc883c43e2c6229e2b2b05c21fa..3e2bc18f62a8d3c55b1dcb01bd1c927e4b8e1b22 100644
--- a/src/Menus.cpp
+++ b/src/Menus.cpp
@@ -771,16 +771,6 @@ void AudacityProject::CreateMenusAndCommands()
 
    c->EndSubMenu();
 
-   /////////////////////////////////////////////////////////////////////////////
-
-   /* i18n-hint: Usually keep the ! at the start.  It means this option is hidden.
-    * Simplified View toggles the showing and hiding of 'hidden' menu items that start
-    * with !.  If your translation file is for a special use, that is if it is for a
-    * simplified view with hidden menu items, then leave the ! out here, so that the
-    * user can show/hide some of the menu items. */
-   c->AddCheck(wxT("SimplifiedView"), _("!Simplified View"), FN(OnSimplifiedView),
-               mCommandManager.mbHideFlaggedItems ? 1 : 0, AlwaysEnabledFlag, AlwaysEnabledFlag);
-
    c->EndMenu();
 
    /////////////////////////////////////////////////////////////////////////////
@@ -1590,34 +1580,10 @@ void AudacityProject::ModifyUndoMenuItems()
       mCommandManager.Modify(wxT("Undo"),
                              wxString::Format(_("&Undo %s"),
                                               desc.c_str()));
-      // LL:  Hackage Alert!!!
-      //
-      // On the Mac, all menu state changes are ignored if a modal
-      // dialog is displayed.
-      //
-      // An example of this is when applying chains where the "Undo"
-      // menu state should change when each command executes.  But,
-      // since the state changes are ignored, the "Undo" menu item
-      // will never get enabled.  And unfortunately, this will cause
-      // the menu item to be permanently disabled since the recorded
-      // state is enabled (even though it isn't) causing the routines
-      // to ignore the new enable request.
-      //
-      // So, the workaround is to transition the item back to disabled
-      // and then to enabled.  (Sorry, I couldn't find a better way of
-      // doing it.)
-      //
-      // See src/mac/carbon/menuitem.cpp, wxMenuItem::Enable() for more
-      // info.
-      mCommandManager.Enable(wxT("Undo"), false);
-      mCommandManager.Enable(wxT("Undo"), true);
    }
    else {
       mCommandManager.Modify(wxT("Undo"),
                              wxString::Format(_("&Undo")));
-      // LL: See above
-      mCommandManager.Enable(wxT("Undo"), true);
-      mCommandManager.Enable(wxT("Undo"), false);
    }
 
    if (mUndoManager.RedoAvailable()) {
@@ -5278,14 +5244,6 @@ void AudacityProject::OnResetToolBars()
    ModifyToolbarMenus();
 }
 
-void AudacityProject::OnSimplifiedView()
-{
-   mCommandManager.mbHideFlaggedItems = !mCommandManager.mbHideFlaggedItems;
-   mCommandManager.Check(wxT("SimplifiedView"), mCommandManager.mbHideFlaggedItems );
-   RebuildMenuBar();
-}
-
-
 //
 // Project Menu
 //
@@ -6285,10 +6243,6 @@ void AudacityProject::OnApplyChain()
 {
    BatchProcessDialog dlg(this);
    dlg.ShowModal();
-
-   // LL:  See comments in ModifyUndoMenuItems() for info about this...
-   //
-   // Refresh the Undo menu.
    ModifyUndoMenuItems();
 }
 
diff --git a/src/Menus.h b/src/Menus.h
index 2b5fe80e0e58b771568741b14de5c6ec3b3f6cb5..ee08d157f32f514728b0ed779ad075e39bc09071 100644
--- a/src/Menus.h
+++ b/src/Menus.h
@@ -298,7 +298,6 @@ void OnShowSpectralSelectionToolBar();
 void OnShowToolsToolBar();
 void OnShowTranscriptionToolBar();
 void OnResetToolBars();
-void OnSimplifiedView();
 
         // Transport Menu
 
diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp
index 25c4e8a0993e26c2651dbbc24552c7bd739cda3c..c6813ea21d1ee082ade6616e29e78cf8a9478706 100644
--- a/src/MixerBoard.cpp
+++ b/src/MixerBoard.cpp
@@ -82,13 +82,12 @@ void MixerTrackSlider::OnMouseEvent(wxMouseEvent &event)
 
 void MixerTrackSlider::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 
diff --git a/src/Project.cpp b/src/Project.cpp
index 9183ec52e4bb6e2fbd26977deb7bf593b7a5a351..3802101139e3d216abbaeb631ca56cb235117f80 100644
--- a/src/Project.cpp
+++ b/src/Project.cpp
@@ -187,6 +187,11 @@ const int sbarHjump = 30;       //STM: This is how far the thumb jumps when the
 #include "AllThemeResources.h"
 #endif
 
+////////////////////////////////////////////////////////////
+/// Custom events
+////////////////////////////////////////////////////////////
+DEFINE_EVENT_TYPE(EVT_CAPTURE_KEY);
+
 //
 // This small template class resembles a try-finally block
 //
@@ -707,8 +712,6 @@ enum {
 
 
 BEGIN_EVENT_TABLE(AudacityProject, wxFrame)
-   EVT_MENU_OPEN(AudacityProject::OnMenuEvent)
-   EVT_MENU_CLOSE(AudacityProject::OnMenuEvent)
    EVT_MENU(wxID_ANY, AudacityProject::OnMenu)
    EVT_MOUSE_EVENTS(AudacityProject::OnMouseEvent)
    EVT_CLOSE(AudacityProject::OnCloseWindow)
@@ -725,8 +728,6 @@ BEGIN_EVENT_TABLE(AudacityProject, wxFrame)
    EVT_ICONIZE(AudacityProject::OnIconize)
    EVT_COMMAND(wxID_ANY, EVT_OPEN_AUDIO_FILE, AudacityProject::OnOpenAudioFile)
    EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, AudacityProject::OnToolBarUpdate)
-   EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEYBOARD, AudacityProject::OnCaptureKeyboard)
-   EVT_COMMAND(wxID_ANY, EVT_RELEASE_KEYBOARD, AudacityProject::OnReleaseKeyboard)
    //mchinen:multithreaded calls - may not be threadsafe with CommandEvent: may have to change.
    EVT_COMMAND(wxID_ANY, EVT_ODTASK_UPDATE, AudacityProject::OnODTaskUpdate)
    EVT_COMMAND(wxID_ANY, EVT_ODTASK_COMPLETE, AudacityProject::OnODTaskComplete)
@@ -768,7 +769,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
      mShowId3Dialog(true),               //lda
      mScrollBeyondZero(false),
      mLastFocusedWindow(NULL),
-     mKeyboardCaptured(NULL),
+     mKeyboardCaptureHandler(NULL),
      mImportXMLTagHandler(NULL),
      mAutoSaving(false),
      mIsRecovered(false),
@@ -1819,7 +1820,7 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event))
 
    if (mScrollBeyondZero) {
       enum { SCROLL_PIXEL_TOLERANCE = 10 };
-      if (abs(mViewInfo.TimeToPosition(0.0, 0
+      if (std::abs(mViewInfo.TimeToPosition(0.0, 0
                                    )) < SCROLL_PIXEL_TOLERANCE) {
          // Snap the scrollbar to 0
          mViewInfo.h = 0;
@@ -1875,20 +1876,6 @@ bool AudacityProject::HandleKeyDown(wxKeyEvent & event)
    if (event.GetKeyCode() == WXK_PAGEDOWN)
       mTrackPanel->HandlePageDownKey();
 
-   // If a window has captured the keyboard, then allow it
-   // first dibs at the event.  If it does an event.Skip(false)
-   // then allow the event to process as normal, bypassing the
-   // command handler.
-   wxWindow *w = HasKeyboardCapture();
-   if (w) {
-      wxCommandEvent e(EVT_CAPTURE_KEY);
-      e.SetEventObject(&event);
-
-      if (w->GetEventHandler()->ProcessEvent(e)) {
-         return false;
-      }
-   }
-
    return mCommandManager.HandleKey(event, GetUpdateFlags(), 0xFFFFFFFF);
 }
 
@@ -1919,16 +1906,6 @@ bool AudacityProject::HandleKeyUp(wxKeyEvent & event)
    return mCommandManager.HandleKey(event, GetUpdateFlags(), 0xFFFFFFFF);
 }
 
-void AudacityProject::OnMenuEvent(wxMenuEvent & event)
-{
-   if (event.GetEventType() == wxEVT_MENU_OPEN) {
-      mCommandManager.HandleMenuOpen(event);
-   }
-   else if (event.GetEventType() == wxEVT_MENU_CLOSE) {
-      mCommandManager.HandleMenuClose(event);
-   }
-}
-
 /// Determines if flags for command are compatible with current state.
 /// If not, then try some recovery action to make it so.
 /// @return whether compatible or not after any actions taken.
@@ -2276,16 +2253,6 @@ void AudacityProject::OnOpenAudioFile(wxCommandEvent & event)
    RequestUserAttention();
 }
 
-void AudacityProject::OnCaptureKeyboard(wxCommandEvent & event)
-{
-   CaptureKeyboard((wxWindow *)event.GetEventObject());
-}
-
-void AudacityProject::OnReleaseKeyboard(wxCommandEvent & event)
-{
-   ReleaseKeyboard((wxWindow *)event.GetEventObject());
-}
-
 // static method, can be called outside of a project
 wxArrayString AudacityProject::ShowOpenDialog(wxString extraformat, wxString extrafilter)
 {
@@ -4642,25 +4609,6 @@ void AudacityProject::GetPlayRegion(double* playRegionStart,
    mRuler->GetPlayRegion(playRegionStart, playRegionEnd);
 }
 
-wxWindow *AudacityProject::HasKeyboardCapture()
-{
-   return mKeyboardCaptured;
-}
-
-void AudacityProject::CaptureKeyboard(wxWindow *w)
-{
-   mKeyboardCaptured = w;
-}
-
-void AudacityProject::ReleaseKeyboard(wxWindow *w)
-{
-   if (w == mKeyboardCaptured)
-   {
-      mKeyboardCaptured = NULL;
-   }
-}
-
-
 void AudacityProject::AutoSave()
 {
    //    SonifyBeginAutoSave(); // part of RBD's r10680 stuff now backed out
@@ -4970,3 +4918,46 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
    ModifyState(true);
 }
 
+// Keyboard capture
+
+// static
+bool AudacityProject::HasKeyboardCapture(const wxWindow *handler)
+{
+   return GetKeyboardCaptureHandler() == handler;
+}
+
+// static
+wxWindow *AudacityProject::GetKeyboardCaptureHandler()
+{
+   AudacityProject *project = GetActiveProject();
+   if (project)
+   {
+      return project->mKeyboardCaptureHandler;
+   }
+
+   return NULL;
+}
+
+// static
+void AudacityProject::CaptureKeyboard(wxWindow *handler)
+{
+   AudacityProject *project = GetActiveProject();
+   if (project)
+   {
+//      wxASSERT(project->mKeyboardCaptureHandler == NULL);
+      project->mKeyboardCaptureHandler = handler;
+   }
+}
+
+// static
+void AudacityProject::ReleaseKeyboard(wxWindow *handler)
+{
+   AudacityProject *project = GetActiveProject();
+   if (project)
+   {
+//      wxASSERT(project->mKeyboardCaptureHandler == handler);
+      project->mKeyboardCaptureHandler = NULL;
+   }
+
+   return;
+}
diff --git a/src/Project.h b/src/Project.h
index 8793bde25b9e11fab9e4d3bb0efa31bbf9f6cb2e..98cc9ffac8d89719d366ff83c16b07039a39d6f5 100644
--- a/src/Project.h
+++ b/src/Project.h
@@ -115,6 +115,11 @@ enum StatusBarField {
    rateStatusBarField = 3
 };
 
+////////////////////////////////////////////////////////////
+/// Custom events
+////////////////////////////////////////////////////////////
+DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_CAPTURE_KEY, -1);
+
 // XML handler for <import> tag
 class ImportXMLTagHandler : public XMLTagHandler
 {
@@ -260,6 +265,12 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
 
    CommandManager *GetCommandManager() { return &mCommandManager; }
 
+   // Keyboard capture
+   static bool HasKeyboardCapture(const wxWindow *handler);
+   static wxWindow *GetKeyboardCaptureHandler();
+   static void CaptureKeyboard(wxWindow *handler);
+   static void ReleaseKeyboard(wxWindow *handler);
+
    void RebuildMenuBar();
    void RebuildOtherMenus();
    void MayStartMonitoring();
@@ -267,7 +278,6 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
 
    // Message Handlers
 
-   void OnMenuEvent(wxMenuEvent & event);
    void OnMenu(wxCommandEvent & event);
    void OnUpdateUI(wxUpdateUIEvent & event);
 
@@ -281,8 +291,6 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    void OnTimer(wxTimerEvent & event);
    void OnToolBarUpdate(wxCommandEvent & event);
    void OnOpenAudioFile(wxCommandEvent & event);
-   void OnCaptureKeyboard(wxCommandEvent & event);
-   void OnReleaseKeyboard(wxCommandEvent & event);
    void OnODTaskUpdate(wxCommandEvent & event);
    void OnODTaskComplete(wxCommandEvent & event);
    void OnTrackListUpdated(wxCommandEvent & event);
@@ -445,10 +453,6 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    PlayMode mLastPlayMode;
    ViewInfo mViewInfo;
 
-   wxWindow *HasKeyboardCapture();
-   void CaptureKeyboard(wxWindow *h);
-   void ReleaseKeyboard(wxWindow *h);
-
    // Audio IO callback methods
    virtual void OnAudioIORate(int rate);
    virtual void OnAudioIOStartRecording();
@@ -601,8 +605,6 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    // See AudacityProject::OnActivate() for an explanation of this.
    wxWindow *mLastFocusedWindow;
 
-   wxWindow *mKeyboardCaptured;
-
    ImportXMLTagHandler* mImportXMLTagHandler;
 
    // Last auto-save file name and path (empty if none)
@@ -645,6 +647,9 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    // Flag that we're recoding.
    bool mIsCapturing;
 
+   // Keyboard capture
+   wxWindow *mKeyboardCaptureHandler;
+
    DECLARE_EVENT_TABLE()
 };
 
diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp
index 78bf71b1c7c6a192cc1ba4c560c3186ed9358b26..3c7624b2fb6cc2f358637661abf5402f2594daf6 100644
--- a/src/TrackArtist.cpp
+++ b/src/TrackArtist.cpp
@@ -324,9 +324,12 @@ void TrackArtist::DrawTracks(TrackList * tracks,
                              bool bigPoints,
                              bool drawSliders)
 {
+#if defined(__WXMAC__)
+   dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
+#endif
+
    wxRect trackRect = rect;
    wxRect stereoTrackRect;
-
    TrackListIterator iter(tracks);
    Track *t;
 
diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp
index 9e34813b6030d96ca1b0728049ec928d23128c0a..730e4db9ac0d26d5a43d955d223b479104d1b4e3 100644
--- a/src/TrackPanel.cpp
+++ b/src/TrackPanel.cpp
@@ -1261,7 +1261,6 @@ void TrackPanel::DoDrawIndicator
             if (x >= w) {
                x = w - 1;
             }
-
             dc.Blit( x, 0, 1, mBacking->GetHeight(), &mBackingDC, x, 0 );
          }
 
@@ -6424,12 +6423,6 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
 /// Allow typing into LabelTracks.
 void TrackPanel::OnChar(wxKeyEvent & event)
 {
-#if defined (__WXGTK__)
-   // AWD: workaround for bug 154
-   bool restore = wxGetApp().inKbdHandler;
-   wxGetApp().inKbdHandler = true;
-#endif
-
    // Only deal with LabelTracks
    Track *t = GetFocusedTrack();
    if (!t || t->GetKind() != Track::Label) {
@@ -6453,11 +6446,6 @@ void TrackPanel::OnChar(wxKeyEvent & event)
       Refresh( false );
    else if (!event.GetSkipped())
       RefreshTrack(t);
-
-#if defined (__WXGTK__)
-   // AWD: workaround for bug 154
-   wxGetApp().inKbdHandler = restore;
-#endif
 }
 
 /// Should handle the case when the mouse capture is lost.
@@ -7219,6 +7207,9 @@ void TrackPanel::Refresh(bool eraseBackground /* = TRUE */,
 /// actual contents of each track are drawn by the TrackArtist.
 void TrackPanel::DrawTracks(wxDC * dc)
 {
+#if defined(__WXMAC__)
+   dc->GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
+#endif
    wxRegion region = GetUpdateRegion();
 
    wxRect clip = GetRect();
@@ -9860,18 +9851,12 @@ void TrackPanel::SetFocusedTrack( Track *t )
    if (t && !t->GetLinked() && t->GetLink())
       t = (WaveTrack*)t->GetLink();
 
-   AudacityProject *p = GetActiveProject();
-
-   if (p && p->HasKeyboardCapture()) {
-      wxCommandEvent e(EVT_RELEASE_KEYBOARD);
-      e.SetEventObject(this);
-      GetParent()->GetEventHandler()->ProcessEvent(e);
+   if (AudacityProject::GetKeyboardCaptureHandler()) {
+      AudacityProject::ReleaseKeyboard(this);
    }
 
    if (t && t->GetKind() == Track::Label) {
-      wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-      e.SetEventObject(this);
-      GetParent()->GetEventHandler()->ProcessEvent(e);
+      AudacityProject::CaptureKeyboard(this);
    }
 
    mAx->SetFocus( t );
diff --git a/src/ViewInfo.h b/src/ViewInfo.h
index bba107215a93fdec8c80ece8c5a25d86161d2eeb..23f3445ab108b03294257d00a18af64753369629 100644
--- a/src/ViewInfo.h
+++ b/src/ViewInfo.h
@@ -112,16 +112,16 @@ public:
 
    // Return true if the mouse position is anywhere in the fisheye
    // origin specifies the pixel corresponding to time h
-   bool InFisheye(wxInt64 position, wxInt64 origin = 0) const
-   {origin; return false;} // stub
+   bool InFisheye(wxInt64 position, wxInt64 WXUNUSED(origin = 0)) const
+   {return false;} // stub
 
    // These accessors ignore the fisheye hiding state.
    // Inclusive:
-   wxInt64 GetFisheyeLeftBoundary(wxInt64 origin = 0) const
-   {origin; return 0;} // stub
+   wxInt64 GetFisheyeLeftBoundary(wxInt64 WXUNUSED(origin = 0)) const
+   {return 0;} // stub
    // Exclusive:
-   wxInt64 GetFisheyeRightBoundary(wxInt64 origin = 0) const
-   {origin; return 0;} // stub
+   wxInt64 GetFisheyeRightBoundary(wxInt64 WXUNUSED(origin = 0)) const
+   {return 0;} // stub
 
 };
 
diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp
index 6a7c5f7669095167913785e1f5234c25a44efc0e..ebfd98baab5103d0e37035b3e70be087fb455d4d 100644
--- a/src/commands/CommandManager.cpp
+++ b/src/commands/CommandManager.cpp
@@ -107,21 +107,163 @@ CommandManager.  It holds the callback for one command.
 #endif
 
 #define COMMAND _("Command")
+
+#if defined(__WXMAC__)
+#include <AppKit/AppKit.h>
+#include <wx/osx/private.h>
+#endif
+
+// Shared by all projects
+static class CommandManagerEventMonitor : public wxEventFilter
+{
+public:
+   CommandManagerEventMonitor()
+   :  wxEventFilter()
+   {
+#if defined(__WXMAC__)
+      NSEventMask mask = NSKeyDownMask;
+      
+      mHandler =
+      [
+         NSEvent addLocalMonitorForEventsMatchingMask:mask handler:^NSEvent *(NSEvent *event)
+         {
+            WXWidget widget = (WXWidget) [[event window] firstResponder];
+            if (widget)
+            {
+               wxWidgetCocoaImpl *impl = (wxWidgetCocoaImpl *)
+                  wxWidgetImpl::FindFromWXWidget(widget);
+               if (impl)
+               {
+                  wxKeyEvent wxevent(wxEVT_KEY_DOWN);
+                  impl->SetupKeyEvent(wxevent, event);
+              
+                  wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent);
+                  return FilterEvent(eventHook) == Event_Processed ? nil : event;
+               }
+            }
+
+            return event;
+         }
+      ];
+#else
+      wxEvtHandler::AddFilter(this);
+#endif
+   }
+
+   virtual ~CommandManagerEventMonitor()
+   {
+#if defined(__WXMAC__)
+      [NSEvent removeMonitor:mHandler];
+#else
+      wxEvtHandler::RemoveFilter(this);
+#endif
+   }
+
+   int FilterEvent(wxEvent& event)
+   {
+      AudacityProject *project = GetActiveProject();
+      if (!project)
+      {
+         return Event_Skip;
+      }
+      
+      wxEvtHandler *handler = project->GetKeyboardCaptureHandler();
+      if (!handler)
+      {
+         return Event_Skip;
+      }
+   
+      wxEventType type = event.GetEventType();
+      if (type != wxEVT_CHAR_HOOK)
+      {
+         return Event_Skip;
+      }
+ 
+      wxKeyEvent temp = (wxKeyEvent &) event;
+      temp.SetEventType(wxEVT_KEY_DOWN);
+   
+      wxCommandEvent e(EVT_CAPTURE_KEY);
+      e.SetEventObject(&temp);
+      e.StopPropagation();
+   
+      if (!handler->ProcessEvent(e))
+      {
+         return Event_Skip;
+      }
+   
+      temp.WasProcessed();
+      temp.StopPropagation();
+      wxEventProcessInHandlerOnly onlyDown(temp, handler);
+      if (!handler->ProcessEvent(temp))
+      {
+         return Event_Skip;
+      }
+   
+      int keyCode = temp.GetKeyCode();
+      switch (keyCode)
+      {
+      case WXK_SHIFT:
+      case WXK_CONTROL:
+      case WXK_MENU:
+      case WXK_CAPITAL:
+      case WXK_NUMLOCK:
+      case WXK_SCROLL:
+         break;
+   
+      default:
+         temp = (wxKeyEvent &) event;
+         temp.SetEventType(wxEVT_CHAR);
+   
+         if (!temp.ShiftDown())
+         {
+            if (wxIsascii(temp.m_keyCode))
+            {
+               temp.m_keyCode = wxTolower(temp.m_keyCode);
+            }
+   
+            if (temp.m_keyCode < WXK_START)
+            {
+               temp.m_uniChar = wxTolower(temp.m_uniChar);
+            }
+         }
+   
+         temp.WasProcessed();
+         temp.StopPropagation();
+         wxEventProcessInHandlerOnly onlyChar(temp, handler);
+         handler->ProcessEvent(temp);
+         
+         break;
+      }
+   
+      temp = (wxKeyEvent &) event;
+      temp.SetEventType(wxEVT_KEY_UP);
+      temp.WasProcessed();
+      temp.StopPropagation();
+      wxEventProcessInHandlerOnly onlyUp(temp, handler);
+      handler->ProcessEvent(temp);
+
+      return Event_Processed;
+   }
+
+private:
+
+#if defined(__WXMAC__)   
+   id mHandler;
+#endif
+
+} monitor;
+
 ///
 ///  Standard Constructor
 ///
 CommandManager::CommandManager():
-   mCurrentID(0),
-   mHiddenID(0),
+   mCurrentID(17000),
    mCurrentMenuName(COMMAND),
    mCurrentMenu(NULL),
-   mOpenMenu(NULL),
    mDefaultFlags(0),
    mDefaultMask(0)
 {
    mbSeparatorAllowed = false;
-   mbHideFlaggedItems = true;
-   mHidingLevel = 0;
 }
 
 ///
@@ -166,7 +308,6 @@ void CommandManager::PurgeData()
    mCurrentMenu = NULL;
    mCurrentMenuName = COMMAND;
    mCurrentID = 0;
-   mOpenMenu = NULL;
 }
 
 
@@ -177,7 +318,6 @@ void CommandManager::PurgeData()
 /// If the menubar already exists, simply returns it.
 wxMenuBar *CommandManager::AddMenuBar(wxString sMenu)
 {
-   mHidingLevel = 0;
    wxMenuBar *menuBar = GetMenuBar(sMenu);
    if (menuBar)
       return menuBar;
@@ -228,13 +368,7 @@ wxMenuBar * CommandManager::CurrentMenuBar()
 ///
 void CommandManager::BeginMenu(wxString tNameIn)
 {
-
    wxString tName = tNameIn;
-   if( ItemShouldBeHidden( tName ) )
-   {
-      mHidingLevel++;
-      return;
-   }
 
    wxMenu *tmpMenu = new wxMenu();
 
@@ -250,9 +384,6 @@ void CommandManager::BeginMenu(wxString tNameIn)
 /// to NULL.  It is still attached to the CurrentMenuBar()
 void CommandManager::EndMenu()
 {
-   if( mHidingLevel > 0 )
-      mHidingLevel--;
-
    mCurrentMenu = NULL;
    mCurrentMenuName = COMMAND;
 }
@@ -264,11 +395,6 @@ void CommandManager::EndMenu()
 wxMenu* CommandManager::BeginSubMenu(wxString tNameIn)
 {
    wxString tName = tNameIn;
-   if( ItemShouldBeHidden( tName ) )
-   {
-      mHidingLevel++;
-      return NULL;
-   }
 
    SubMenuListEntry *tmpEntry = new SubMenuListEntry;
 
@@ -288,12 +414,6 @@ wxMenu* CommandManager::BeginSubMenu(wxString tNameIn)
 /// after BeginSubMenu() is called but before EndSubMenu() is called.
 void CommandManager::EndSubMenu()
 {
-   if( mHidingLevel > 0 )
-   {
-      mHidingLevel--;
-      return;
-   }
-
    size_t submenu_count = mSubMenuList.GetCount()-1;
 
    //Save the submenu's information
@@ -340,22 +460,6 @@ wxMenu * CommandManager::CurrentMenu()
    return tmpCurrentSubMenu;
 }
 
-// This allows us a simplified menu that has fewer items.
-bool CommandManager::ItemShouldBeHidden( wxString &Label )
-{
-   if( Label.StartsWith(wxT("!")) )
-   {
-      Label = Label.Mid( 1 );
-      if( mbHideFlaggedItems )
-      {
-         return true;
-      }
-   }
-   if( mHidingLevel > 0 )
-      return true;
-   return false;
-}
-
 ///
 /// Add a menu item to the current menu.  When the user selects it, the
 /// given functor will be called
@@ -365,11 +469,6 @@ void CommandManager::InsertItem(wxString name, wxString label_in,
 {
    wxString label = label_in;
 
-   if (ItemShouldBeHidden(label)) {
-      delete callback;
-      return;
-   }
-
    wxMenuBar *bar = GetActiveProject()->GetMenuBar();
    wxArrayString names = ::wxStringTokenize(after, wxT(":"));
    size_t cnt = names.GetCount();
@@ -418,9 +517,6 @@ void CommandManager::InsertItem(wxString name, wxString label_in,
 
    int ID = NewIdentifier(name, label, menu, callback, false, 0, 0);
 
-   // Remove the accelerator as it will be handled internally
-   label = label.BeforeFirst(wxT('\t'));
-
    if (checkmark >= 0) {
       menu->InsertCheckItem(pos, ID, label);
       menu->Check(ID, checkmark != 0);
@@ -471,20 +567,12 @@ void CommandManager::AddItem(const wxChar *name,
    label += wxT("\t");
    label += accel ? accel : wxEmptyString;
 
-   if (ItemShouldBeHidden(label)) {
-      delete callback;
-      return;
-   }
-
    int ID = NewIdentifier(name, label, CurrentMenu(), callback, false, 0, 0);
 
    if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
       SetCommandFlags(name, flags, mask);
    }
 
-   // Remove the accelerator as it will be handled internally
-   label = label.BeforeFirst(wxT('\t'));
-
    if (checkmark >= 0) {
       CurrentMenu()->AppendCheckItem(ID, label);
       CurrentMenu()->Check(ID, checkmark != 0);
@@ -503,67 +591,21 @@ void CommandManager::AddItem(const wxChar *name,
 /// When you call Enable on this command name, it will enable or disable
 /// all of the items at once.
 void CommandManager::AddItemList(wxString name, wxArrayString labels,
-                                 CommandFunctor *callback,
-                                 bool plugins /*= false*/)
+                                 CommandFunctor *callback)
 {
    unsigned int i;
 
-   #ifndef __WXGTK__
-   plugins = false;
-   #endif
-
-   if( mHidingLevel  > 0 )
-      return;
-
    unsigned int effLen = labels.GetCount();
-   unsigned int nVisibleEffects=0;
 
    wxString label;
    int tmpmax;
 
-   // Count the visible effects.
-   for(i=0; i<effLen; i++) {
-      // ItemShouldBeHidden removes the ! so do it to a temporary.
-      label = labels[i];
-      if (!ItemShouldBeHidden(label)) {
-         nVisibleEffects++;
-      }
-   }
-
-   if (CurrentMenu()->GetMenuItemCount() + nVisibleEffects < MAX_MENU_LEN)
-      plugins = false;
-
-   // j counts the visible menu items, i counts the actual menu items.
-   // These numbers are the same unless we are using a simplified interface
-   // by hiding effects with a ! before them when translated.
-   int j=0;
    for(i=0; i<effLen; i++) {
-      if (!ItemShouldBeHidden(labels[i])) {
-
-         // ---- Start of code for Plugin sub-menus.  Only relevant on wxGTK.
-         // If plugins, and at start of a sublist....
-         if( plugins && ((j % MAX_SUBMENU_LEN) == 0 )) {
-            // End previous sub-menu, if there was one.
-            if( j>0 )
-               EndSubMenu();
-
-            // Start new sub-menu
-            // tmpmax is number of last plugin for this sub-menu
-            tmpmax = wxMin(j + MAX_SUBMENU_LEN, (int)nVisibleEffects);
-            // Submenu titles are 1 to 15, 15 to 30, etc.
-            BeginSubMenu(wxString::Format(_("Plug-ins %i to %i"),j+1,tmpmax));
-         }
-         // ---- End of code for Plugin sub-menus.
-
-         j++;
-         int ID = NewIdentifier(name, labels[i], CurrentMenu(), callback,
-                                true, i, effLen);
-         CurrentMenu()->Append(ID, labels[i]);
-         mbSeparatorAllowed = true;
-      }
+      int ID = NewIdentifier(name, labels[i], CurrentMenu(), callback,
+                             true, i, effLen);
+      CurrentMenu()->Append(ID, labels[i]);
+      mbSeparatorAllowed = true;
    }
-   if( plugins && (nVisibleEffects>0 ))
-      EndSubMenu();
 }
 
 ///
@@ -616,8 +658,6 @@ void CommandManager::AddMetaCommand(const wxChar *name,
 
 void CommandManager::AddSeparator()
 {
-   if( mHidingLevel > 0 )
-      return;
    if( mbSeparatorAllowed )
       CurrentMenu()->AppendSeparator();
    mbSeparatorAllowed = false; // boolean to prevent too many separators.
@@ -639,9 +679,13 @@ int CommandManager::NextIdentifier(int ID)
 ///WARNING: Does this conflict with the identifiers set for controls/windows?
 ///If it does, a workaround may be to keep controls below wxID_LOWEST
 ///and keep menus above wxID_HIGHEST
-int CommandManager::NewIdentifier(wxString name, wxString label, wxMenu *menu,
+int CommandManager::NewIdentifier(wxString name,
+                                  wxString label,
+                                  wxMenu *menu,
                                   CommandFunctor *callback,
-                                  bool multi, int index, int count)
+                                  bool multi,
+                                  int index,
+                                  int count)
 {
    CommandListEntry *tmpEntry = new CommandListEntry;
 
@@ -865,123 +909,6 @@ void CommandManager::SetKeyFromIndex(int i, wxString key)
    entry->key = KeyStringNormalize(key);
 }
 
-
-void CommandManager::HandleMenuOpen(wxMenuEvent &evt)
-{
-   // Ensure we have a menu and that it's a top-level menu.
-   wxMenu *m = evt.GetMenu();
-   if (!m || m->GetParent())
-      return;
-
-   // Windows does not send a CLOSE event if you move from one
-   // top-level menu to another, so simulate it.
-#if !defined(__WXMAC__)
-   if (mOpenMenu) {
-      wxMenuEvent dummy;
-      HandleMenuClose(dummy);
-   }
-
-   // Remember this menu
-   mOpenMenu = m;
-#endif
-
-   // Turn on the accelerators
-   ToggleAccels(m, true);
-
-   return;
-}
-
-void CommandManager::HandleMenuClose(wxMenuEvent &evt)
-{
-#if defined(__WXMAC__)
-   mOpenMenu = evt.GetMenu();
-#endif
-
-   // This can happen when if the Windows system menu is used
-   if (mOpenMenu == NULL)
-      return;
-
-   // GetMenu() under Windows will always return NULL.  And on other
-   // platforms we must ensure we are a top-level menu.
-   wxMenu *m = evt.GetMenu();
-   if (m && m->GetParent())
-      return;
-
-   // Turn off the accelerators
-   ToggleAccels(mOpenMenu, false);
-
-   // Forget about it
-   mOpenMenu = NULL;
-
-#if defined(__WXMSW__)
-   // On Windows, the last accelerator entry will remain active due to the way that
-   // wxMenuBar::RebuildAccelTable() functions.  Just so happens that if that last
-   // entry is an unmodified character, then that character will not be usable in
-   // a label track until a different menu has been opened...thus replacing that
-   // dangling accelerator entry.
-   //
-   // This should go away (or at least be re-evaluated) when moving to wx3 as they've
-   // completely redesigned the accelerator table handling.
-#if !wxCHECK_VERSION(3, 0, 0)
-   wxAcceleratorTable & at = const_cast<wxAcceleratorTable &>(GetActiveProject()->GetMenuBar()->GetAccelTable());
-   at = wxNullAcceleratorTable;
-#endif
-#endif
-   return;
-}
-
-void CommandManager::ToggleAccels(wxMenu *m, bool show)
-{
-   // Add the top-level menu to the stack;
-   wxArrayPtrVoid stack;
-   stack.Add(m);
-
-   // Process all sub-menus in this tree
-   while (!stack.IsEmpty()) {
-
-      // Pop the bottom entry
-      m = (wxMenu *) stack.Item(0);
-      stack.RemoveAt(0);
-
-      // Retrieve menuitem info for this menu
-      wxMenuItemList mil = m->GetMenuItems();
-      int iCnt = m->GetMenuItemCount();
-      int iNdx;
-
-      // Iterate all menuitems at this level
-      for (iNdx = 0; iNdx < iCnt; iNdx++) {
-
-         // Retrieve the menuitem
-         wxMenuItem *mi = mil.Item(iNdx)->GetData();
-         if (!mi)
-            continue;
-
-         // Stack the menu if this item represents a submenu
-         if (mi->IsSubMenu()) {
-            stack.Add(mi->GetSubMenu());
-            continue;
-         }
-
-         // Retrieve the command entry for this item
-         CommandListEntry *entry = mCommandIDHash[mi->GetId()];
-         if (!entry)
-            continue;
-
-         // Rebuild the label based on whether the accelerator should
-         // be shown.
-         wxString label = entry->label.BeforeFirst(wxT('\t'));
-         if (show && !entry->key.IsEmpty()) {
-            label = label + wxT("\t") + entry->key;
-         }
-
-         // Set the new label
-         mi->SetItemLabel( label );
-      }
-   }
-
-   return;
-}
-
 void CommandManager::TellUserWhyDisallowed( wxUint32 flagsGot, wxUint32 flagsRequired )
 {
    // The default string for 'reason' is a catch all.  I hope it won't ever be seen
@@ -1422,4 +1349,5 @@ void CommandManager::CheckDups()
       }
    }
 }
+
 #endif
diff --git a/src/commands/CommandManager.h b/src/commands/CommandManager.h
index c5bc548ed266d0ecd5fe8aeba9a4197b63487a20..221e618314caed735f5b79bd61040ea945287b42 100644
--- a/src/commands/CommandManager.h
+++ b/src/commands/CommandManager.h
@@ -102,7 +102,7 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
                    wxString after, int checkmark = -1);
 
    void AddItemList(wxString name, wxArrayString labels,
-                    CommandFunctor *callback, bool plugins = false);
+                    CommandFunctor *callback);
 
    void AddCheck(const wxChar *name,
                  const wxChar *label,
@@ -179,12 +179,6 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
    void SetKeyFromName(wxString name, wxString key);
    void SetKeyFromIndex(int i, wxString key);
 
-   //
-   // Displaying menus
-   //
-   void HandleMenuOpen(wxMenuEvent &evt);
-   void HandleMenuClose(wxMenuEvent &evt);
-
    //
    // Executing commands
    //
@@ -231,8 +225,6 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
    virtual XMLTagHandler *HandleXMLChild(const wxChar *tag);
    virtual void WriteXML(XMLWriter &xmlFile);
 
-   bool mbHideFlaggedItems;
-
 protected:
 
    wxMenuBar * CurrentMenuBar();
@@ -248,9 +240,6 @@ protected:
 
    wxString GetKey(wxString label);
 
-   void ToggleAccels(wxMenu *m, bool show);
-   bool ItemShouldBeHidden( wxString &Label );
-
 private:
    MenuBarList  mMenuBarList;
    SubMenuList  mSubMenuList;
@@ -259,15 +248,12 @@ private:
    CommandNameHash  mCommandKeyHash;
    CommandIDHash  mCommandIDHash;
    int mCurrentID;
-   int mHiddenID;
    int mXMLKeysRead;
 
    bool mbSeparatorAllowed; // false at the start of a menu and immediately after a separator.
-   int mHidingLevel;
 
    wxString mCurrentMenuName;
    wxMenu * mCurrentMenu;
-   wxMenu * mOpenMenu;
 
    wxUint32 mDefaultFlags;
    wxUint32 mDefaultMask;
diff --git a/src/toolbars/DeviceToolBar.cpp b/src/toolbars/DeviceToolBar.cpp
index c7b3a206ea766847f75438ad48d7722c06ad13c0..76295743949a54667f1ffe40beb23691c4c2990f 100644
--- a/src/toolbars/DeviceToolBar.cpp
+++ b/src/toolbars/DeviceToolBar.cpp
@@ -194,13 +194,12 @@ void DeviceToolBar::RefillCombos()
 
 void DeviceToolBar::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 
diff --git a/src/toolbars/MixerToolBar.cpp b/src/toolbars/MixerToolBar.cpp
index 5b398601327b6c0cf8fc86689df58b51adc9fd3f..6ea303c20a8736579dccff187c219669a7ee62e1 100644
--- a/src/toolbars/MixerToolBar.cpp
+++ b/src/toolbars/MixerToolBar.cpp
@@ -132,13 +132,12 @@ void MixerToolBar::Populate()
 //Also from SelectionBar;
 void MixerToolBar::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 
diff --git a/src/toolbars/SelectionBar.cpp b/src/toolbars/SelectionBar.cpp
index f2c908f40ce94f5e421662e51516f16dad660b9a..76b431d33027f1851c117678d836294d2896ea25 100644
--- a/src/toolbars/SelectionBar.cpp
+++ b/src/toolbars/SelectionBar.cpp
@@ -46,10 +46,10 @@ with changes in the SelectionBar.
 #include "SelectionBarListener.h"
 #include "SelectionBar.h"
 
-#include "../AudacityApp.h"
 #include "../AudioIO.h"
 #include "../AColor.h"
 #include "../Prefs.h"
+#include "../Project.h"
 #include "../Snap.h"
 #include "../widgets/NumericTextCtrl.h"
 
@@ -521,13 +521,12 @@ void SelectionBar::UpdateRates()
 
 void SelectionBar::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 
@@ -540,11 +539,6 @@ void SelectionBar::OnCaptureKey(wxCommandEvent &event)
    wxWindow *w = FindFocus();
    int keyCode = kevent->GetKeyCode();
 
-   // Pass the SPACE through for SnapTo
-   if (w == mSnapTo && keyCode == WXK_SPACE) {
-      return;
-   }
-
    // Convert numeric keypad entries.
    if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) {
       keyCode -= WXK_NUMPAD0 - '0';
diff --git a/src/toolbars/TranscriptionToolBar.cpp b/src/toolbars/TranscriptionToolBar.cpp
index e864a8bbe4099c4049c5098e033a6f80d6d9f818..31c7ab0f3620bce31a99c4714d5fb6522a9a95b5 100644
--- a/src/toolbars/TranscriptionToolBar.cpp
+++ b/src/toolbars/TranscriptionToolBar.cpp
@@ -326,13 +326,12 @@ void TranscriptionToolBar::RegenerateTooltips()
 
 void TranscriptionToolBar::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 
diff --git a/src/widgets/NumericTextCtrl.cpp b/src/widgets/NumericTextCtrl.cpp
index 380d177e8aff6b64349fe0feaf2a19c0f538de65..73bab1830bed1e0c5688a91c0039db4d5a62514b 100644
--- a/src/widgets/NumericTextCtrl.cpp
+++ b/src/widgets/NumericTextCtrl.cpp
@@ -166,12 +166,12 @@ different formats.
 
 
 #include "../Audacity.h"
-#include "../AudacityApp.h"
 #include "NumericTextCtrl.h"
 #include "../Sequence.h"   // for sampleCount
 #include "../Theme.h"
 #include "../AllThemeResources.h"
 #include "../AColor.h"
+#include "../Project.h"
 
 #include <algorithm>
 #include <math.h>
@@ -1169,10 +1169,6 @@ NumericTextCtrl::NumericTextCtrl(NumericConverter::Type type,
 
 NumericTextCtrl::~NumericTextCtrl()
 {
-   wxCommandEvent e(EVT_RELEASE_KEYBOARD);
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
-
    if (mBackgroundBitmap)
       delete mBackgroundBitmap;
    if (mDigitFont)
@@ -1537,13 +1533,12 @@ void NumericTextCtrl::OnMouse(wxMouseEvent &event)
 
 void NumericTextCtrl::OnFocus(wxFocusEvent &event)
 {
-   wxCommandEvent e(EVT_CAPTURE_KEYBOARD);
-
    if (event.GetEventType() == wxEVT_KILL_FOCUS) {
-      e.SetEventType(EVT_RELEASE_KEYBOARD);
+      AudacityProject::ReleaseKeyboard(this);
+   }
+   else {
+      AudacityProject::CaptureKeyboard(this);
    }
-   e.SetEventObject(this);
-   GetParent()->GetEventHandler()->ProcessEvent(e);
 
    Refresh(false);
 }
@@ -1554,7 +1549,8 @@ void NumericTextCtrl::OnCaptureKey(wxCommandEvent &event)
    int keyCode = kevent->GetKeyCode();
 
    // Convert numeric keypad entries.
-   if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) keyCode -= WXK_NUMPAD0 - '0';
+   if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9))
+      keyCode -= WXK_NUMPAD0 - '0';
 
    switch (keyCode)
    {
@@ -1605,7 +1601,7 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
       return;
    }
 
-   event.Skip();
+   event.Skip(false);
 
    int keyCode = event.GetKeyCode();
    int digit = mFocusedDigit;
@@ -1616,7 +1612,8 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
       mFocusedDigit = mDigits.GetCount()-1;
 
    // Convert numeric keypad entries.
-   if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) keyCode -= WXK_NUMPAD0 - '0';
+   if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9))
+      keyCode -= WXK_NUMPAD0 - '0';
 
    if (!mReadOnly && (keyCode >= '0' && keyCode <= '9')) {
       int digitPosition = mDigits[mFocusedDigit].pos;
@@ -1687,7 +1684,6 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
       nevent.SetEventObject(parent);
       nevent.SetCurrentFocus(parent);
       GetParent()->GetEventHandler()->ProcessEvent(nevent);
-      event.Skip(false);
    }
 
    else if (keyCode == WXK_RETURN || keyCode == WXK_NUMPAD_ENTER) {
@@ -1697,7 +1693,6 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
          wxCommandEvent cevent(wxEVT_COMMAND_BUTTON_CLICKED,
                                def->GetId());
          GetParent()->GetEventHandler()->ProcessEvent(cevent);
-         event.Skip(false);
       }
    }