vcl/inc/impdel.hxx           |    6 ++++
 vcl/source/window/window.cxx |    4 ++
 vcl/win/window/salframe.cxx  |   59 ++++++++++++++++++++++++++-----------------
 3 files changed, 46 insertions(+), 23 deletions(-)

New commits:
commit a2dd71feb75d93adf0f0daac899e7476f961ec34
Author:     Mike Kaganski <[email protected]>
AuthorDate: Sat Feb 10 20:01:05 2024 +0600
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sat Feb 10 16:58:11 2024 +0100

    tdf#54169: implement auto-accelerator feature on Windows
    
    Change-Id: I219dfc0c8377628c10e5a19232d19260923bf614
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163215
    Tested-by: Mike Kaganski <[email protected]>
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/vcl/inc/impdel.hxx b/vcl/inc/impdel.hxx
index b387c34a0974..3b9dbb60a45e 100644
--- a/vcl/inc/impdel.hxx
+++ b/vcl/inc/impdel.hxx
@@ -57,6 +57,12 @@ class DeletionListener
            if( m_pNotifier )
                m_pNotifier->addDel( this );
        }
+    DeletionListener(const DeletionListener& rOther)
+    :  m_pNotifier(rOther.m_pNotifier)
+       {
+           if (m_pNotifier)
+               m_pNotifier->addDel(this);
+       }
    ~DeletionListener()
    {
        if( m_pNotifier )
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index 85454316acdf..ec3adaca4674 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -1808,15 +1808,17 @@ void Window::SimulateKeyPress( sal_uInt16 nKeyCode ) 
const
 
 void Window::KeyInput( const KeyEvent& rKEvt )
 {
+#ifndef _WIN32 // On Windows, dialogs react to accelerators  without Alt 
(tdf#157649)
     KeyCode cod = rKEvt.GetKeyCode ();
-    bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel;
 
     // do not respond to accelerators unless Alt or Ctrl is held
     if (cod.GetCode () >= 0x200 && cod.GetCode () <= 0x219)
     {
+        bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel;
         if (autoacc && cod.GetModifier () != KEY_MOD2 && !(cod.GetModifier() & 
KEY_MOD1))
             return;
     }
+#endif
 
     NotifyEvent aNEvt( NotifyEventType::KEYINPUT, this, &rKEvt );
     if ( !CompatNotify( aNEvt ) )
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index ed8f7fddee7a..313ae0ffcf2d 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -301,6 +301,15 @@ static void UpdateDarkMode(HWND hWnd)
     DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
 }
 
+static void UpdateAutoAccel()
+{
+    BOOL bUnderline = FALSE;
+    SystemParametersInfoW(SPI_GETKEYBOARDCUES, 0, &bUnderline, 0);
+
+    ImplSVData* pSVData = ImplGetSVData();
+    pSVData->maNWFData.mbAutoAccel = !bUnderline;
+}
+
 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
                               HWND hWndParent, SalFrameStyleFlags 
nSalFrameStyle )
 {
@@ -3578,7 +3587,7 @@ static bool HandleAltNumPadCode(HWND hWnd, UINT nMsg, 
WPARAM wParam, LPARAM lPar
                 if (!(keyFlags & KF_REPEAT))
                     state.clear();
                 state.started = true;
-                return true;
+                return false; // This must be processed further - e.g., to 
show accelerators
             }
 
             if (!state.started)
@@ -3637,8 +3646,6 @@ static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
     static WPARAM       nDeadChar       = 0;
     static WPARAM       nLastVKChar     = 0;
     static sal_uInt16   nLastChar       = 0;
-    static ModKeyFlags  nLastModKeyCode = ModKeyFlags::NONE;
-    static bool         bWaitForModKeyRelease = false;
     sal_uInt16          nRepeat         = LOWORD( lParam );
     if (nRepeat)
         --nRepeat;
@@ -3774,14 +3781,11 @@ static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
     // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
     else
     {
+        static ModKeyFlags nLastModKeyCode = ModKeyFlags::NONE;
+
         // for shift, control and menu we issue a KeyModChange event
         if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == 
VK_MENU) )
         {
-            SalKeyModEvent aModEvt;
-            aModEvt.mbDown = false; // auto-accelerator feature not supported 
here.
-            aModEvt.mnCode = nModCode;
-            aModEvt.mnModKeyCode = ModKeyFlags::NONE;   // no command events 
will be sent if this member is 0
-
             ModKeyFlags tmpCode = ModKeyFlags::NONE;
             if( GetKeyState( VK_LSHIFT )  & 0x8000 )
                 tmpCode |= ModKeyFlags::LeftShift;
@@ -3796,22 +3800,16 @@ static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
             if( GetKeyState( VK_RMENU )  & 0x8000 )
                 tmpCode |= ModKeyFlags::RightMod2;
 
-            if( tmpCode < nLastModKeyCode )
+            if (tmpCode != nLastModKeyCode)
             {
-                aModEvt.mnModKeyCode = nLastModKeyCode;
-                nLastModKeyCode = ModKeyFlags::NONE;
-                bWaitForModKeyRelease = true;
+                SalKeyModEvent aModEvt;
+                aModEvt.mbDown = nMsg == WM_KEYDOWN || nMsg == WM_SYSKEYDOWN;
+                aModEvt.mnCode = nModCode;
+                aModEvt.mnModKeyCode = tmpCode < nLastModKeyCode ? 
nLastModKeyCode : tmpCode;
+                nLastModKeyCode = tmpCode;
+                return pFrame->CallCallback(SalEvent::KeyModChange, &aModEvt);
             }
-            else
-            {
-                if( !bWaitForModKeyRelease )
-                    nLastModKeyCode = tmpCode;
-            }
-
-            if( tmpCode == ModKeyFlags::NONE )
-                bWaitForModKeyRelease = false;
-
-            return pFrame->CallCallback( SalEvent::KeyModChange, &aModEvt );
+            return false;
         }
         else
         {
@@ -3822,6 +3820,21 @@ static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
             UINT            nCharMsg = WM_CHAR;
             bool            bKeyUp = (nMsg == WM_KEYUP) || (nMsg == 
WM_SYSKEYUP);
 
+            comphelper::ScopeGuard aEndModKeyCodes(
+                [nModCode, pFrame, listener = vcl::DeletionListener(pFrame)]
+                {
+                    if (listener.isDeleted())
+                        return;
+                    // Send SalEvent::KeyModChange, to make sure that this 
window ends special mode
+                    // (e.g., hides mnemonics if auto-accelerator feature is 
active)
+                    SalKeyModEvent aModEvt;
+                    aModEvt.mbDown = false;
+                    aModEvt.mnCode = nModCode;
+                    aModEvt.mnModKeyCode = nLastModKeyCode;
+                    pFrame->CallCallback(SalEvent::KeyModChange, &aModEvt);
+                });
+            if (nLastModKeyCode == ModKeyFlags::NONE)
+                aEndModKeyCodes.dismiss();
             nLastModKeyCode = ModKeyFlags::NONE; // make sure no modkey 
messages are sent if they belong to a hotkey (see above)
             aKeyEvt.mnCharCode = 0;
             aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
@@ -4376,6 +4389,7 @@ static void ImplHandleSettingsChangeMsg(HWND hWnd, UINT 
nMsg, WPARAM /*wParam*/,
         }
         aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
         aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+        UpdateAutoAccel();
         UpdateDarkMode(hWnd);
         GetSalData()->mbThemeChanged = true;
     }
@@ -5782,6 +5796,7 @@ static LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT 
nMsg, WPARAM wParam, LP
         {
             SetWindowPtr( hWnd, pFrame );
 
+            UpdateAutoAccel();
             UpdateDarkMode(hWnd);
 
             // Set HWND already here, as data might be used already

Reply via email to