Audacity  3.0.3
KeyConfigPrefs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  KeyConfigPrefs.cpp
6 
7  Brian Gunlogson
8  Dominic Mazzoni
9  James Crook
10 
11 *******************************************************************//*********************************************************************/
21 
22 
23 
24 #include "KeyConfigPrefs.h"
25 
26 #include <wx/setup.h> // for wxUSE_* macros
27 #include <wx/defs.h>
28 #include <wx/ffile.h>
29 #include <wx/intl.h>
30 #include <wx/menu.h>
31 #include <wx/button.h>
32 #include <wx/radiobut.h>
33 #include <wx/stattext.h>
34 #include <wx/statbox.h>
35 #include <wx/textctrl.h>
36 
37 #include "Prefs.h"
38 #include "../Project.h"
39 #include "../commands/CommandManager.h"
40 #include "../xml/XMLFileReader.h"
41 
42 #include "../ShuttleGui.h"
43 
44 #include "../FileNames.h"
45 
46 #include "../widgets/KeyView.h"
47 #include "../widgets/AudacityMessageBox.h"
48 
49 #if wxUSE_ACCESSIBILITY
50 #include "../widgets/WindowAccessible.h"
51 #endif
52 
53 //
54 // KeyConfigPrefs
55 //
56 #define AssignDefaultsButtonID 17001
57 #define CurrentComboID 17002
58 #define SetButtonID 17003
59 #define ClearButtonID 17004
60 #define CommandsListID 17005
61 #define ExportButtonID 17006
62 #define ImportButtonID 17007
63 #define FilterID 17008
64 #define ViewByTreeID 17009
65 #define ViewByNameID 17010
66 #define ViewByKeyID 17011
67 #define FilterTimerID 17012
68 
69 // EMPTY_SHORTCUT means "user chose to have no shortcut"
70 #define EMPTY_SHORTCUT ("")
71 // NO_SHORTCUT means "user made no choice"
72 #define NO_SHORTCUT (wxString)((wxChar)7)
73 
74 BEGIN_EVENT_TABLE(KeyConfigPrefs, PrefsPanel)
81  EVT_RADIOBUTTON(ViewByTreeID, KeyConfigPrefs::OnViewBy)
82  EVT_RADIOBUTTON(ViewByNameID, KeyConfigPrefs::OnViewBy)
83  EVT_RADIOBUTTON(ViewByKeyID, KeyConfigPrefs::OnViewBy)
86 
88  wxWindow * parent, wxWindowID winid, AudacityProject *pProject,
89  const CommandID &name)
90 /* i18n-hint: as in computer keyboard (not musical!) */
91 : PrefsPanel(parent, winid, XO("Keyboard")),
92  mView(NULL),
93  mKey(NULL),
94  mFilter(NULL),
95  mFilterTimer(this, FilterTimerID),
96  mFilterPending(false)
97  , mProject{ pProject }
98 {
99  Populate();
100  if (!name.empty()) {
101  auto index = mView->GetIndexByName(name);
102  mView->SelectNode(index);
103  }
104 
105  // See bug #2315 for discussion. This should be reviewed
106  // and (possibly) removed after wx3.1.3.
107  Bind(wxEVT_SHOW, &KeyConfigPrefs::OnShow, this);
108 }
109 
111 {
113 }
114 
116 {
117  return XO("Preferences for KeyConfig");
118 }
119 
121 {
122  return "Keyboard_Preferences";
123 }
124 
126 {
128 
129  if (!mProject) {
130  S.StartVerticalLay(true);
131  {
132  S.StartStatic( {}, true);
133  {
134  S.AddTitle(XO("Keyboard preferences currently unavailable."));
135  S.AddTitle(XO("Open a new project to modify keyboard shortcuts."));
136  }
137  S.EndStatic();
138  }
139  S.EndVerticalLay();
140 
141  return;
142  }
143 
145 
146  mCommandSelected = wxNOT_FOUND;
147 
149 
150  // For speed, don't sort here. We're just creating.
151  // Instead sort when we do SetView later in this function.
152  RefreshBindings(false);
153 
154  if (mViewByTree->GetValue()) {
156  }
157  else if (mViewByName->GetValue()) {
159  }
160  else if (mViewByKey->GetValue()) {
162  mFilterLabel->SetLabel(_("&Hotkey:"));
163  mFilter->SetName(wxStripMenuCodes(mFilterLabel->GetLabel()));
164  }
165 
167 }
168 
174 {
175  S.SetBorder(2);
176 
177  S.StartStatic(XO("Key Bindings"), 1);
178  {
179  S.StartHorizontalLay(wxEXPAND, 0);
180  {
181  S.Position(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL).AddTitle(XO("View by:"));
182 
183  // Bug 2692: Place button group in panel so tabbing will work and,
184  // on the Mac, VoiceOver will announce as radio buttons.
185  S.StartPanel();
186  {
187  S.StartHorizontalLay();
188  {
190  wxT("/Prefs/KeyConfig/ViewBy"),
191  {
192  { wxT("tree"), XXO("&Tree") },
193  { wxT("name"), XXO("&Name") },
194  { wxT("key"), XXO("&Key") },
195  },
196  0 // tree
197  });
198  {
200  .Name(XO("View by tree"))
201  .TieRadioButton();
203  .Name(XO("View by name"))
204  .TieRadioButton();
206  .Name(XO("View by key"))
207  .TieRadioButton();
208 #if !defined(__WXMAC__) && wxUSE_ACCESSIBILITY
209  // so that name can be set on a standard control
213 #endif
214  }
216  }
217  S.EndHorizontalLay();
218  }
219  S.EndPanel();
220 
221  S.AddSpace(wxDefaultCoord, wxDefaultCoord, 1);
222 
223  S.StartHorizontalLay(wxALIGN_CENTER_VERTICAL, 0);
224  {
225  mFilterLabel = S.Position(wxALIGN_CENTER_VERTICAL).AddVariableText(XO("Searc&h:"));
226 
227  if (!mFilter) {
228  mFilter = safenew wxTextCtrl(S.GetParent(),
229  FilterID,
230  wxT(""),
231  wxDefaultPosition,
232 #if defined(__WXMAC__)
233  wxSize(300, -1),
234 #else
235  wxSize(210, -1),
236 #endif
237  wxTE_PROCESS_ENTER);
238  mFilter->SetName(wxStripMenuCodes(mFilterLabel->GetLabel()));
239  }
240  S.Position(wxALIGN_NOT | wxALIGN_LEFT)
241  .ConnectRoot(wxEVT_KEY_DOWN,
243  .ConnectRoot(wxEVT_CHAR,
245  .AddWindow(mFilter);
246  }
247  S.EndHorizontalLay();
248  }
249  S.EndHorizontalLay();
250 
251  S.AddSpace(wxDefaultCoord, 2);
252 
253  S.StartHorizontalLay(wxEXPAND, 1);
254  {
255  if (!mView) {
257  mView->SetName(_("Bindings"));
258  }
259  S.Prop(true)
260  .Position(wxEXPAND)
261  .AddWindow(mView);
262  }
263  S.EndHorizontalLay();
264 
265  S.StartThreeColumn();
266  {
267  if (!mKey) {
268  mKey = safenew wxTextCtrl(S.GetParent(),
270  wxT(""),
271  wxDefaultPosition,
272 #if defined(__WXMAC__)
273  wxSize(300, -1),
274 #else
275  wxSize(210, -1),
276 #endif
277  wxTE_PROCESS_ENTER);
278 #if !defined(__WXMAC__) && wxUSE_ACCESSIBILITY
279  // so that name can be set on a standard control
280  mKey->SetAccessible(safenew WindowAccessible(mKey));
281 #endif
282  mKey->SetName(_("Short cut"));
283  }
284  S
285  .ConnectRoot(wxEVT_KEY_DOWN,
287  .ConnectRoot(wxEVT_CHAR,
289  .ConnectRoot(wxEVT_KILL_FOCUS,
291  .ConnectRoot(wxEVT_CONTEXT_MENU,
293  .AddWindow(mKey);
294 
295  /* i18n-hint: (verb)*/
296  mSet = S.Id(SetButtonID).AddButton(XXO("&Set"));
297  /* i18n-hint: (verb)*/
298  mClear = S.Id(ClearButtonID).AddButton(XXO("Cl&ear"));
299  }
300  S.EndThreeColumn();
301 
302 #if defined(__WXMAC__)
303  S.AddFixedText(XO("Note: Pressing Cmd+Q will quit. All other keys are valid."));
304 #endif
305 
306  S.StartThreeColumn();
307  {
308  S.Id(ImportButtonID).AddButton(XXO("&Import..."));
309  S.Id(ExportButtonID).AddButton(XXO("&Export..."));
310  S.Id(AssignDefaultsButtonID).AddButton(XXO("&Defaults"));
311  }
312  S.EndThreeColumn();
313  }
314  S.EndStatic();
315 
316 
317  // Need to layout so that the KeyView is properly sized before populating.
318  // Otherwise, the initial selection is not scrolled into view.
319  Layout();
320 }
321 
323 {
324  TranslatableStrings Labels;
325  TranslatableStrings Categories;
326  TranslatableStrings Prefixes;
327 
328  mNames.clear();
329  mKeys.clear();
330  mDefaultKeys.clear();
331  mStandardDefaultKeys.clear();
333  mNames,
334  mKeys,
335  mDefaultKeys,
336  Labels,
337  Categories,
338  Prefixes,
339  true); // True to include effects (list items), false otherwise.
340 
343 
345  Categories,
346  Prefixes,
347  Labels,
348  mKeys,
349  bSort);
350  //Not needed as NEW nodes are already shown expanded.
351  //mView->ExpandAll();
352 
353  mNewKeys = mKeys;
354 }
355 
356 // RefreshKeyInfo is used to update mKeys vector only
357 // Introduced for efficiency purposes to avoid unnecessary usage of RefreshBinding
359 {
360  mKeys.clear();
361 
362  for (const auto & name : mNames)
363  mKeys.push_back(mManager->GetKeyFromName(name));
364 }
365 
366 // Removes all shortcuts
367 // Doesn't call RefreshBindings()
369 {
370  const NormalizedKeyString noKey{ NO_SHORTCUT };
371  for (const auto & command : mNames)
372  mManager->SetKeyFromName(command, noKey);
373 }
374 
375 // Checks if the given vector of keys contains illegal duplicates.
376 // In case it does, stores the prefixed labels of operations
377 // with illegal key duplicates in fMatching and sMatching.
378 // Search for duplicates fully implemented here
379 // to avoid possible problems with legal shortcut duplicates.
381  TranslatableString & fMatching, TranslatableString & sMatching) const
382 {
383  using IndexesArray = std::vector<int>;
384  std::unordered_map<NormalizedKeyString, IndexesArray> seen;
385 
386  for (size_t i{ 0 }; i < mKeys.size(); i++)
387  {
388  if (mKeys[i] == EMPTY_SHORTCUT || mKeys[i] == NO_SHORTCUT)
389  continue;
390 
391  if (seen.count(mKeys[i]) == 0)
392  seen.insert({ mKeys[i], {(int)i} });
393  else
394  {
395  IndexesArray checkMe{ seen.at(mKeys[i]) };
396  for (int index : checkMe)
397  {
398  if (mDefaultKeys[i] == EMPTY_SHORTCUT ||
399  mDefaultKeys[i] != mDefaultKeys[index])
400  {
401  fMatching = mManager->GetPrefixedLabelFromName(mNames[i]);
402  sMatching = mManager->GetPrefixedLabelFromName(mNames[index]);
403  return true;
404  }
405  else
406  seen.at(mKeys[i]).push_back(index);
407  }
408  }
409  }
410  return false;
411 }
412 
413 
414 // This function tries to add the given shortcuts(keys) "toAdd"
415 // to the already existing shortcuts(keys). Shortcuts are added only if
416 // 1. the shortcut for the operation isn't defined already
417 // 2. the added shortcut doesn't create illegal shortcut duplicate
418 // The names of operations for which the second condition was violated
419 // are returned in a single error message
421  const std::vector<NormalizedKeyString> &toAdd)
422 {
423  TranslatableString disabledShortcuts;
424 
425  auto searchAddInKeys = [&](size_t index)
426  {
427  for (size_t k{ 0 }; k < toAdd.size(); k++)
428  if (k == index)
429  continue;
430  else if (toAdd[index] == mKeys[k] &&
431  (mDefaultKeys[k] == EMPTY_SHORTCUT ||
432  mDefaultKeys[k] != mDefaultKeys[index]))
433  return (int)k;
434 
435  return -1;
436  };
437 
438  const NormalizedKeyString noKey{ EMPTY_SHORTCUT };
439 
440  for (size_t i{ 0 }; i < toAdd.size(); i++)
441  {
442  if (mKeys[i] != NO_SHORTCUT)
443  continue;
444  else if (toAdd[i] == EMPTY_SHORTCUT)
445  mManager->SetKeyFromIndex(i, noKey);
446  else
447  {
448  int sRes{ searchAddInKeys(i) };
449 
450  if (sRes == -1)
451  mManager->SetKeyFromIndex(i, toAdd[i]);
452  else
453  {
455 
456  disabledShortcuts +=
457  XO(
458 "\n * \"%s\" (because the shortcut \'%s\' is used by \"%s\")\n")
459  .Format(
461  name,
463 
464  mManager->SetKeyFromIndex(i, noKey);
465  }
466  }
467  }
468 
469  return disabledShortcuts;
470 }
471 
472 // See bug #2315 for discussion. This should be reviewed
473 // and (possibly) removed after wx3.1.3.
474 void KeyConfigPrefs::OnShow(wxShowEvent & event)
475 {
476  event.Skip();
477 
478  // This is required to prevent a crash if Preferences
479  // were opened without a project.
480  if (event.IsShown() && mView != nullptr)
481  {
482  mView->Refresh();
483  }
484 }
485 
486 void KeyConfigPrefs::OnImport(wxCommandEvent & WXUNUSED(event))
487 {
488  wxString file = wxT("Audacity-keys.xml");
489 
490  file = FileNames::SelectFile(FileNames::Operation::Open,
491  XO("Select an XML file containing Audacity keyboard shortcuts..."),
492  wxEmptyString,
493  file,
494  wxT(""),
496  wxRESIZE_BORDER,
497  this);
498 
499  if (!file) {
500  return;
501  }
502 
503  // this RefreshKeyInfo is here to account for
504  // potential OnSet() function executions before importing
505  RefreshKeyInfo();
506 
507  // saving pre-import settings
508  const std::vector<NormalizedKeyString> oldKeys{ mKeys };
509 
510  // clearing all pre-import settings
511  ClearAllKeys();
512 
513  // getting new settings
514  XMLFileReader reader;
515  if (!reader.Parse(mManager, file)) {
517  reader.GetErrorStr(),
518  XO("Error Importing Keyboard Shortcuts"),
519  wxOK | wxCENTRE,
520  this);
521  }
522 
523  RefreshKeyInfo();
524 
525  // checking new setting for duplicates
526  // if there are duplicates, throwing error and returning to pre-import state
527  TranslatableString fMatching;
528  TranslatableString sMatching;
529 
530  if (ContainsIllegalDups(fMatching, sMatching))
531  {
532  // restore the old pre-import hotkeys stored in oldKeys
533  for (size_t k{ 0 }; k < mNames.size(); k++)
534  mManager->SetKeyFromName(mNames[k], oldKeys[k]);
535  mKeys = oldKeys;
536 
537  // output an error message
539  XO(
540 "The file with the shortcuts contains illegal shortcut duplicates for \"%s\" and \"%s\".\nNothing is imported.")
541  .Format( fMatching, sMatching ),
542  XO("Error Importing Keyboard Shortcuts"),
543  wxICON_ERROR | wxCENTRE, this);
544 
545  // stop the function
546  return;
547  }
548 
549  // adding possible old settings to the new settings and recording the conflicting ones
550  TranslatableString disabledShortcuts{ MergeWithExistingKeys(oldKeys) };
551 
552  RefreshBindings(true);
553 
554  TranslatableString message{
555  XO("Loaded %d keyboard shortcuts\n").Format(mManager->GetNumberOfKeysRead()) };
556 
557  if (disabledShortcuts.Translation() != (""))
558  message += XO("\nThe following commands are not mentioned in the imported file, "
559  "but have their shortcuts removed because of the conflict with other new shortcuts:\n") +
560  disabledShortcuts;
561 
562  AudacityMessageBox(message, XO("Loading Keyboard Shortcuts"), wxOK | wxCENTRE);
563 }
564 
565 void KeyConfigPrefs::OnExport(wxCommandEvent & WXUNUSED(event))
566 {
567  wxString file = wxT("Audacity-keys.xml");
568 
569  file = FileNames::SelectFile(FileNames::Operation::Export,
570  XO("Export Keyboard Shortcuts As:"),
571  wxEmptyString,
572  file,
573  wxT("xml"),
575  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
576  this);
577 
578  if (!file) {
579  return;
580  }
581 
582  GuardedCall( [&] {
583  XMLFileWriter prefFile{ file, XO("Error Exporting Keyboard Shortcuts") };
584  mManager->WriteXML(prefFile);
585  prefFile.Commit();
586  } );
587 }
588 
589 
590 
591 // There currently is only one clickable AButton
592 // so we just do what it needs.
593 void KeyConfigPrefs::OnDefaults(wxCommandEvent & WXUNUSED(event))
594 {
595  wxMenu Menu;
596  Menu.Append( 1, _("Standard") );
597  Menu.Append( 2, _("Full") );
598  Menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &KeyConfigPrefs::OnImportDefaults, this );
599  // Pop it up where the mouse is.
600  PopupMenu(&Menu);//, wxPoint(0, 0));
601 }
602 
603 void KeyConfigPrefs::FilterKeys( std::vector<NormalizedKeyString> & arr )
604 {
605  const auto &MaxListOnly = CommandManager::ExcludedList();
606 
607  // Remove items that are in MaxList.
608  for (size_t i = 0; i < arr.size(); i++) {
609  if( std::binary_search(MaxListOnly.begin(), MaxListOnly.end(), arr[i]) )
610  arr[i] = {};
611  }
612 }
613 
614 void KeyConfigPrefs::OnImportDefaults(wxCommandEvent & event)
615 {
616  gPrefs->DeleteEntry(wxT("/GUI/Shortcuts/FullDefaults"));
617  gPrefs->Flush();
618 
620  if( event.GetId() == 1 )
621  FilterKeys( mNewKeys );
622 
623  for (size_t i = 0; i < mNewKeys.size(); i++) {
625  }
626 
627  RefreshBindings(true);
628 }
629 
631 {
632  wxTextCtrl *t = (wxTextCtrl *)e.GetEventObject();
633 
634  // Make sure we can navigate away from the hotkey textctrl.
635  // On Linux and OSX, it can get stuck, but it doesn't hurt
636  // to do it for Windows as well.
637  //
638  // Mac note: Don't waste time trying to figure out why the
639  // focus goes back to the prefs tree. Unless Voiceover is
640  // active, buttons on the Mac do not accept focus and all the
641  // controls between this one and the tree control are buttons.
642  if (e.GetKeyCode() == WXK_TAB) {
643  t->Navigate(e.ShiftDown()
644  ? wxNavigationKeyEvent::IsBackward
645  : wxNavigationKeyEvent::IsForward);
646  return;
647  }
648 
649  t->SetValue(KeyEventToKeyString(e).Display());
650 }
651 
652 void KeyConfigPrefs::OnHotkeyChar(wxEvent & WXUNUSED(e))
653 {
654  // event.Skip() not performed, so event will not be processed further.
655 }
656 
658 {
659  if (mKey->GetValue().empty() && mCommandSelected != wxNOT_FOUND) {
660  mKey->AppendText(mView->GetKey(mCommandSelected).Display());
661  }
662 
663  e.Skip();
664 }
665 
666 void KeyConfigPrefs::OnHotkeyContext(wxEvent & WXUNUSED(e))
667 {
668  // event.Skip() not performed, so event will not be processed further.
669 }
670 
671 void KeyConfigPrefs::OnFilterTimer(wxTimerEvent & WXUNUSED(e))
672 {
673  // The filter timer has expired, so set the filter
674  if (mFilterPending)
675  {
676  // Do not reset mFilterPending here...possible race
677  mView->SetFilter(mFilter->GetValue());
678  }
679 }
680 
682 {
683  wxTextCtrl *t = (wxTextCtrl *)e.GetEventObject();
684  int keycode = e.GetKeyCode();
685 
686  // Make sure we can navigate away from the hotkey textctrl.
687  // On Linux and OSX, it an get stuck, but it doesn't hurt
688  // to do it for Windows as well.
689  if (keycode == WXK_TAB) {
690  wxNavigationKeyEvent nevent;
691  nevent.SetWindowChange(e.ControlDown());
692  nevent.SetDirection(!e.ShiftDown());
693  nevent.SetEventObject(t);
694  nevent.SetCurrentFocus(t);
695  t->GetParent()->GetEventHandler()->ProcessEvent(nevent);
696 
697  return;
698  }
699 
700  if (mViewType == ViewByKey) {
701  wxString key = KeyEventToKeyString(e).Display();
702  t->SetValue(key);
703 
704  if (!key.empty()) {
705  mView->SetFilter(t->GetValue());
706  }
707  }
708  else
709  {
710  if (keycode == WXK_RETURN) {
711  mFilterPending = false;
712  mView->SetFilter(t->GetValue());
713  }
714  else {
715  mFilterPending = true;
716  mFilterTimer.Start(500, wxTIMER_ONE_SHOT);
717 
718  e.Skip();
719  }
720  }
721 }
722 
724 {
725  if (mViewType != ViewByKey)
726  {
727  e.Skip();
728  }
729 }
730 
731 // Given a hotkey combination, returns the name (description) of the
732 // corresponding command, or the empty string if none is found.
734 {
735  return mView->GetNameByKey(key);
736 }
737 
738 // Sets the selected command to have this key
739 // This is not yet a committed change, which will happen on a save.
741 {
743 
745  {
747  XO("You may not assign a key to this entry"),
748  XO("Error"),
749  wxICON_ERROR | wxCENTRE,
750  this);
751  return;
752  }
753 
756  mNewKeys[ make_iterator_range( mNames ).index( name ) ] = key;
757 }
758 
759 
760 void KeyConfigPrefs::OnSet(wxCommandEvent & WXUNUSED(event))
761 {
762  if (mCommandSelected == wxNOT_FOUND) {
764  XO("You must select a binding before assigning a shortcut"),
765  XO("Error"),
766  wxICON_WARNING | wxCENTRE,
767  this);
768  return;
769  }
770 
771  CommandID newCommand{ mView->GetName(mCommandSelected) };
772  NormalizedKeyString enteredKey{ mKey->GetValue() };
773  NormalizedKeyString newComDefaultKey{
774  mManager->GetDefaultKeyFromName(newCommand) };
775  CommandIDs oldCommands;
776 
777  // collecting commands competing for the same shortcut
778  for (size_t i{ 0 }; i < mNames.size(); i++)
779  {
780  if (mNewKeys[i] == enteredKey)
781  {
782  // ignore the Set button if the same shortcut is used
783  if (mNames[i] == newCommand)
784  return;
785 
786  if (newComDefaultKey == EMPTY_SHORTCUT ||
787  mDefaultKeys[i] != newComDefaultKey)
788  {
789  oldCommands.push_back(mNames[i]);
790  }
791  }
792  }
793 
794  // Prevent same hotkey combination being used twice.
795  if (!oldCommands.empty()) {
796  auto newlabel = Verbatim( wxT("'%s - %s'") )
797  .Format(
798  mManager->GetCategoryFromName(newCommand),
799  mManager->GetPrefixedLabelFromName(newCommand) );
800  auto oldlabel = Verbatim(wxT("'%s - %s'"))
801  .Format(
802  mManager->GetCategoryFromName(oldCommands[0]),
803  mManager->GetPrefixedLabelFromName(oldCommands[0]));
804 
805  for (size_t i{ 1 }; i < oldCommands.size(); i++)
806  oldlabel += XO("\n\n\t and\n\n\t") +
807  Verbatim(wxT("'%s - %s'")).Format(
808  mManager->GetCategoryFromName(oldCommands[i]),
809  mManager->GetPrefixedLabelFromName(oldCommands[i]));
810 
811  if (wxCANCEL == AudacityMessageBox(
812  XO(
813 "The keyboard shortcut '%s' is already assigned to:\n\n\t%s\n\n\nClick OK to assign the shortcut to\n\n\t%s\n\ninstead. Otherwise, click Cancel.")
814  .Format(
815  mKey->GetValue(),
816  oldlabel,
817  newlabel
818  ),
819  XO("Warning"),
820  wxOK | wxCANCEL | wxICON_STOP | wxCENTRE,
821  this))
822  {
823  return;
824  }
825 
826  for (const auto & command : oldCommands)
827  {
828  mView->SetKeyByName(command, {});
829  mManager->SetKeyFromName(command, {});
830  mNewKeys[make_iterator_range(mNames).index(command)] = {};
831  }
832  }
833 
834  SetKeyForSelected(enteredKey);
835 }
836 
837 void KeyConfigPrefs::OnClear(wxCommandEvent& WXUNUSED(event))
838 {
839  mKey->Clear();
840 
841  if (mCommandSelected != wxNOT_FOUND) {
842  SetKeyForSelected({});
843  }
844 }
845 
846 void KeyConfigPrefs::OnSelected(wxCommandEvent & WXUNUSED(e))
847 {
849  mKey->Clear();
850 
851  if (mCommandSelected != wxNOT_FOUND) {
852  bool canset = mView->CanSetKey(mCommandSelected);
853  if (canset) {
854  mKey->AppendText(mView->GetKey(mCommandSelected).Display());
855  }
856 
857  mKey->Enable(canset);
858  mSet->Enable(canset);
859  mClear->Enable(canset);
860  }
861 }
862 
863 void KeyConfigPrefs::OnViewBy(wxCommandEvent & e)
864 {
865  switch (e.GetId())
866  {
867  case ViewByTreeID:
869  mFilterLabel->SetLabel(_("Searc&h:"));
870  break;
871 
872  case ViewByNameID:
874  mFilterLabel->SetLabel(_("Searc&h:"));
875  break;
876 
877  case ViewByKeyID:
879  mFilterLabel->SetLabel(_("&Hotkey:"));
880  break;
881  }
882 
884  mFilter->SetName(wxStripMenuCodes(mFilterLabel->GetLabel()));
885 }
886 
888 {
889  // On the Mac, preferences may be changed without any active
890  // projects. This means that the CommandManager isn't available
891  // either. So we can't attempt to save preferences, otherwise
892  // NULL ptr dereferences will happen in ShuttleGui because the
893  // radio buttons are never created. (See Populate() above.)
894  if ( !mProject ) {
895  return true;
896  }
897 
898  ShuttleGui S(this, eIsSavingToPrefs);
900 
901  bool bFull = gPrefs->ReadBool(wxT("/GUI/Shortcuts/FullDefaults"), false);
902  for (size_t i = 0; i < mNames.size(); i++) {
903  const auto &dkey = bFull ? mDefaultKeys[i] : mStandardDefaultKeys[i];
904  // using GET to interpret CommandID as a config path component
905  auto name = wxT("/NewKeys/") + mNames[i].GET();
906  const auto &key = mNewKeys[i];
907 
908  if (gPrefs->HasEntry(name)) {
909  if (key != NormalizedKeyString{ gPrefs->ReadObject(name, key) } ) {
910  gPrefs->Write(name, key);
911  }
912  if (key == dkey) {
914  }
915  }
916  else {
917  if (key != dkey) {
918  gPrefs->Write(name, key);
919  }
920  }
921  }
922 
923  return gPrefs->Flush();
924 }
925 
927 {
928  // Restore original key values
929  for (size_t i = 0; i < mNames.size(); i++) {
931  }
932 
933  return;
934 }
935 
938 {
939  return [=](wxWindow *parent, wxWindowID winid, AudacityProject *pProject)
940  {
941  wxASSERT(parent); // to justify safenew
942  auto result = safenew KeyConfigPrefs{ parent, winid, pProject, name };
943  return result;
944  };
945 }
946 namespace{
949 };
950 }
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
ShuttleGuiBase::StartRadioButtonGroup
void StartRadioButtonGroup(const ChoiceSetting &Setting)
Call this before any TieRadioButton calls.
Definition: ShuttleGui.cpp:1595
CommandManager::GetAllCommandData
void GetAllCommandData(CommandIDs &names, std::vector< NormalizedKeyString > &keys, std::vector< NormalizedKeyString > &default_keys, TranslatableStrings &labels, TranslatableStrings &categories, bool includeMultis)
Definition: CommandManager.cpp:1384
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
KeyConfigPrefs::OnDefaults
void OnDefaults(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:593
CommandManager::SetKeyFromIndex
void SetKeyFromIndex(int i, const NormalizedKeyString &key)
Definition: CommandManager.cpp:1016
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
ImportButtonID
#define ImportButtonID
Definition: KeyConfigPrefs.cpp:62
ShuttleGuiBase::EndRadioButtonGroup
void EndRadioButtonGroup()
Definition: ShuttleGui.cpp:1612
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
KeyView::RefreshBindings
void RefreshBindings(const CommandIDs &names, const TranslatableStrings &categories, const TranslatableStrings &prefixes, const TranslatableStrings &labels, const std::vector< NormalizedKeyString > &keys, bool bSort)
Definition: KeyView.cpp:636
KeyConfigPrefs::mStandardDefaultKeys
std::vector< NormalizedKeyString > mStandardDefaultKeys
Definition: KeyConfigPrefs.h:103
GuardedCall
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), std::function< void(AudacityException *)> delayedHandler=DefaultDelayedHandlerAction{})
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
Definition: AudacityException.h:202
KeyConfigPrefs::NameFromKey
CommandID NameFromKey(const NormalizedKeyString &key)
Definition: KeyConfigPrefs.cpp:733
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:549
KeyConfigPrefs::OnShow
void OnShow(wxShowEvent &e)
Definition: KeyConfigPrefs.cpp:474
NormalizedKeyString::Display
wxString Display(bool usesSpecialChars=false) const
Definition: Keyboard.cpp:56
KeyConfigPrefs::OnHotkeyKillFocus
void OnHotkeyKillFocus(wxEvent &e)
Definition: KeyConfigPrefs.cpp:657
KeyConfigPrefs::ContainsIllegalDups
bool ContainsIllegalDups(TranslatableString &fMatching, TranslatableString &sMatching) const
Definition: KeyConfigPrefs.cpp:380
ShuttleGuiBase::EndThreeColumn
void EndThreeColumn()
Definition: ShuttleGui.h:369
ExportButtonID
#define ExportButtonID
Definition: KeyConfigPrefs.cpp:61
ShuttleGuiBase::AddTitle
void AddTitle(const TranslatableString &Prompt, int wrapWidth=0)
Centred text string.
Definition: ShuttleGui.cpp:281
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
KeyConfigPrefs::OnExport
void OnExport(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:565
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: TranslatableString.h:295
KeyView::GetName
wxString GetName() const override
Definition: KeyView.cpp:194
FileConfig::HasEntry
virtual bool HasEntry(const wxString &strName) const wxOVERRIDE
Definition: FileConfig.cpp:138
KeyConfigPrefs::Populate
void Populate()
Definition: KeyConfigPrefs.cpp:125
KeyConfigPrefs::mFilterPending
bool mFilterPending
Definition: KeyConfigPrefs.h:89
Format
Abstract base class used in importing a file.
KeyConfigPrefs::OnFilterTimer
void OnFilterTimer(wxTimerEvent &e)
Definition: KeyConfigPrefs.cpp:671
CommandManager::GetPrefixedLabelFromName
TranslatableString GetPrefixedLabelFromName(const CommandID &name)
Definition: CommandManager.cpp:1431
KeyConfigPrefs::OnViewBy
void OnViewBy(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:863
ShuttleGui::AddSpace
wxSizerItem * AddSpace(int width, int height, int prop=0)
Definition: ShuttleGui.cpp:2447
KeyConfigPrefs::GetDescription
TranslatableString GetDescription() override
Definition: KeyConfigPrefs.cpp:115
KeyConfigPrefs::mNames
CommandIDs mNames
Definition: KeyConfigPrefs.h:101
PrefsPanel::Registration
Definition: PrefsPanel.h:84
FileConfig::DeleteEntry
virtual bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty=true) wxOVERRIDE
Definition: FileConfig.cpp:209
XO
#define XO(s)
Definition: Internat.h:31
FileNames::XMLFiles
AUDACITY_DLL_API const FileType XMLFiles
Definition: FileNames.h:77
CommandManager::ExcludedList
static const std::vector< NormalizedKeyString > & ExcludedList()
Definition: CommandManager.cpp:249
PrefsPanel::Factory
std::function< PrefsPanel *(wxWindow *parent, wxWindowID winid, AudacityProject *) > Factory
Definition: PrefsPanel.h:79
FilterID
#define FilterID
Definition: KeyConfigPrefs.cpp:63
CommandManager::GetCategoryFromName
TranslatableString GetCategoryFromName(const CommandID &name)
Definition: CommandManager.cpp:1445
KeyConfigPrefs::mFilterLabel
wxStaticText * mFilterLabel
Definition: KeyConfigPrefs.h:87
KeyView::GetSelected
int GetSelected() const
Definition: KeyView.cpp:185
KeyConfigPrefs::OnSelected
void OnSelected(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:846
FileNames::AllFiles
AUDACITY_DLL_API const FileType AllFiles
Definition: FileNames.h:74
KeyConfigPrefs::mNewKeys
std::vector< NormalizedKeyString > mNewKeys
Definition: KeyConfigPrefs.h:105
CommandManager::GetNumberOfKeysRead
int GetNumberOfKeysRead() const
Definition: CommandManager.cpp:983
KeyConfigPrefs::OnImport
void OnImport(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:486
KeyView::SetKey
bool SetKey(int index, const NormalizedKeyString &key)
Definition: KeyView.cpp:355
ShuttleGuiBase::StartPanel
wxPanel * StartPanel(int iStyle=0)
Definition: ShuttleGui.cpp:990
KeyConfigPrefs::mProject
AudacityProject * mProject
Definition: KeyConfigPrefs.h:96
ShuttleGuiBase::EndPanel
void EndPanel()
Definition: ShuttleGui.cpp:1018
KeyConfigPrefs::Commit
bool Commit() override
Definition: KeyConfigPrefs.cpp:887
KEY_CONFIG_PREFS_PLUGIN_SYMBOL
#define KEY_CONFIG_PREFS_PLUGIN_SYMBOL
Definition: KeyConfigPrefs.h:30
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterfaceSymbol.h:27
KeyConfigPrefs::mKey
wxTextCtrl * mKey
Definition: KeyConfigPrefs.h:82
KeyConfigPrefs::ClearAllKeys
void ClearAllKeys()
Definition: KeyConfigPrefs.cpp:368
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
KeyView::SetKeyByName
bool SetKeyByName(const CommandID &name, const NormalizedKeyString &key)
Definition: KeyView.cpp:396
XMLFileReader::Parse
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
Definition: XMLFileReader.cpp:42
KeyConfigPrefs::FilterKeys
void FilterKeys(std::vector< NormalizedKeyString > &arr)
Definition: KeyConfigPrefs.cpp:603
ViewByKeyID
#define ViewByKeyID
Definition: KeyConfigPrefs.cpp:66
SetButtonID
#define SetButtonID
Definition: KeyConfigPrefs.cpp:58
KeyConfigPrefs::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S) override
Definition: KeyConfigPrefs.cpp:173
CommandIDs
std::vector< CommandID > CommandIDs
Definition: Identifier.h:233
CommandsListID
#define CommandsListID
Definition: KeyConfigPrefs.cpp:60
XXO
#define XXO(s)
Definition: Internat.h:44
KeyConfigPrefs::GetSymbol
ComponentInterfaceSymbol GetSymbol() override
Definition: KeyConfigPrefs.cpp:110
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
XMLFileReader::GetErrorStr
const TranslatableString & GetErrorStr() const
Definition: XMLFileReader.cpp:178
anonymous_namespace{KeyConfigPrefs.cpp}::sAttachment
PrefsPanel::Registration sAttachment
Definition: KeyConfigPrefs.cpp:947
KeyConfigPrefs::HelpPageName
ManualPageID HelpPageName() override
If not empty string, the Help button is added below the panel.
Definition: KeyConfigPrefs.cpp:120
KeyConfigPrefs::mViewByTree
wxRadioButton * mViewByTree
Definition: KeyConfigPrefs.h:92
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
CommandManager::GetKeyFromName
NormalizedKeyString GetKeyFromName(const CommandID &name) const
Definition: CommandManager.cpp:1454
CurrentComboID
#define CurrentComboID
Definition: KeyConfigPrefs.cpp:57
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
ViewByKey
@ ViewByKey
Definition: KeyView.h:64
KeyConfigPrefsFactory
PrefsPanel::Factory KeyConfigPrefsFactory(const CommandID &name)
Definition: KeyConfigPrefs.cpp:937
KeyConfigPrefs::Cancel
void Cancel() override
Definition: KeyConfigPrefs.cpp:926
name
const TranslatableString name
Definition: Distortion.cpp:98
KeyConfigPrefs::OnClear
void OnClear(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:837
KeyView::GetKey
NormalizedKeyString GetKey(int index) const
Definition: KeyView.cpp:322
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
KeyView::GetNameByKey
CommandID GetNameByKey(const NormalizedKeyString &key) const
Definition: KeyView.cpp:282
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
WindowAccessible
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
ViewByTree
@ ViewByTree
Definition: KeyView.h:62
KeyConfigPrefs::mViewByName
wxRadioButton * mViewByName
Definition: KeyConfigPrefs.h:93
ShuttleGuiBase::StartThreeColumn
void StartThreeColumn()
Definition: ShuttleGui.h:368
KeyConfigPrefs::OnFilterKeyDown
void OnFilterKeyDown(wxKeyEvent &e)
Definition: KeyConfigPrefs.cpp:681
KeyConfigPrefs::mFilter
wxTextCtrl * mFilter
Definition: KeyConfigPrefs.h:86
KeyConfigPrefs::mView
KeyView * mView
Definition: KeyConfigPrefs.h:81
NO_SHORTCUT
#define NO_SHORTCUT
Definition: KeyConfigPrefs.cpp:72
ShuttleGui::Prop
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:725
ShuttleGuiBase::AddButton
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:360
Identifier::GET
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
Definition: Identifier.h:66
NormalizedKeyString
Definition: Keyboard.h:25
CommandManager::SetKeyFromName
void SetKeyFromName(const CommandID &name, const NormalizedKeyString &key)
Definition: CommandManager.cpp:1007
KeyConfigPrefs
A PrefsPanel for keybindings.
Definition: KeyConfigPrefs.h:33
ShuttleGuiBase::StartStatic
wxStaticBox * StartStatic(const TranslatableString &Str, int iProp=0)
Definition: ShuttleGui.cpp:893
eIsSavingToPrefs
@ eIsSavingToPrefs
Definition: ShuttleGui.h:48
ViewByName
@ ViewByName
Definition: KeyView.h:63
KeyConfigPrefs::RefreshKeyInfo
void RefreshKeyInfo()
Definition: KeyConfigPrefs.cpp:358
ShuttleGui::Name
ShuttleGui & Name(const TranslatableString &name)
Definition: ShuttleGui.h:663
KeyConfigPrefs::mCommandSelected
int mCommandSelected
Definition: KeyConfigPrefs.h:99
CommandManager::WriteXML
void WriteXML(XMLWriter &xmlFile) const
Definition: CommandManager.cpp:1525
CommandManager::GetDefaultKeyFromName
NormalizedKeyString GetDefaultKeyFromName(const CommandID &name)
Definition: CommandManager.cpp:1465
KeyConfigPrefs::mKeys
std::vector< NormalizedKeyString > mKeys
Definition: KeyConfigPrefs.h:104
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
EMPTY_SHORTCUT
#define EMPTY_SHORTCUT
Definition: KeyConfigPrefs.cpp:70
key
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: CommandManager.cpp:197
XMLFileReader
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:20
FileNames::SelectFile
AUDACITY_DLL_API FilePath SelectFile(Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
ShuttleGui::Position
ShuttleGui & Position(int flags)
Definition: ShuttleGui.h:712
KeyConfigPrefs::mDefaultKeys
std::vector< NormalizedKeyString > mDefaultKeys
Definition: KeyConfigPrefs.h:102
TaggedIdentifier< CommandIdTag, false >
KeyView::SetView
void SetView(ViewByType type)
Definition: KeyView.cpp:414
_
#define _(s)
Definition: Internat.h:75
ShuttleGui::ConnectRoot
auto ConnectRoot(wxEventTypeTag< Tag > eventType, void(Handler::*func)(Argument &)) -> typename std::enable_if< std::is_base_of< Argument, Tag >::value, ShuttleGui & >::type
Definition: ShuttleGui.h:699
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
KeyConfigPrefs::mClear
wxButton * mClear
Definition: KeyConfigPrefs.h:84
XMLFileWriter
Wrapper to output XML data to files.
Definition: XMLWriter.h:81
KeyConfigPrefs::mSet
wxButton * mSet
Definition: KeyConfigPrefs.h:83
KeyConfigPrefs::OnHotkeyChar
void OnHotkeyChar(wxEvent &e)
Definition: KeyConfigPrefs.cpp:652
KeyConfigPrefs::OnSet
void OnSet(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:760
FilterTimerID
#define FilterTimerID
Definition: KeyConfigPrefs.cpp:67
MenuTable::Menu
std::unique_ptr< MenuItem > Menu(const Identifier &internalName, const TranslatableString &title, Args &&... args)
Definition: CommandManager.h:610
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
KeyView
Provides multiple views of keyboard shortcuts.
Definition: KeyView.h:73
KeyConfigPrefs::OnHotkeyContext
void OnHotkeyContext(wxEvent &e)
Definition: KeyConfigPrefs.cpp:666
KeyConfigPrefs::RefreshBindings
void RefreshBindings(bool bSort)
Definition: KeyConfigPrefs.cpp:322
KeyView::SetFilter
void SetFilter(const wxString &filter)
Definition: KeyView.cpp:472
ViewByTreeID
#define ViewByTreeID
Definition: KeyConfigPrefs.cpp:64
KeyEventToKeyString
NormalizedKeyString KeyEventToKeyString(const wxKeyEvent &event)
Definition: Keyboard.cpp:83
PrefsPanel
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
Prefs.h
KeyConfigPrefs::mViewByKey
wxRadioButton * mViewByKey
Definition: KeyConfigPrefs.h:94
ViewByNameID
#define ViewByNameID
Definition: KeyConfigPrefs.cpp:65
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
TranslatableString::Format
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
Definition: TranslatableString.h:103
eIsCreatingFromPrefs
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:47
ShuttleGuiBase::AddVariableText
wxStaticText * AddVariableText(const TranslatableString &Str, bool bCenter=false, int PositionFlags=0, int wrapWidth=0)
Definition: ShuttleGui.cpp:463
KeyConfigPrefs::OnFilterChar
void OnFilterChar(wxEvent &e)
Definition: KeyConfigPrefs.cpp:723
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:203
ShuttleGuiBase::EndStatic
void EndStatic()
Definition: ShuttleGui.cpp:922
KeyConfigPrefs::MergeWithExistingKeys
TranslatableString MergeWithExistingKeys(const std::vector< NormalizedKeyString > &toAdd)
Definition: KeyConfigPrefs.cpp:420
safenew
#define safenew
Definition: MemoryX.h:10
KeyConfigPrefs::SetKeyForSelected
void SetKeyForSelected(const NormalizedKeyString &key)
Definition: KeyConfigPrefs.cpp:740
KeyView::CanSetKey
bool CanSetKey(int index) const
Definition: KeyView.cpp:338
END_EVENT_TABLE
END_EVENT_TABLE()
KeyConfigPrefs::mFilterTimer
wxTimer mFilterTimer
Definition: KeyConfigPrefs.h:88
ClearButtonID
#define ClearButtonID
Definition: KeyConfigPrefs.cpp:59
KeyConfigPrefs.h
KeyConfigPrefs::mManager
CommandManager * mManager
Definition: KeyConfigPrefs.h:98
AssignDefaultsButtonID
#define AssignDefaultsButtonID
Definition: KeyConfigPrefs.cpp:56
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
KeyConfigPrefs::OnImportDefaults
void OnImportDefaults(wxCommandEvent &e)
Definition: KeyConfigPrefs.cpp:614
KeyConfigPrefs::mViewType
ViewByType mViewType
Definition: KeyConfigPrefs.h:91
KeyConfigPrefs::OnHotkeyKeyDown
void OnHotkeyKeyDown(wxKeyEvent &e)
Definition: KeyConfigPrefs.cpp:630