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

Huw Davies huw at codeweavers.com
Thu Sep 13 05:37:29 CDT 2018


On Wed, Sep 12, 2018 at 10:42:17PM +0300, Gabriel Ivăncescu wrote:
> 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)

Not that it really matters, because this isn't going to go in as it is, but
having noautoappend as a tri-state is fine, except you can't declare it as a
BOOL and use FALSE, TRUE and 2 as its states.  You'd want an enum.

Huw.

> 
>  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