From b2a983c2bb3b96d011c3d96b1e71b95f21544db2 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 30 Oct 2020 17:10:10 -0700 Subject: [PATCH] Bring back multiple accelerator key bindings Fixes: https://github.com/pcman-bbs/pcman-windows/issues/43 --- BuildMenu/BuildMenu.cpp | 56 ++++++++++++++++++++--------------------- BuildMenu/BuildMenu.h | 9 +++---- Lite/CustomizeDlg.cpp | 46 ++++++++++++++++----------------- Lite/CustomizeDlg.h | 1 - 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/BuildMenu/BuildMenu.cpp b/BuildMenu/BuildMenu.cpp index 30988c9..cda21e7 100644 --- a/BuildMenu/BuildMenu.cpp +++ b/BuildMenu/BuildMenu.cpp @@ -36,12 +36,13 @@ class MenuHotkeyUpdater : public MenuVisitor void VisitMenuItem(CMenu *menu, UINT index) override { UINT cmd = menu->GetMenuItemID(index); - std::optional accel = accel_table_->GetByCmd(cmd); - if (accel) { + std::vector accels = accel_table_->GetByCmd(cmd); + if (!accels.empty()) { + const auto& accel = accels[0]; CString text; menu->GetMenuString(index, text, MF_BYPOSITION); text.Append(_T("\t")); - text.Append(HotkeyToStr(accel->fVirt, accel->key)); + text.Append(HotkeyToStr(accel.fVirt, accel.key)); menu->ModifyMenu(index, MF_BYPOSITION, cmd, text); } } @@ -77,48 +78,47 @@ void TraverseMenuPreorder(HMENU hMenu, MenuVisitor *visitor) void AcceleratorTable::Set(const ACCEL &accel) { - DeleteByCmd(accel.cmd); - DeleteByKey(accel.fVirt, accel.key); + Delete(accel); + key_to_accel_[Key{ accel.fVirt, accel.key }] = accel; cmd_to_accel_.emplace(accel.cmd, accel); - key_to_cmd_.emplace(Key{ accel.fVirt, accel.key }, accel.cmd); } -void AcceleratorTable::DeleteByCmd(WORD cmd) +void AcceleratorTable::Delete(const ACCEL &accel) { - auto it = cmd_to_accel_.find(cmd); - if (it == cmd_to_accel_.end()) { - return; - } - key_to_cmd_.erase(Key{it->second.fVirt, it->second.key}); - cmd_to_accel_.erase(it); -} + Key key = Key{ accel.fVirt, accel.key }; -void AcceleratorTable::DeleteByKey(BYTE fVirt, WORD key) -{ - auto it = key_to_cmd_.find(Key{ fVirt, key }); - if (it == key_to_cmd_.end()) { + auto it = key_to_accel_.find(key); + if (it == key_to_accel_.end()) return; + + auto range = cmd_to_accel_.equal_range(it->second.cmd); + for (auto rt = range.first; rt != range.second; rt++) { + if (key == Key{ rt->second.fVirt, rt->second.key }) { + cmd_to_accel_.erase(rt); + break; + } } - cmd_to_accel_.erase(it->second); - key_to_cmd_.erase(it); + + key_to_accel_.erase(it); } -std::optional AcceleratorTable::GetByCmd(WORD cmd) const +std::vector AcceleratorTable::GetByCmd(WORD cmd) const { - auto it = cmd_to_accel_.find(cmd); - if (it == cmd_to_accel_.end()) { - return std::nullopt; + std::vector accels; + auto range = cmd_to_accel_.equal_range(cmd); + for (auto it = range.first; it != range.second; it++) { + accels.push_back(it->second); } - return it->second; + return accels; } std::optional AcceleratorTable::GetByKey(BYTE fVirt, WORD key) const { - auto it = key_to_cmd_.find(Key{fVirt, key}); - if (it == key_to_cmd_.end()) { + auto it = key_to_accel_.find(Key{fVirt, key}); + if (it == key_to_accel_.end()) { return std::nullopt; } - return cmd_to_accel_.at(it->second); + return it->second; } HACCEL AcceleratorTable::CreateHandle() const diff --git a/BuildMenu/BuildMenu.h b/BuildMenu/BuildMenu.h index c5b26e6..35fc219 100644 --- a/BuildMenu/BuildMenu.h +++ b/BuildMenu/BuildMenu.h @@ -15,9 +15,8 @@ class AcceleratorTable { public: void Set(const ACCEL &accel); - void DeleteByCmd(WORD cmd); - void DeleteByKey(BYTE fVirt, WORD key); - std::optional GetByCmd(WORD cmd) const; + void Delete(const ACCEL &accel); + std::vector GetByCmd(WORD cmd) const; std::optional GetByKey(BYTE fVirt, WORD key) const; HACCEL CreateHandle() const; @@ -30,8 +29,8 @@ class AcceleratorTable { private: using Key = std::pair; - std::map cmd_to_accel_; - std::map key_to_cmd_; + std::multimap cmd_to_accel_; + std::map key_to_accel_; }; class MenuVisitor { diff --git a/Lite/CustomizeDlg.cpp b/Lite/CustomizeDlg.cpp index 068820a..441095a 100644 --- a/Lite/CustomizeDlg.cpp +++ b/Lite/CustomizeDlg.cpp @@ -197,17 +197,27 @@ void CCustomizeDlg::OnApply() void CCustomizeDlg::OnDel() { - int sel = key_list_.GetCurSel(); - if (sel == -1) + auto* menu_item = menu_tree_.GetSelectedItem(); + if (!menu_item) + return; + HotkeyData *data = reinterpret_cast(menu_tree_.GetItemData(menu_item)); + + int key_sel = key_list_.GetCurSel(); + if (key_sel == -1) return; // Confirm deletion. - if (MessageBox(LoadString(IDS_DEL_CONFIRM) , NULL, MB_OKCANCEL | MB_ICONQUESTION) != IDOK) + if (MessageBox(LoadString(IDS_DEL_CONFIRM), NULL, MB_OKCANCEL | MB_ICONQUESTION) != IDOK) return; hkedit_.Reset(); - DeleteHotkeyForID(reinterpret_cast(key_list_.GetItemData(sel))); + std::vector accels = accel_table_.GetByCmd(data->cmd); + if (key_sel >= 0 && key_sel < accels.size()) { + accel_table_.Delete(accels[key_sel]); + } + + UpdateHotkeyDisplay(data); } void CCustomizeDlg::OnSelChanged(NMHDR* pNMHDR, LRESULT* pResult) @@ -250,15 +260,12 @@ void CCustomizeDlg::UpdateHotkeyDisplay(CCustomizeDlg::HotkeyData *data) UpdateTreeItemDisplay(data); - std::optional accel = accel_table_.GetByCmd(data->cmd); - if (accel) { - CString hotkey_text = HotkeyToStr(accel->fVirt, accel->key); - int index = key_list_.AddString(hotkey_text); - key_list_.SetItemData(index, reinterpret_cast(data)); - key_list_.SetCurSel(0); - - hkedit_.SetWindowText(hotkey_text); - text_assigned_to_.SetWindowText(menu_tree_.GetItemText(data->hitem)); + std::vector accels = accel_table_.GetByCmd(data->cmd); + if (!accels.empty()) { + for (const auto& accel : accels) { + CString hotkey_text = HotkeyToStr(accel.fVirt, accel.key); + key_list_.AddString(hotkey_text); + } } else { btn_delete_hotkey_.EnableWindow(false); hkedit_.Reset(); @@ -273,10 +280,10 @@ void CCustomizeDlg::UpdateTreeItemDisplay(CCustomizeDlg::HotkeyData *data) if ((p = text.Find('\t')) != -1) text = text.Left(p); - std::optional accel = accel_table_.GetByCmd(data->cmd); - if (accel) { + std::vector accel = accel_table_.GetByCmd(data->cmd); + if (!accel.empty()) { text += '\t'; - text += HotkeyToStr(accel->fVirt, accel->key); + text += HotkeyToStr(accel[0].fVirt, accel[0].key); } menu_tree_.SetItemText(data->hitem, text); } @@ -310,10 +317,3 @@ CCustomizeDlg::HotkeyData* CCustomizeDlg::HotkeyDataFromKeys(BYTE fVirt, WORD ke } return it->second; } - -// 從所有具有相同 ID (hkdel->id) 的選單項目中,移除和 hkdel 相同的熱鍵 (hkdel->fVirt + hkdel->key) -void CCustomizeDlg::DeleteHotkeyForID(CCustomizeDlg::HotkeyData* hkdel) -{ - accel_table_.DeleteByCmd(hkdel->cmd); - UpdateHotkeyDisplay(hkdel); -} diff --git a/Lite/CustomizeDlg.h b/Lite/CustomizeDlg.h index f2a7fd8..a3894d1 100644 --- a/Lite/CustomizeDlg.h +++ b/Lite/CustomizeDlg.h @@ -75,7 +75,6 @@ class CCustomizeDlg : public CDialog HotkeyData *NewHotkeyData(); void UpdateTreeItemDisplay(HotkeyData *data); void UpdateHotkeyDisplay(HotkeyData *data); - void DeleteHotkeyForID(HotkeyData *hkdel); HotkeyData *HotkeyDataFromKeys(BYTE fVirt, WORD key); void UIWriteAccels(); };