[PATCH v5 3/7] shell32/autocomplete: Redesign the window proc to trigger on key presses instead of key release

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Sep 12 14:42:17 CDT 2018


AutoComplete currently shows up when the user releases a key, which is
wrong. Windows does it when the user presses a key, so use both WM_KEYDOWN
and WM_CHAR and redesign it so that it matches Windows behavior.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Compared to version 4 of the patch, noautoappend and displayall have been
collapsed into one parameter to reduce clutter when calling the function,
since the latter implies the former (uses value 2 since it's only used in
one place at the beginning of the function); to me it's better than seeing
stuff like TRUE, FALSE or TRUE, TRUE (of course can be changed to that,
if needed... just a preference here)

 dlls/shell32/autocomplete.c | 108 ++++++++++++++++++++++++--------------------
 1 file changed, 59 insertions(+), 49 deletions(-)

diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index 63fdf3d..71259af 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -119,10 +119,25 @@ static size_t format_quick_complete(WCHAR *dst, const WCHAR *qc, const WCHAR *st
     return dst - base;
 }
 
-static void autocomplete_text(IAutoCompleteImpl *ac, WCHAR *text, UINT len, HWND hwnd, BOOL displayall)
+static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, BOOL noautoappend)
 {
     HRESULT hr;
-    UINT cpt;
+    WCHAR *text;
+    UINT cpt, size, len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
+
+    if (noautoappend != 2 && len == 0)
+    {
+        if (ac->options & ACO_AUTOSUGGEST)
+            ShowWindow(ac->hwndListBox, SW_HIDE);
+        return;
+    }
+
+    size = len + 1;
+    if (!(text = heap_alloc(size * sizeof(WCHAR))))
+        return;
+    len = SendMessageW(hwnd, WM_GETTEXT, size, (LPARAM)text);
+    if (len + 1 != size)
+        text = heap_realloc(text, (len + 1) * sizeof(WCHAR));
 
     SendMessageW(ac->hwndListBox, LB_RESETCONTENT, 0, 0);
 
@@ -130,9 +145,6 @@ static void autocomplete_text(IAutoCompleteImpl *ac, WCHAR *text, UINT len, HWND
     heap_free(ac->txtbackup);
     ac->txtbackup = text;
 
-    if (!displayall && !len)
-        return;
-
     IEnumString_Reset(ac->enumstr);
     for(cpt = 0;;)
     {
@@ -145,7 +157,7 @@ static void autocomplete_text(IAutoCompleteImpl *ac, WCHAR *text, UINT len, HWND
 
         if (!strncmpiW(text, strs, len))
         {
-            if (cpt == 0 && (ac->options & ACO_AUTOAPPEND))
+            if (cpt == 0 && noautoappend == FALSE)
             {
                 WCHAR buffW[255];
 
@@ -203,9 +215,7 @@ static void destroy_autocomplete_object(IAutoCompleteImpl *ac)
 static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     IAutoCompleteImpl *This = GetPropW(hwnd, autocomplete_propertyW);
-    WCHAR *hwndText;
-    UINT len, size;
-    BOOL displayall = FALSE;
+    LRESULT ret;
 
     if (!This->enabled) return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
 
@@ -221,20 +231,20 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
                 ShowWindow(This->hwndListBox, SW_HIDE);
             }
             return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
-        case WM_KEYUP:
-            len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
-            size = len + 1;
-            if (!(hwndText = heap_alloc(size * sizeof(WCHAR))))
-                return 0;
-            len = SendMessageW(hwnd, WM_GETTEXT, size, (LPARAM)hwndText);
-
+        case WM_KEYDOWN:
             switch(wParam) {
                 case VK_RETURN:
                     /* If quickComplete is set and control is pressed, replace the string */
                     if (This->quickComplete && (GetKeyState(VK_CONTROL) & 0x8000))
                     {
-                        WCHAR *buf;
-                        size_t sz = strlenW(This->quickComplete) + 1 + len;
+                        WCHAR *hwndText, *buf;
+                        size_t sz;
+                        UINT len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
+                        if (!(hwndText = heap_alloc((len + 1) * sizeof(WCHAR))))
+                            return 0;
+                        len = SendMessageW(hwnd, WM_GETTEXT, len + 1, (LPARAM)hwndText);
+                        sz = strlenW(This->quickComplete) + 1 + len;
+
                         if ((buf = heap_alloc(sz * sizeof(WCHAR))))
                         {
                             len = format_quick_complete(buf, This->quickComplete, hwndText, len);
@@ -242,32 +252,35 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
                             SendMessageW(hwnd, EM_SETSEL, 0, len);
                             heap_free(buf);
                         }
+
+                        if (This->options & ACO_AUTOSUGGEST)
+                            ShowWindow(This->hwndListBox, SW_HIDE);
+                        heap_free(hwndText);
+                        return 0;
                     }
 
                     if (This->options & ACO_AUTOSUGGEST)
                         ShowWindow(This->hwndListBox, SW_HIDE);
-                    heap_free(hwndText);
-                    return 0;
-                case VK_LEFT:
-                case VK_RIGHT:
-                    heap_free(hwndText);
-                    return 0;
+                    break;
                 case VK_UP:
                 case VK_DOWN:
-                    /* Two cases here :
-                       - if the listbox is not visible, displays it
-                       with all the entries if the style ACO_UPDOWNKEYDROPSLIST
-                       is present but does not select anything.
+                    /* Two cases here:
+                       - if the listbox is not visible and ACO_UPDOWNKEYDROPSLIST is
+                         set, display it with all the entries, without selecting any
                        - if the listbox is visible, change the selection
                     */
-                    if ( (This->options & (ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST))
-                         && (!IsWindowVisible(This->hwndListBox) && (! *hwndText)) )
+                    if (This->options & ACO_AUTOSUGGEST)
                     {
-                         /* We must display all the entries */
-                         displayall = TRUE;
-                    } else {
-                        heap_free(hwndText);
-                        if (IsWindowVisible(This->hwndListBox)) {
+                        if (!IsWindowVisible(This->hwndListBox))
+                        {
+                            if (This->options & ACO_UPDOWNKEYDROPSLIST)
+                            {
+                                autocomplete_text(This, hwnd, 2);
+                                return 0;
+                            }
+                        }
+                        else
+                        {
                             int count, sel;
 
                             count = SendMessageW(This->hwndListBox, LB_GETCOUNT, 0, 0);
@@ -295,25 +308,22 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
                                 len = strlenW(This->txtbackup);
                                 SendMessageW(hwnd, EM_SETSEL, len, len);
                             }
+                            return 0;
                         }
-                        return 0;
                     }
                     break;
-                case VK_BACK:
                 case VK_DELETE:
-                    if ((! *hwndText) && (This->options & ACO_AUTOSUGGEST)) {
-                        heap_free(hwndText);
-                        ShowWindow(This->hwndListBox, SW_HIDE);
-                        return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
-                    }
-                    break;
+                    ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
+                    autocomplete_text(This, hwnd, TRUE);
+                    return ret;
             }
-
-            if (len + 1 != size)
-                hwndText = heap_realloc(hwndText, (len + 1) * sizeof(WCHAR));
-
-            autocomplete_text(This, hwndText, len, hwnd, displayall);
-            break;
+            return CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
+        case WM_CHAR:
+        case WM_UNICHAR:
+            ret = CallWindowProcW(This->wpOrigEditProc, hwnd, uMsg, wParam, lParam);
+            autocomplete_text(This, hwnd, (wParam < ' ' && wParam != 0x16 /* ^V (paste) */)
+                                          || !(This->options & ACO_AUTOAPPEND));
+            return ret;
         case WM_DESTROY:
         {
             WNDPROC proc = This->wpOrigEditProc;
-- 
1.9.1




More information about the wine-devel mailing list