From 5ddf723beaab20cd65553133287f40dc5cbfba10 Mon Sep 17 00:00:00 2001 From: sdottaka Date: Wed, 9 Oct 2024 07:59:23 +0900 Subject: [PATCH] Add One-Hand mice wheel scroll diff and merge (#2435) (5). Alt+Wheel Down and other commands now work not only in the editor but also in other windows. --- Src/DirView.cpp | 3 + Src/LowLevelMouseHook.cpp | 188 ++++++++++++++++++++++++++++++++++++++ Src/LowLevelMouseHook.h | 13 +++ Src/Merge.cpp | 5 + Src/Merge.vcxproj | 2 + Src/MergeEditView.cpp | 133 +-------------------------- Src/MergeEditView.h | 1 - 7 files changed, 213 insertions(+), 132 deletions(-) create mode 100644 Src/LowLevelMouseHook.cpp create mode 100644 Src/LowLevelMouseHook.h diff --git a/Src/DirView.cpp b/Src/DirView.cpp index 57a68e0a7bf..e66b843a5f5 100644 --- a/Src/DirView.cpp +++ b/Src/DirView.cpp @@ -49,6 +49,7 @@ #include "SyntaxColors.h" #include "Shell.h" #include "DirTravel.h" +#include "LowLevelMouseHook.h" #include #include @@ -638,6 +639,8 @@ void CDirView::Redisplay() */ void CDirView::OnContextMenu(CWnd*, CPoint point) { + if (CLowLevelMouseHook::IsRightWheelScrolling()) + return; if (GetListCtrl().GetItemCount() == 0) return; // Make sure window is active diff --git a/Src/LowLevelMouseHook.cpp b/Src/LowLevelMouseHook.cpp new file mode 100644 index 00000000000..693053ab0ff --- /dev/null +++ b/Src/LowLevelMouseHook.cpp @@ -0,0 +1,188 @@ +#include +#include "LowLevelMouseHook.h" + +void CALLBACK CLowLevelMouseHook::TimerProc(HWND unnamedParam1, UINT unnamedParam2, UINT_PTR id, DWORD unnamedParam4HWND) +{ + KillTimer(nullptr, id); + EndMenu(); + m_bIgnoreRBUp = false; +} + +LRESULT CALLBACK CLowLevelMouseHook::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode < 0) + return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); + + if (wParam == WM_RBUTTONDOWN) + { + m_bRButtonDown = true; + } + else if (wParam == WM_RBUTTONUP) + { + m_bRButtonDown = false; + if (m_bIgnoreRBUp) + { + LRESULT result = CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); + SetTimer(nullptr, 0, USER_TIMER_MINIMUM, TimerProc); + return result; + } + } + else if (wParam == WM_MOUSEWHEEL) + { + MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam; + int zDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData); + int nFlags = pMouseStruct->flags; + + if (GetKeyState(VK_MENU) & 0x8000) + { + HWND hwndTarget = GetForegroundWindow(); + // When hold Alt key, use nFlags to check MK_CONTROL MK_SHIFT holding got problem, Use GetKeyState() instead. + const auto bShiftDown = GetKeyState(VK_SHIFT) & 0x8000; + const auto bControlDown = GetKeyState(VK_CONTROL) & 0x8000; + // zDelta > 0 scrool up, < 0 scrool down + if (zDelta > 0) + { + // Check Shift key hold for mice without HWheel function + if (bShiftDown && bControlDown) + { + // Alt+Ctrl+Shift+ScrollUp as Alt+Ctrl+Left + PostMessage(hwndTarget, WM_COMMAND, ID_R2LNEXT, 0); + return 1; + } + else if (bShiftDown) + { + // Alt+Shift+ScrollUp as Alt+Left + PostMessage(hwndTarget, WM_COMMAND, ID_R2L, 0); + return 1; + } + else if (nFlags == 0) + { + // Alt+ScrollUp as Alt+Up + PostMessage(hwndTarget, WM_COMMAND, ID_PREVDIFF, 0); + return 1; + } + } + else if (zDelta < 0) + { + // Check Shift key hold for mice without HWheel function + if (bShiftDown && bControlDown) + { + // Alt+Ctrl+Shift+ScrollDown as Alt+Ctrl+Right + PostMessage(hwndTarget, WM_COMMAND, ID_L2RNEXT, 0); + return 1; + } + else if (bShiftDown) + { + // Alt+Shift+ScrollDown as Alt+Right + PostMessage(hwndTarget, WM_COMMAND, ID_L2R, 0); + return 1; + } + else if (nFlags == 0) + { + // Alt+ScrollDown as Alt+Down + PostMessage(hwndTarget, WM_COMMAND, ID_NEXTDIFF, 0); + return 1; + } + } + } + + // Hold mice right button for One-handed operation + if (m_bRButtonDown) + { + HWND hwndTarget = GetForegroundWindow(); + if (zDelta > 0) + { + // RButton+ScrollUp as Alt+Up + m_bIgnoreRBUp = true; + PostMessage(hwndTarget, WM_COMMAND, ID_PREVDIFF, 0); + return 1; + } + else if (zDelta < 0) + { + // RButton+ScrollDown as Alt+Down + m_bIgnoreRBUp = true; + PostMessage(hwndTarget, WM_COMMAND, ID_NEXTDIFF, 0); + return 1; + } + } + } + else if (wParam == WM_MOUSEHWHEEL) + { + MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam; + int zDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData); + int nFlags = pMouseStruct->flags; + + if (GetKeyState(VK_MENU) & 0x8000) + { + HWND hwndTarget = GetForegroundWindow(); + const auto bControlDown = GetKeyState(VK_CONTROL) & 0x8000; + // zDelta > 0 scrool right, < 0 scrool left + if (zDelta > 0) + { + if (bControlDown) + { + // Alt+Ctrl+HScrollRight as Alt+Ctrl+Right + PostMessage(hwndTarget, WM_COMMAND, ID_L2RNEXT, 0); + return 1; + } + else if (nFlags == 0) + { + // Alt+HScrollRight as Alt+Right + PostMessage(hwndTarget, WM_COMMAND, ID_L2R, 0); + return 1; + } + } + else if (zDelta < 0) + { + if (bControlDown) + { + // Alt+Ctrl+HScrollLeft as Alt+Ctrl+Left + PostMessage(hwndTarget, WM_COMMAND, ID_R2LNEXT, 0); + return 1; + } + else if (nFlags == 0) + { + // Alt+HScrollLeft as Alt+Left + PostMessage(hwndTarget, WM_COMMAND, ID_R2L, 0); + return 1; + } + } + } + + // Hold mice right button for One-handed operation + if (m_bRButtonDown) + { + HWND hwndTarget = GetForegroundWindow(); + if (zDelta > 0) + { + // RButton+ScrollRight as Alt+Right + m_bIgnoreRBUp = true; + PostMessage(hwndTarget, WM_COMMAND, ID_L2R, 0); + return 1; + } + else if (zDelta < 0) + { + // RButton+ScrollLeft as Alt+Left + m_bIgnoreRBUp = true; + PostMessage(hwndTarget, WM_COMMAND, ID_R2L, 0); + return 1; + } + } + } + return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); +} + +void CLowLevelMouseHook::SetMouseHook() +{ + m_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, nullptr, 0); +} + +void CLowLevelMouseHook::UnhookMouseHook() +{ + if (m_hMouseHook) + { + UnhookWindowsHookEx(m_hMouseHook); + m_hMouseHook = nullptr; + } +} + diff --git a/Src/LowLevelMouseHook.h b/Src/LowLevelMouseHook.h new file mode 100644 index 00000000000..1254fc9dd76 --- /dev/null +++ b/Src/LowLevelMouseHook.h @@ -0,0 +1,13 @@ +class CLowLevelMouseHook +{ +public: + static void SetMouseHook(); + static void UnhookMouseHook(); + static bool IsRightWheelScrolling() { return m_bIgnoreRBUp; } +private: + static LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); + static void CALLBACK TimerProc(HWND unnamedParam1, UINT unnamedParam2, UINT_PTR id, DWORD unnamedParam4HWND); + inline static HHOOK m_hMouseHook; + inline static bool m_bIgnoreRBUp; + inline static bool m_bRButtonDown; +}; diff --git a/Src/Merge.cpp b/Src/Merge.cpp index 93c4709cf33..abdb3bf2a7a 100644 --- a/Src/Merge.cpp +++ b/Src/Merge.cpp @@ -64,6 +64,7 @@ #include "RegKey.h" #include "Win_VersionHelper.h" #include "BCMenu.h" +#include "LowLevelMouseHook.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -423,6 +424,8 @@ BOOL CMergeApp::InitInstance() return FALSE; } + CLowLevelMouseHook::SetMouseHook(); + // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) @@ -561,6 +564,8 @@ void CMergeApp::OnAppAbout() */ int CMergeApp::ExitInstance() { + CLowLevelMouseHook::UnhookMouseHook(); + charsets_cleanup(); // Save registry keys if existing WinMerge.reg diff --git a/Src/Merge.vcxproj b/Src/Merge.vcxproj index b8b16e8d6d3..7fc086e5692 100644 --- a/Src/Merge.vcxproj +++ b/Src/Merge.vcxproj @@ -945,6 +945,7 @@ pch.h $(IntDir)$(TargetName)2.pch + @@ -1447,6 +1448,7 @@ + diff --git a/Src/MergeEditView.cpp b/Src/MergeEditView.cpp index 027f59439a6..a499f312f28 100644 --- a/Src/MergeEditView.cpp +++ b/Src/MergeEditView.cpp @@ -33,6 +33,7 @@ #include "Shell.h" #include "SelectPluginDlg.h" #include "Constants.h" +#include "LowLevelMouseHook.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -59,7 +60,6 @@ IMPLEMENT_DYNCREATE(CMergeEditView, CCrystalEditViewEx) CMergeEditView::CMergeEditView() : m_bCurrentLineIsDiff(false) -, m_bIgnoreRBUp(false) , m_nThisPane(0) , m_nThisGroup(0) , m_bDetailView(false) @@ -2869,11 +2869,8 @@ void CMergeEditView::OnUpdateEditReplace(CCmdUI* pCmdUI) */ void CMergeEditView::OnContextMenu(CWnd* pWnd, CPoint point) { - if (m_bIgnoreRBUp) - { - m_bIgnoreRBUp = false; + if (CLowLevelMouseHook::IsRightWheelScrolling()) return; - } CRect rect; GetClientRect(rect); @@ -4268,77 +4265,6 @@ void CMergeEditView::OnUpdateChangeScheme(CCmdUI* pCmdUI) */ BOOL CMergeEditView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { - if (GetKeyState(VK_MENU) & 0x8000) - { - // When hold Alt key, use nFlags to check MK_CONTROL MK_SHIFT holding got problem, Use GetKeyState() instead. - const auto bShiftDown = GetKeyState(VK_SHIFT) & 0x8000; - const auto bControlDown = GetKeyState(VK_CONTROL) & 0x8000; - // zDelta > 0 scrool up, < 0 scrool down - if (zDelta > 0) - { - // Check Shift key hold for mice without HWheel function - if (bShiftDown && bControlDown) - { - // Alt+Ctrl+Shift+ScrollUp as Alt+Ctrl+Left - OnR2LNext(); - return TRUE; - } - else if (bShiftDown) - { - // Alt+Shift+ScrollUp as Alt+Left - OnR2l(); - return TRUE; - } - else if (nFlags == 0) - { - // Alt+ScrollUp as Alt+Up - OnPrevdiff(); - return TRUE; - } - } - else if (zDelta < 0) - { - // Check Shift key hold for mice without HWheel function - if (bShiftDown && bControlDown) - { - // Alt+Ctrl+Shift+ScrollDown as Alt+Ctrl+Right - OnL2RNext(); - return TRUE; - } - else if (bShiftDown) - { - // Alt+Shift+ScrollDown as Alt+Right - OnL2r(); - return TRUE; - } - else if (nFlags == 0) - { - // Alt+ScrollDown as Alt+Down - OnNextdiff(); - return TRUE; - } - } - } - - // Hold mice right button for One-handed operation - if (nFlags == MK_RBUTTON) - { - if (zDelta > 0) - { - // RButton+ScrollUp as Alt+Up - OnPrevdiff(); - m_bIgnoreRBUp = true; - return TRUE; - } - else if (zDelta < 0) - { - // RButton+ScrollDown as Alt+Down - OnNextdiff(); - m_bIgnoreRBUp = true; - return TRUE; - } - } - if ( nFlags == MK_CONTROL ) { short amount = zDelta < 0 ? -1: 1; @@ -4377,61 +4303,6 @@ BOOL CMergeEditView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) */ void CMergeEditView::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) { - if (GetKeyState(VK_MENU) & 0x8000) - { - const auto bControlDown = GetKeyState(VK_CONTROL) & 0x8000; - // zDelta > 0 scrool right, < 0 scrool left - if (zDelta > 0) - { - if (bControlDown) - { - // Alt+Ctrl+HScrollRight as Alt+Ctrl+Right - OnL2RNext(); - return; - } - else if (nFlags == 0) - { - // Alt+HScrollRight as Alt+Right - OnL2r(); - return; - } - } - else if (zDelta < 0) - { - if (bControlDown) - { - // Alt+Ctrl+HScrollLeft as Alt+Ctrl+Left - OnR2LNext(); - return; - } - else if (nFlags == 0) - { - // Alt+HScrollLeft as Alt+Left - OnR2l(); - return; - } - } - } - - // Hold mice right button for One-handed operation - if (nFlags == MK_RBUTTON) - { - if (zDelta > 0) - { - // RButton+ScrollRight as Alt+Right - OnL2r(); - m_bIgnoreRBUp = true; - return; - } - else if (zDelta < 0) - { - // RButton+ScrollLeft as Alt+Left - OnR2l(); - m_bIgnoreRBUp = true; - return; - } - } - SCROLLINFO si = { sizeof SCROLLINFO }; si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; diff --git a/Src/MergeEditView.h b/Src/MergeEditView.h index 4721231da7f..6ecc30ebf00 100644 --- a/Src/MergeEditView.h +++ b/Src/MergeEditView.h @@ -86,7 +86,6 @@ class CMergeEditView : public CGhostTextView COLORSETTINGS m_cachedColors; /**< Cached color settings */ bool m_bCurrentLineIsDiff; /**< `true` if cursor is in diff line */ - bool m_bIgnoreRBUp; // Attributes public: