1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-04 17:49:45 +02:00

Further fixes for keyboard handling

I'm pretty sure this gets all of the currently known issues, including
the SHIFT+M not working, the Play buttons responding to SHIFT and CTRL,
the ESC key canceling drags, and I'm pretty sure it even fixes
but #784.
This commit is contained in:
Leland Lucius 2015-08-10 13:15:15 -05:00
parent 5522722d2c
commit 04d026e5bc
5 changed files with 125 additions and 115 deletions

View File

@ -738,8 +738,6 @@ void AudacityApp::MacNewFile()
#endif //__WXMAC__
typedef int (AudacityApp::*SPECIALKEYEVENT)(wxKeyEvent&);
#define ID_RECENT_CLEAR 6100
#define ID_RECENT_FIRST 6101
#define ID_RECENT_LAST 6112

View File

@ -1092,8 +1092,8 @@ void AudacityProject::CreateMenusAndCommands()
SetMenuBar(menubar);
c->AddMetaCommand(wxT("PrevWindow"), _("Move backward thru active windows"), FN(PrevWindow), wxT("Alt+Shift+F6"));
c->AddMetaCommand(wxT("NextWindow"), _("Move forward thru active windows"), FN(NextWindow), wxT("Alt+F6"));
c->AddGlobalCommand(wxT("PrevWindow"), _("Move backward thru active windows"), FN(PrevWindow), wxT("Alt+Shift+F6"));
c->AddGlobalCommand(wxT("NextWindow"), _("Move forward thru active windows"), FN(NextWindow), wxT("Alt+F6"));
c->SetDefaultFlags(AlwaysEnabledFlag, AlwaysEnabledFlag);
@ -1152,10 +1152,10 @@ void AudacityProject::CreateMenusAndCommands()
c->SetDefaultFlags(AudioIOBusyFlag, AudioIOBusyFlag);
c->AddCommand(wxT("SeekLeftShort"), _("Short seek left during playback"), FN(OnSeekLeftShort), wxT("Left\tallowdup"));
c->AddCommand(wxT("SeekRightShort"),_("Short seek right during playback"), FN(OnSeekRightShort), wxT("Right\tallowdup"));
c->AddCommand(wxT("SeekLeftLong"), _("Long seek left during playback"), FN(OnSeekLeftLong), wxT("Shift+Left\tallowdup"));
c->AddCommand(wxT("SeekRightLong"), _("Long Seek right during playback"), FN(OnSeekRightLong), wxT("Shift+Right\tallowdup"));
c->AddCommand(wxT("SeekLeftShort"), _("Short seek left during playback"), FN(OnSeekLeftShort), wxT("Left\tallowDup"));
c->AddCommand(wxT("SeekRightShort"),_("Short seek right during playback"), FN(OnSeekRightShort), wxT("Right\tallowDup"));
c->AddCommand(wxT("SeekLeftLong"), _("Long seek left during playback"), FN(OnSeekLeftLong), wxT("Shift+Left\tallowDup"));
c->AddCommand(wxT("SeekRightLong"), _("Long Seek right during playback"), FN(OnSeekRightLong), wxT("Shift+Right\tallowDup"));
c->SetDefaultFlags(TracksExistFlag | TrackPanelHasFocus,
TracksExistFlag | TrackPanelHasFocus);
@ -1171,21 +1171,21 @@ void AudacityProject::CreateMenusAndCommands()
c->AddCommand(wxT("Toggle"), _("Toggle Focused Track"), FN(OnToggle), wxT("Return"));
c->AddCommand(wxT("ToggleAlt"), _("Toggle Focused Track"), FN(OnToggle), wxT("NUMPAD_ENTER"));
c->AddCommand(wxT("CursorLeft"), _("Cursor Left"), FN(OnCursorLeft), wxT("Left\twantevent\tallowdup"));
c->AddCommand(wxT("CursorRight"), _("Cursor Right"), FN(OnCursorRight), wxT("Right\twantevent\tallowdup"));
c->AddCommand(wxT("CursorLeft"), _("Cursor Left"), FN(OnCursorLeft), wxT("Left\twantKeyup\tallowDup"));
c->AddCommand(wxT("CursorRight"), _("Cursor Right"), FN(OnCursorRight), wxT("Right\twantKeyup\tallowDup"));
c->AddCommand(wxT("CursorShortJumpLeft"), _("Cursor Short Jump Left"), FN(OnCursorShortJumpLeft), wxT(","));
c->AddCommand(wxT("CursorShortJumpRight"), _("Cursor Short Jump Right"), FN(OnCursorShortJumpRight), wxT("."));
c->AddCommand(wxT("CursorLongJumpLeft"), _("Cursor Long Jump Left"), FN(OnCursorLongJumpLeft), wxT("Shift+,"));
c->AddCommand(wxT("CursorLongJumpRight"), _("Cursor Long Jump Right"), FN(OnCursorLongJumpRight), wxT("Shift+."));
c->AddCommand(wxT("SelExtLeft"), _("Selection Extend Left"), FN(OnSelExtendLeft), wxT("Shift+Left\twantevent\tallowdup"));
c->AddCommand(wxT("SelExtRight"), _("Selection Extend Right"), FN(OnSelExtendRight), wxT("Shift+Right\twantevent\tallowdup"));
c->AddCommand(wxT("SelExtLeft"), _("Selection Extend Left"), FN(OnSelExtendLeft), wxT("Shift+Left\twantKeyup\tallowDup"));
c->AddCommand(wxT("SelExtRight"), _("Selection Extend Right"), FN(OnSelExtendRight), wxT("Shift+Right\twantKeyup\tallowDup"));
c->AddCommand(wxT("SelSetExtLeft"), _("Set (or Extend) Left Selection"), FN(OnSelSetExtendLeft));
c->AddCommand(wxT("SelSetExtRight"), _("Set (or Extend) Right Selection"), FN(OnSelSetExtendRight));
c->AddCommand(wxT("SelCntrLeft"), _("Selection Contract Left"), FN(OnSelContractLeft), wxT("Ctrl+Shift+Right\twantevent"));
c->AddCommand(wxT("SelCntrRight"), _("Selection Contract Right"), FN(OnSelContractRight), wxT("Ctrl+Shift+Left\twantevent"));
c->AddCommand(wxT("SelCntrLeft"), _("Selection Contract Left"), FN(OnSelContractLeft), wxT("Ctrl+Shift+Right\twantKeyup"));
c->AddCommand(wxT("SelCntrRight"), _("Selection Contract Right"), FN(OnSelContractRight), wxT("Ctrl+Shift+Left\twantKeyup"));
c->AddCommand(wxT("TrackPan"), _("Change pan on focused track"), FN(OnTrackPan), wxT("Shift+P"));
c->AddCommand(wxT("TrackPanLeft"), _("Pan left on focused track"), FN(OnTrackPanLeft), wxT("Alt+Shift+Left"));
@ -1193,8 +1193,7 @@ void AudacityProject::CreateMenusAndCommands()
c->AddCommand(wxT("TrackGain"), _("Change gain on focused track"), FN(OnTrackGain), wxT("Shift+G"));
c->AddCommand(wxT("TrackGainInc"), _("Increase gain on focused track"), FN(OnTrackGainInc), wxT("Alt+Shift+Up"));
c->AddCommand(wxT("TrackGainDec"), _("Decrease gain on focused track"), FN(OnTrackGainDec), wxT("Alt+Shift+Down"));
// use "wantevent" to eat the KEY_UP event...fixes a problem on Windows where the key up selects the "Mono" item
c->AddCommand(wxT("TrackMenu"), _("Open menu on focused track"), FN(OnTrackMenu), wxT("Shift+M\tignoredown"));
c->AddCommand(wxT("TrackMenu"), _("Open menu on focused track"), FN(OnTrackMenu), wxT("Shift+M"));
c->AddCommand(wxT("TrackMute"), _("Mute/Unmute focused track"), FN(OnTrackMute), wxT("Shift+U"));
c->AddCommand(wxT("TrackSolo"), _("Solo/Unsolo focused track"), FN(OnTrackSolo), wxT("Shift+S"));
c->AddCommand(wxT("TrackClose"), _("Close focused track"), FN(OnTrackClose), wxT("Shift+C"));

View File

@ -324,7 +324,7 @@ BEGIN_EVENT_TABLE(TrackPanel, wxWindow)
EVT_MOUSE_CAPTURE_LOST(TrackPanel::OnCaptureLost)
EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, TrackPanel::OnCaptureKey)
EVT_KEY_DOWN(TrackPanel::OnKeyDown)
EVT_KEY_DOWN(TrackPanel::OnKeyUp)
EVT_KEY_UP(TrackPanel::OnKeyUp)
EVT_CHAR(TrackPanel::OnChar)
EVT_SIZE(TrackPanel::OnSize)
EVT_ERASE_BACKGROUND(TrackPanel::OnErase)
@ -6243,29 +6243,36 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
event.Skip(!((LabelTrack *)t)->CaptureKey(*kevent));
}
/// Allow typing into LabelTracks.
void TrackPanel::OnKeyDown(wxKeyEvent & event)
{
if (event.GetKeyCode() == WXK_ESCAPE)
switch (event.GetKeyCode())
{
case WXK_ESCAPE:
HandleEscapeKey(true);
break;
if (event.GetKeyCode() == WXK_ALT)
case WXK_ALT:
HandleAltKey(true);
break;
// Allow the zoom cursor to change to a zoom out cursor
if (event.GetKeyCode() == WXK_SHIFT)
case WXK_SHIFT:
HandleShiftKey(true);
break;
if (event.GetKeyCode() == WXK_CONTROL)
case WXK_CONTROL:
HandleControlKey(true);
break;
// Allow PageUp and PageDown keys to
//scroll the Track Panel left and right
if (event.GetKeyCode() == WXK_PAGEUP)
case WXK_PAGEUP:
HandlePageUpKey();
return;
if (event.GetKeyCode() == WXK_PAGEDOWN)
case WXK_PAGEDOWN:
HandlePageDownKey();
return;
}
Track *t = GetFocusedTrack();
@ -6301,9 +6308,19 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
RefreshTrack(t);
}
/// Allow typing into LabelTracks.
void TrackPanel::OnChar(wxKeyEvent & event)
{
switch (event.GetKeyCode())
{
case WXK_ESCAPE:
case WXK_ALT:
case WXK_SHIFT:
case WXK_CONTROL:
case WXK_PAGEUP:
case WXK_PAGEDOWN:
return;
}
// Only deal with LabelTracks
Track *t = GetFocusedTrack();
if (!t || t->GetKind() != Track::Label) {
@ -6331,19 +6348,25 @@ void TrackPanel::OnChar(wxKeyEvent & event)
void TrackPanel::OnKeyUp(wxKeyEvent & event)
{
if (event.GetKeyCode() == WXK_ESCAPE)
switch (event.GetKeyCode())
{
case WXK_ESCAPE:
HandleEscapeKey(false);
if (event.GetKeyCode() == WXK_ALT)
break;
case WXK_ALT:
HandleAltKey(false);
break;
// Allow the Zoom Out cursor back to Zoom In
if (event.GetKeyCode() == WXK_SHIFT)
case WXK_SHIFT:
HandleShiftKey(false);
break;
if (event.GetKeyCode() == WXK_CONTROL)
case WXK_CONTROL:
HandleControlKey(false);
break;
}
event.Skip();
}
/// Should handle the case when the mouse capture is lost.

View File

@ -729,7 +729,7 @@ void CommandManager::AddCommand(const wxChar *name,
}
}
void CommandManager::AddMetaCommand(const wxChar *name,
void CommandManager::AddGlobalCommand(const wxChar *name,
const wxChar *label_in,
CommandFunctor *callback,
const wxChar *accel)
@ -737,7 +737,7 @@ void CommandManager::AddMetaCommand(const wxChar *name,
CommandListEntry *entry = NewIdentifier(name, label_in, accel, NULL, callback, false, 0, 0);
entry->enabled = false;
entry->isMeta = true;
entry->isGlobal = true;
entry->flags = 0;
entry->mask = 0;
}
@ -834,9 +834,8 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & name,
entry->flags = mDefaultFlags;
entry->mask = mDefaultMask;
entry->enabled = true;
entry->wantevent = (accel.Find(wxT("\twantevent")) != wxNOT_FOUND);
entry->ignoredown = (accel.Find(wxT("\tignoredown")) != wxNOT_FOUND);
entry->isMeta = false;
entry->wantKeyup = (accel.Find(wxT("\twantKeyup")) != wxNOT_FOUND);
entry->isGlobal = false;
// For key bindings for commands with a list, such as effects,
// the name in prefs is the category name plus the effect name.
@ -1042,12 +1041,28 @@ void CommandManager::TellUserWhyDisallowed( wxUint32 flagsGot, wxUint32 flagsReq
///
///
///
bool CommandManager::FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt, bool permit)
bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit)
{
if (HandleMeta(evt))
CommandListEntry *entry = mCommandKeyHash[KeyEventToKeyString(evt)];
if (entry == NULL)
{
return false;
}
// Global commands are tied to any specific project
if (entry->isGlobal)
{
// Global commands are always disabled so they do not interfere with the
// rest of the command handling. But, to use the common handler, we
// enable it temporarily and then disable it again after handling.
entry->enabled = true;
bool ret = HandleCommandEntry(entry, 0xffffffff, 0xffffffff, &evt);
entry->enabled = false;
if (ret)
{
return true;
}
}
// Any other keypresses must be destined for this project window.
if (!permit && wxGetTopLevelParent(wxWindow::FindFocus()) != project)
@ -1059,10 +1074,13 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt,
wxKeyEvent temp = evt;
temp.SetEventType(wxEVT_KEY_DOWN);
if (HandleKey(temp, flags, 0xFFFFFFFF))
if (HandleCommandEntry(entry, flags, 0xffffffff, &evt))
{
if (entry->wantKeyup)
{
temp.SetEventType(wxEVT_KEY_UP);
HandleKey(temp, flags, 0xFFFFFFFF);
HandleCommandEntry(entry, flags, 0xffffffff, &evt);
}
return true;
}
@ -1074,7 +1092,7 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt,
/// returning true iff successful. If you pass any flags,
///the command won't be executed unless the flags are compatible
///with the command's flags.
bool CommandManager::HandleCommandEntry(CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt)
bool CommandManager::HandleCommandEntry(const CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt)
{
if (!entry || !entry->enabled)
return false;
@ -1114,53 +1132,6 @@ bool CommandManager::HandleMenuID(int id, wxUint32 flags, wxUint32 mask)
return HandleCommandEntry( entry, flags, mask );
}
///Call this when a key event is received.
///If it matches a command, it will call the appropriate
///CommandManagerListener function. If you pass any flags,
///the command won't be executed unless the flags are compatible
///with the command's flags.
bool CommandManager::HandleKey(wxKeyEvent &evt, wxUint32 flags, wxUint32 mask)
{
wxString keyStr = KeyEventToKeyString(evt);
CommandListEntry *entry = mCommandKeyHash[keyStr];
if (entry)
{
if (evt.GetEventType() == wxEVT_KEY_DOWN && !entry->ignoredown)
{
return HandleCommandEntry( entry, flags, mask, &evt );
}
if (evt.GetEventType() == wxEVT_KEY_UP && (entry->wantevent || entry->ignoredown))
{
return HandleCommandEntry( entry, flags, mask, &evt );
}
}
return false;
}
bool CommandManager::HandleMeta(wxKeyEvent &evt)
{
wxString keyStr = KeyEventToKeyString(evt);
CommandListEntry *entry = mCommandKeyHash[keyStr];
// Return unhandle if it isn't a meta command
if (!entry || !entry->isMeta)
{
return false;
}
// Meta commands are always disabled so they do not interfere with the
// rest of the command handling. But, to use the common handler, we
// enable it temporarily and then disable it again after handling.
entry->enabled = true;
bool ret = HandleCommandEntry( entry, 0xffffffff, 0xffffffff, &evt );
entry->enabled = false;
return ret;
}
/// HandleTextualCommand() allows us a limitted version of script/batch
/// behavior, since we can get from a string command name to the actual
/// code to run.
@ -1471,7 +1442,7 @@ void CommandManager::CheckDups()
continue;
}
if (mCommandList[j]->label.AfterLast(wxT('\t')) == wxT("allowdup")) {
if (mCommandList[j]->label.AfterLast(wxT('\t')) == wxT("allowDup")) {
continue;
}

View File

@ -57,9 +57,8 @@ struct CommandListEntry
int index;
int count;
bool enabled;
bool wantevent;
bool ignoredown;
bool isMeta;
bool wantKeyup;
bool isGlobal;
wxUint32 flags;
wxUint32 mask;
};
@ -150,7 +149,7 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
unsigned int flags = NoFlagsSpecifed,
unsigned int mask = NoFlagsSpecifed);
void AddMetaCommand(const wxChar *name,
void AddGlobalCommand(const wxChar *name,
const wxChar *label,
CommandFunctor *callback,
const wxChar *accel);
@ -187,15 +186,11 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
// Executing commands
//
// "permit" allows filtering even if the active window is a child of the project.
// "permit" allows filtering even if the active window isn't a child of the project.
// Lyrics and MixerTrackCluster classes use it.
bool FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt, bool permit = false);
bool HandleCommandEntry(CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt = NULL);
bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit = false);
bool HandleMenuID(int id, wxUint32 flags, wxUint32 mask);
bool HandleKey(wxKeyEvent &evt, wxUint32 flags, wxUint32 mask);
bool HandleMeta(wxKeyEvent &evt);
bool HandleTextualCommand(wxString & Str, wxUint32 flags, wxUint32 mask);
void TellUserWhyDisallowed(wxUint32 flagsGot, wxUint32 flagsRequired);
//
// Accessing
@ -228,17 +223,13 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
// Loading/Saving
//
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
virtual void HandleXMLEndTag(const wxChar *tag);
virtual XMLTagHandler *HandleXMLChild(const wxChar *tag);
virtual void WriteXML(XMLWriter &xmlFile);
protected:
wxMenuBar * CurrentMenuBar() const;
wxMenuBar * GetMenuBar(wxString sMenu) const;
wxMenu * CurrentSubMenu() const;
wxMenu * CurrentMenu() const;
//
// Creating menus and adding commands
//
int NextIdentifier(int ID);
CommandListEntry *NewIdentifier(const wxString & name,
@ -256,10 +247,38 @@ protected:
bool multi,
int index,
int count);
//
// Executing commands
//
bool HandleCommandEntry(const CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt = NULL);
void TellUserWhyDisallowed(wxUint32 flagsGot, wxUint32 flagsRequired);
//
// Modifying
//
void Enable(CommandListEntry *entry, bool enabled);
//
// Accessing
//
wxMenuBar * CurrentMenuBar() const;
wxMenuBar * GetMenuBar(wxString sMenu) const;
wxMenu * CurrentSubMenu() const;
wxMenu * CurrentMenu() const;
wxString GetLabel(const CommandListEntry *entry) const;
//
// Loading/Saving
//
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
virtual void HandleXMLEndTag(const wxChar *tag);
virtual XMLTagHandler *HandleXMLChild(const wxChar *tag);
private:
MenuBarList mMenuBarList;
SubMenuList mSubMenuList;