diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp new file mode 100644 index 00000000..b6706cc2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/mptrack/KeyConfigDlg.cpp @@ -0,0 +1,816 @@ +/* + * KeyConfigDlg.cpp + * ---------------- + * Purpose: Implementation of OpenMPT's keyboard configuration dialog. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "KeyConfigDlg.h" +#include "FileDialog.h" +#include "../soundlib/mod_specifications.h" +#include "../soundlib/MIDIEvents.h" + + +OPENMPT_NAMESPACE_BEGIN + + +//***************************************************************************************// +// CCustEdit: customised CEdit control to catch keypresses. +// (does what CHotKeyCtrl does,but better) +//***************************************************************************************// + +BEGIN_MESSAGE_MAP(CCustEdit, CEdit) + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_MESSAGE(WM_MOD_MIDIMSG, &CCustEdit::OnMidiMsg) +END_MESSAGE_MAP() + + +LRESULT CCustEdit::OnMidiMsg(WPARAM dwMidiDataParam, LPARAM) +{ + if(!m_isFocussed) + return 1; + + uint32 midiData = static_cast<uint32>(dwMidiDataParam); + const auto byte1 = MIDIEvents::GetDataByte1FromEvent(midiData), byte2 = MIDIEvents::GetDataByte2FromEvent(midiData); + switch(MIDIEvents::GetTypeFromEvent(midiData)) + { + case MIDIEvents::evControllerChange: + if(byte2 != 0) + { + SetKey(ModMidi, byte1); + if(!m_isDummy) + m_pOptKeyDlg->OnSetKeyChoice(); + } + break; + + case MIDIEvents::evNoteOn: + case MIDIEvents::evNoteOff: + SetKey(ModMidi, byte1 | 0x80); + if(!m_isDummy) + m_pOptKeyDlg->OnSetKeyChoice(); + break; + } + + return 1; +} + + +BOOL CCustEdit::PreTranslateMessage(MSG *pMsg) +{ + if(pMsg) + { + if(pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) + { + SetKey(CMainFrame::GetInputHandler()->GetModifierMask(), static_cast<UINT>(pMsg->wParam)); + return -1; // Keypress handled, don't pass on message. + } else if(pMsg->message == WM_KEYUP || pMsg->message == WM_SYSKEYUP) + { + //if a key has been released but custom edit box is empty, we have probably just + //navigated into the box with TAB or SHIFT-TAB. No need to set keychoice. + if(code != 0 && !m_isDummy) + m_pOptKeyDlg->OnSetKeyChoice(); + } + } + return CEdit::PreTranslateMessage(pMsg); +} + + +void CCustEdit::SetKey(FlagSet<Modifiers> inMod, UINT inCode) +{ + mod = inMod; + code = inCode; + //Setup display + SetWindowText(KeyCombination::GetKeyText(mod, code)); +} + + +void CCustEdit::OnSetFocus(CWnd *pOldWnd) +{ + CEdit::OnSetFocus(pOldWnd); + // Lock the input handler + CMainFrame::GetInputHandler()->Bypass(true); + // Accept MIDI input + CMainFrame::GetMainFrame()->SetMidiRecordWnd(m_hWnd); + + m_isFocussed = true; +} + + +void CCustEdit::OnKillFocus(CWnd *pNewWnd) +{ + CEdit::OnKillFocus(pNewWnd); + //unlock the input handler + CMainFrame::GetInputHandler()->Bypass(false); + m_isFocussed = false; +} + + +//***************************************************************************************// +// COptionsKeyboard: +// +//***************************************************************************************// + +// Initialisation + +BEGIN_MESSAGE_MAP(COptionsKeyboard, CPropertyPage) + ON_LBN_SELCHANGE(IDC_CHOICECOMBO, &COptionsKeyboard::OnKeyChoiceSelect) + ON_LBN_SELCHANGE(IDC_COMMAND_LIST, &COptionsKeyboard::OnCommandKeySelChanged) + ON_LBN_SELCHANGE(IDC_KEYCATEGORY, &COptionsKeyboard::OnCategorySelChanged) + ON_EN_UPDATE(IDC_CHORDDETECTWAITTIME, &COptionsKeyboard::OnChordWaitTimeChanged) //rewbs.autochord + ON_COMMAND(IDC_DELETE, &COptionsKeyboard::OnDeleteKeyChoice) + ON_COMMAND(IDC_RESTORE, &COptionsKeyboard::OnRestoreKeyChoice) + ON_COMMAND(IDC_LOAD, &COptionsKeyboard::OnLoad) + ON_COMMAND(IDC_SAVE, &COptionsKeyboard::OnSave) + ON_COMMAND(IDC_CHECKKEYDOWN, &COptionsKeyboard::OnCheck) + ON_COMMAND(IDC_CHECKKEYHOLD, &COptionsKeyboard::OnCheck) + ON_COMMAND(IDC_CHECKKEYUP, &COptionsKeyboard::OnCheck) + ON_COMMAND(IDC_NOTESREPEAT, &COptionsKeyboard::OnNotesRepeat) + ON_COMMAND(IDC_NONOTESREPEAT, &COptionsKeyboard::OnNoNotesRepeat) + ON_COMMAND(IDC_CLEARLOG, &COptionsKeyboard::OnClearLog) + ON_COMMAND(IDC_RESTORE_KEYMAP, &COptionsKeyboard::OnRestoreDefaultKeymap) + ON_EN_CHANGE(IDC_FIND, &COptionsKeyboard::OnSearchTermChanged) + ON_EN_CHANGE(IDC_FINDHOTKEY, &COptionsKeyboard::OnFindHotKey) + ON_EN_SETFOCUS(IDC_FINDHOTKEY, &COptionsKeyboard::OnClearHotKey) + ON_WM_DESTROY() +END_MESSAGE_MAP() + +void COptionsKeyboard::DoDataExchange(CDataExchange *pDX) +{ + CPropertyPage::DoDataExchange(pDX); + DDX_Control(pDX, IDC_KEYCATEGORY, m_cmbCategory); + DDX_Control(pDX, IDC_COMMAND_LIST, m_lbnCommandKeys); + DDX_Control(pDX, IDC_CHOICECOMBO, m_cmbKeyChoice); + DDX_Control(pDX, IDC_CHORDDETECTWAITTIME, m_eChordWaitTime);//rewbs.autochord + DDX_Control(pDX, IDC_KEYREPORT, m_eReport); + DDX_Control(pDX, IDC_CUSTHOTKEY, m_eCustHotKey); + DDX_Control(pDX, IDC_FINDHOTKEY, m_eFindHotKey); + DDX_Control(pDX, IDC_CHECKKEYDOWN, m_bKeyDown); + DDX_Control(pDX, IDC_CHECKKEYHOLD, m_bKeyHold); + DDX_Control(pDX, IDC_CHECKKEYUP, m_bKeyUp); + DDX_Control(pDX, IDC_FIND, m_eFind); +} + + +BOOL COptionsKeyboard::OnSetActive() +{ + CMainFrame::m_nLastOptionsPage = OPTIONS_PAGE_KEYBOARD; + return CPropertyPage::OnSetActive(); +} + + + +BOOL COptionsKeyboard::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + m_fullPathName = TrackerSettings::Instance().m_szKbdFile; + + m_localCmdSet = std::make_unique<CCommandSet>(); + m_localCmdSet->Copy(CMainFrame::GetInputHandler()->m_activeCommandSet.get()); + + //Fill category combo and automatically selects first category + DefineCommandCategories(); + for(size_t c = 0; c < commandCategories.size(); c++) + { + if(commandCategories[c].name && !commandCategories[c].commands.empty()) + m_cmbCategory.SetItemData(m_cmbCategory.AddString(commandCategories[c].name), c); + } + m_cmbCategory.SetCurSel(0); + UpdateDialog(); + + m_eCustHotKey.SetParent(m_hWnd, IDC_CUSTHOTKEY, this); + m_eFindHotKey.SetParent(m_hWnd, IDC_FINDHOTKEY, this); + m_eReport.FmtLines(TRUE); + m_eReport.SetWindowText(_T("")); + + m_eChordWaitTime.SetWindowText(mpt::cfmt::val(TrackerSettings::Instance().gnAutoChordWaitTime)); + return TRUE; +} + + +void CommandCategory::AddCommands(CommandID first, CommandID last, bool addSeparatorAtEnd) +{ + int count = last - first + 1, val = first; + commands.insert(commands.end(), count, kcNull); + std::generate(commands.end() - count, commands.end(), [&val] { return static_cast<CommandID>(val++); }); + if(addSeparatorAtEnd) + separators.push_back(last); +} + + +// Filter commands: We only need user to see a select set off commands +// for each category +void COptionsKeyboard::DefineCommandCategories() +{ + { + CommandCategory newCat(_T("Global keys"), kCtxAllContexts); + + newCat.AddCommands(kcStartFile, kcEndFile, true); + newCat.AddCommands(kcStartPlayCommands, kcEndPlayCommands, true); + newCat.AddCommands(kcStartEditCommands, kcEndEditCommands, true); + newCat.AddCommands(kcStartView, kcEndView, true); + newCat.AddCommands(kcStartMisc, kcEndMisc, true); + newCat.commands.push_back(kcDummyShortcut); + + commandCategories.push_back(newCat); + } + + commandCategories.emplace_back(_T(" General [Top]"), kCtxCtrlGeneral); + commandCategories.emplace_back(_T(" General [Bottom]"), kCtxViewGeneral); + commandCategories.emplace_back(_T(" Pattern Editor [Top]"), kCtxCtrlPatterns); + + { + CommandCategory newCat(_T(" Pattern Editor - Order List"), kCtxCtrlOrderlist); + + newCat.AddCommands(kcStartOrderlistCommands, kcEndOrderlistCommands); + newCat.separators.push_back(kcEndOrderlistNavigation); + newCat.separators.push_back(kcEndOrderlistEdit); + newCat.separators.push_back(kcEndOrderlistNum); + + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Quick Channel Settings"), kCtxChannelSettings); + newCat.AddCommands(kcStartChnSettingsCommands, kcEndChnSettingsCommands); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - General"), kCtxViewPatterns); + + newCat.AddCommands(kcStartPlainNavigate, kcEndPlainNavigate, true); + newCat.AddCommands(kcStartJumpSnap, kcEndJumpSnap, true); + newCat.AddCommands(kcStartHomeEnd, kcEndHomeEnd, true); + newCat.AddCommands(kcPrevPattern, kcNextSequence, true); + newCat.AddCommands(kcStartSelect, kcEndSelect, true); + newCat.AddCommands(kcStartPatternClipboard, kcEndPatternClipboard, true); + newCat.AddCommands(kcClearRow, kcInsertWholeRowGlobal, true); + newCat.AddCommands(kcStartChannelKeys, kcEndChannelKeys, true); + newCat.AddCommands(kcBeginTranspose, kcEndTranspose, true); + newCat.AddCommands(kcPatternAmplify, kcPatternShrinkSelection, true); + newCat.AddCommands(kcStartPatternEditMisc, kcEndPatternEditMisc, true); + + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Note Column"), kCtxViewPatternsNote); + + newCat.AddCommands(kcVPStartNotes, kcVPEndNotes, true); + newCat.AddCommands(kcSetOctave0, kcSetOctave9, true); + newCat.AddCommands(kcStartNoteMisc, kcEndNoteMisc); + + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Instrument Column"), kCtxViewPatternsIns); + newCat.AddCommands(kcSetIns0, kcSetIns9); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Volume Column"), kCtxViewPatternsVol); + newCat.AddCommands(kcSetVolumeStart, kcSetVolumeEnd); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Effect Column"), kCtxViewPatternsFX); + newCat.AddCommands(kcSetFXStart, kcSetFXEnd); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Pattern Editor - Effect Parameter Column"), kCtxViewPatternsFXparam); + newCat.AddCommands(kcSetFXParam0, kcSetFXParamF); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Sample [Top]"), kCtxCtrlSamples); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Sample Editor"), kCtxViewSamples); + + newCat.AddCommands(kcStartSampleEditing, kcEndSampleEditing, true); + newCat.AddCommands(kcStartSampleMisc, kcEndSampleMisc, true); + newCat.AddCommands(kcStartSampleCues, kcEndSampleCueGroup); + + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Instrument Editor"), kCtxCtrlInstruments); + newCat.AddCommands(kcStartInstrumentCtrlMisc, kcEndInstrumentCtrlMisc); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Envelope Editor"), kCtxViewInstruments); + newCat.AddCommands(kcStartInstrumentMisc, kcEndInstrumentMisc); + commandCategories.push_back(newCat); + } + + commandCategories.emplace_back(_T(" Comments [Top]"), kCtxCtrlComments); + + { + CommandCategory newCat(_T(" Comments [Bottom]"), kCtxViewComments); + newCat.AddCommands(kcStartCommentsCommands, kcEndCommentsCommands); + commandCategories.push_back(newCat); + } + + { + CommandCategory newCat(_T(" Plugin Editor"), kCtxVSTGUI); + newCat.AddCommands(kcStartVSTGUICommands, kcEndVSTGUICommands); + commandCategories.push_back(newCat); + } +} + + +// Pure GUI methods + +void COptionsKeyboard::UpdateDialog() +{ + OnCategorySelChanged(); // Fills command list and automatically selects first command. + OnCommandKeySelChanged(); // Fills command key choice list for that command and automatically selects first choice. +} + + +void COptionsKeyboard::OnKeyboardChanged() +{ + OnSettingsChanged(); + UpdateDialog(); +} + + +void COptionsKeyboard::OnCategorySelChanged() +{ + int cat = static_cast<int>(m_cmbCategory.GetItemData(m_cmbCategory.GetCurSel())); + + if(cat >= 0 && cat != m_curCategory) + { + // Changed category + UpdateShortcutList(cat); + } +} + + +// Force last active category to be selected in dropdown menu. +void COptionsKeyboard::UpdateCategory() +{ + for(int i = 0; i < m_cmbCategory.GetCount(); i++) + { + if((int)m_cmbCategory.GetItemData(i) == m_curCategory) + { + m_cmbCategory.SetCurSel(i); + break; + } + } +} + +void COptionsKeyboard::OnSearchTermChanged() +{ + CString findString; + m_eFind.GetWindowText(findString); + + if(findString.IsEmpty()) + { + UpdateCategory(); + } + UpdateShortcutList(findString.IsEmpty() ? m_curCategory : -1); +} + + +void COptionsKeyboard::OnFindHotKey() +{ + if(m_eFindHotKey.code == 0) + { + UpdateCategory(); + } + UpdateShortcutList(m_eFindHotKey.code == 0 ? m_curCategory : -1); +} + + +void COptionsKeyboard::OnClearHotKey() +{ + // Focus key search: Clear input + m_eFindHotKey.SetKey(ModNone, 0); +} + + +// Fills command list and automatically selects first command. +void COptionsKeyboard::UpdateShortcutList(int category) +{ + CString findString; + m_eFind.GetWindowText(findString); + findString.MakeLower(); + + const bool searchByName = !findString.IsEmpty(), searchByKey = (m_eFindHotKey.code != 0); + const bool doSearch = (searchByName || searchByKey); + + int firstCat = category, lastCat = category; + if(category == -1) + { + // We will search in all categories + firstCat = 0; + lastCat = static_cast<int>(commandCategories.size()) - 1; + } + + CommandID curCommand = static_cast<CommandID>(m_lbnCommandKeys.GetItemData(m_lbnCommandKeys.GetCurSel())); + m_lbnCommandKeys.ResetContent(); + + for(int cat = firstCat; cat <= lastCat; cat++) + { + // When searching, we also add the category names to the list. + bool addCategoryName = (firstCat != lastCat); + + for(size_t cmd = 0; cmd < commandCategories[cat].commands.size(); cmd++) + { + CommandID com = (CommandID)commandCategories[cat].commands[cmd]; + + CString cmdText = m_localCmdSet->GetCommandText(com); + bool addKey = true; + + if(searchByKey) + { + addKey = false; + int numChoices = m_localCmdSet->GetKeyListSize(com); + for(int choice = 0; choice < numChoices; choice++) + { + const KeyCombination &kc = m_localCmdSet->GetKey(com, choice); + if(kc.KeyCode() == m_eFindHotKey.code && kc.Modifier() == m_eFindHotKey.mod) + { + addKey = true; + break; + } + } + } + if(searchByName && addKey) + { + addKey = (cmdText.MakeLower().Find(findString) >= 0); + } + + if(addKey) + { + m_curCategory = cat; + + if(!m_localCmdSet->isHidden(com)) + { + if(doSearch && addCategoryName) + { + const CString catName = _T("------ ") + commandCategories[cat].name.Trim() + _T(" ------"); + m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString(catName), DWORD_PTR(-1)); + addCategoryName = false; + } + + int item = m_lbnCommandKeys.AddString(m_localCmdSet->GetCommandText(com)); + m_lbnCommandKeys.SetItemData(item, com); + + if(curCommand == com) + { + // Keep selection on previously selected string + m_lbnCommandKeys.SetCurSel(item); + } + } + + if(commandCategories[cat].SeparatorAt(com)) + m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString(_T("------------------------------------------------------")), DWORD_PTR(-1)); + } + } + } + + if(m_lbnCommandKeys.GetCurSel() == -1) + { + m_lbnCommandKeys.SetCurSel(0); + } + OnCommandKeySelChanged(); +} + + +// Fills key choice list and automatically selects first key choice +void COptionsKeyboard::OnCommandKeySelChanged() +{ + const CommandID cmd = static_cast<CommandID>(m_lbnCommandKeys.GetItemData(m_lbnCommandKeys.GetCurSel())); + CString str; + + //Separator + if(cmd == kcNull) + { + m_cmbKeyChoice.SetWindowText(_T("")); + m_cmbKeyChoice.EnableWindow(FALSE); + m_eCustHotKey.SetWindowText(_T("")); + m_eCustHotKey.EnableWindow(FALSE); + m_bKeyDown.SetCheck(0); + m_bKeyDown.EnableWindow(FALSE); + m_bKeyHold.SetCheck(0); + m_bKeyHold.EnableWindow(FALSE); + m_bKeyUp.SetCheck(0); + m_bKeyUp.EnableWindow(FALSE); + m_curCommand = kcNull; + } + + //Fill "choice" list + else if((cmd >= 0) && (cmd != m_curCommand) || m_forceUpdate) // Have we changed command? + { + m_forceUpdate = false; + + m_cmbKeyChoice.EnableWindow(TRUE); + m_eCustHotKey.EnableWindow(TRUE); + m_bKeyDown.EnableWindow(TRUE); + m_bKeyHold.EnableWindow(TRUE); + m_bKeyUp.EnableWindow(TRUE); + + m_curCommand = cmd; + m_curCategory = GetCategoryFromCommandID(cmd); + + m_cmbKeyChoice.ResetContent(); + int numChoices = m_localCmdSet->GetKeyListSize(cmd); + if((cmd < kcNumCommands) && (numChoices > 0)) + { + for(int i = 0; i < numChoices; i++) + { + CString s = MPT_CFORMAT("Choice {} (of {})")(i + 1, numChoices); + m_cmbKeyChoice.SetItemData(m_cmbKeyChoice.AddString(s), i); + } + } + m_cmbKeyChoice.SetItemData(m_cmbKeyChoice.AddString(_T("<new>")), numChoices); + m_cmbKeyChoice.SetCurSel(0); + m_curKeyChoice = -1; + OnKeyChoiceSelect(); + } +} + +//Fills or clears key choice info +void COptionsKeyboard::OnKeyChoiceSelect() +{ + int choice = static_cast<int>(m_cmbKeyChoice.GetItemData(m_cmbKeyChoice.GetCurSel())); + CommandID cmd = m_curCommand; + + //If nothing there, clear + if(cmd == kcNull || choice >= m_localCmdSet->GetKeyListSize(cmd) || choice < 0) + { + m_curKeyChoice = choice; + m_forceUpdate = true; + m_eCustHotKey.SetKey(ModNone, 0); + m_bKeyDown.SetCheck(0); + m_bKeyHold.SetCheck(0); + m_bKeyUp.SetCheck(0); + return; + } + + //else, if changed, Fill + if(choice != m_curKeyChoice || m_forceUpdate) + { + m_curKeyChoice = choice; + m_forceUpdate = false; + KeyCombination kc = m_localCmdSet->GetKey(cmd, choice); + m_eCustHotKey.SetKey(kc.Modifier(), kc.KeyCode()); + + m_bKeyDown.SetCheck((kc.EventType() & kKeyEventDown) ? BST_CHECKED : BST_UNCHECKED); + m_bKeyHold.SetCheck((kc.EventType() & kKeyEventRepeat) ? BST_CHECKED : BST_UNCHECKED); + m_bKeyUp.SetCheck((kc.EventType() & kKeyEventUp) ? BST_CHECKED : BST_UNCHECKED); + } +} + +void COptionsKeyboard::OnChordWaitTimeChanged() +{ + CString s; + UINT val; + m_eChordWaitTime.GetWindowText(s); + val = _tstoi(s); + if(val > 5000) + { + val = 5000; + m_eChordWaitTime.SetWindowText(_T("5000")); + } + OnSettingsChanged(); +} + +// Change handling + +void COptionsKeyboard::OnRestoreKeyChoice() +{ + KeyCombination kc; + CommandID cmd = m_curCommand; + + CInputHandler *ih = CMainFrame::GetInputHandler(); + + // Do nothing if there's nothing to restore + if(cmd == kcNull || m_curKeyChoice < 0 || m_curKeyChoice >= ih->GetKeyListSize(cmd)) + { + ::MessageBeep(MB_ICONWARNING); + return; + } + + // Restore current key combination choice for currently selected command. + kc = ih->m_activeCommandSet->GetKey(cmd, m_curKeyChoice); + m_localCmdSet->Remove(m_curKeyChoice, cmd); + m_localCmdSet->Add(kc, cmd, true, m_curKeyChoice); + + ForceUpdateGUI(); + return; +} + +void COptionsKeyboard::OnDeleteKeyChoice() +{ + CommandID cmd = m_curCommand; + + // Do nothing if there's no key defined for this slot. + if(m_curCommand == kcNull || m_curKeyChoice < 0 || m_curKeyChoice >= m_localCmdSet->GetKeyListSize(cmd)) + { + ::MessageBeep(MB_ICONWARNING); + return; + } + + // Delete current key combination choice for currently selected command. + m_localCmdSet->Remove(m_curKeyChoice, cmd); + + ForceUpdateGUI(); + return; +} + + +void COptionsKeyboard::OnSetKeyChoice() +{ + CommandID cmd = m_curCommand; + if(cmd == kcNull) + { + Reporting::Warning("Invalid slot.", "Invalid key data", this); + return; + } + + FlagSet<KeyEventType> event = kKeyEventNone; + if(m_bKeyDown.GetCheck() != BST_UNCHECKED) + event |= kKeyEventDown; + if(m_bKeyHold.GetCheck() != BST_UNCHECKED) + event |= kKeyEventRepeat; + if(m_bKeyUp.GetCheck() != BST_UNCHECKED) + event |= kKeyEventUp; + + KeyCombination kc((commandCategories[m_curCategory]).id, m_eCustHotKey.mod, m_eCustHotKey.code, event); + //detect invalid input + if(!kc.KeyCode()) + { + Reporting::Warning("You need to say to which key you'd like to map this command to.", "Invalid key data", this); + return; + } + if(!kc.EventType()) + { + ::MessageBeep(MB_ICONWARNING); + kc.EventType(kKeyEventDown); + } + + bool add = true; + std::pair<CommandID, KeyCombination> conflictCmd; + if((conflictCmd = m_localCmdSet->IsConflicting(kc, cmd)).first != kcNull + && conflictCmd.first != cmd + && !m_localCmdSet->IsCrossContextConflict(kc, conflictCmd.second)) + { + ConfirmAnswer delOld = Reporting::Confirm(_T("New shortcut (") + kc.GetKeyText() + _T(") has the same key combination as ") + m_localCmdSet->GetCommandText(conflictCmd.first) + _T(" in ") + conflictCmd.second.GetContextText() + _T(".\nDo you want to delete the other shortcut, only keeping the new one?"), _T("Shortcut Conflict"), true, false, this); + if(delOld == cnfYes) + { + m_localCmdSet->Remove(conflictCmd.second, conflictCmd.first); + } else if(delOld == cnfCancel) + { + // Cancel altogther; restore original choice + add = false; + if(m_curKeyChoice >= 0 && m_curKeyChoice < m_localCmdSet->GetKeyListSize(cmd)) + { + KeyCombination origKc = m_localCmdSet->GetKey(cmd, m_curKeyChoice); + m_eCustHotKey.SetKey(origKc.Modifier(), origKc.KeyCode()); + } else + { + m_eCustHotKey.SetWindowText(_T("")); + } + } + } + + if(add) + { + CString report, reportHistory; + //process valid input + m_localCmdSet->Remove(m_curKeyChoice, cmd); + report = m_localCmdSet->Add(kc, cmd, true, m_curKeyChoice); + + //Update log + m_eReport.GetWindowText(reportHistory); + m_eReport.SetWindowText(report + reportHistory); + ForceUpdateGUI(); + } +} + + +void COptionsKeyboard::OnOK() +{ + CMainFrame::GetInputHandler()->SetNewCommandSet(m_localCmdSet.get()); + + CString cs; + m_eChordWaitTime.GetWindowText(cs); + TrackerSettings::Instance().gnAutoChordWaitTime = _tstoi(cs); + + CPropertyPage::OnOK(); +} + + +void COptionsKeyboard::OnDestroy() +{ + CPropertyPage::OnDestroy(); + m_localCmdSet = nullptr; +} + + +void COptionsKeyboard::OnLoad() +{ + auto dlg = OpenFileDialog() + .DefaultExtension("mkb") + .DefaultFilename(m_fullPathName) + .ExtensionFilter("OpenMPT Key Bindings (*.mkb)|*.mkb||") + .AddPlace(theApp.GetInstallPkgPath() + P_("extraKeymaps")) + .WorkingDirectory(TrackerSettings::Instance().m_szKbdFile); + if(!dlg.Show(this)) + return; + + m_fullPathName = dlg.GetFirstFile(); + m_localCmdSet->LoadFile(m_fullPathName); + ForceUpdateGUI(); +} + + +void COptionsKeyboard::OnSave() +{ + auto dlg = SaveFileDialog() + .DefaultExtension("mkb") + .DefaultFilename(m_fullPathName) + .ExtensionFilter("OpenMPT Key Bindings (*.mkb)|*.mkb||") + .WorkingDirectory(TrackerSettings::Instance().m_szKbdFile); + if(!dlg.Show(this)) + return; + + m_fullPathName = dlg.GetFirstFile(); + m_localCmdSet->SaveFile(m_fullPathName); +} + + +void COptionsKeyboard::OnNotesRepeat() +{ + m_localCmdSet->QuickChange_NotesRepeat(true); + ForceUpdateGUI(); +} + + +void COptionsKeyboard::OnNoNotesRepeat() +{ + m_localCmdSet->QuickChange_NotesRepeat(false); + ForceUpdateGUI(); +} + + +void COptionsKeyboard::ForceUpdateGUI() +{ + m_forceUpdate = true; // m_nCurKeyChoice and m_nCurHotKey haven't changed, yet we still want to update. + int ntmpChoice = m_curKeyChoice; // next call will overwrite m_nCurKeyChoice + OnCommandKeySelChanged(); // update keychoice list + m_cmbKeyChoice.SetCurSel(ntmpChoice); // select fresh keychoice (thus restoring m_nCurKeyChoice) + OnKeyChoiceSelect(); // update key data + OnSettingsChanged(); // Enable "apply" button +} + + +void COptionsKeyboard::OnClearLog() +{ + m_eReport.SetWindowText(_T("")); + ForceUpdateGUI(); +} + + +void COptionsKeyboard::OnRestoreDefaultKeymap() +{ + if(Reporting::Confirm("Discard all custom changes and restore default key configuration?", false, true, this) == cnfYes) + { + m_localCmdSet->LoadDefaultKeymap(); + ForceUpdateGUI(); + } +} + + +int COptionsKeyboard::GetCategoryFromCommandID(CommandID command) const +{ + for(size_t cat = 0; cat < commandCategories.size(); cat++) + { + const auto &cmds = commandCategories[cat].commands; + if(mpt::contains(cmds, command)) + return static_cast<int>(cat); + } + return -1; +} + + +OPENMPT_NAMESPACE_END |