https://git.reactos.org/?p=reactos.git;a=commitdiff;h=91e591b3d590df3c5164e…
commit 91e591b3d590df3c5164ed6f88ac8da389d42cba
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Mar 30 06:50:32 2021 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Mar 30 06:50:32 2021 +0900
[BROWSEUI] Enable AutoAppend of auto-completion (#3552)
Fix and improve Auto-Append of auto-completion. CORE-9281
- Implement CAutoComplete::DoAutoAppend method.
---
dll/win32/browseui/CAutoComplete.cpp | 481 +++++++++++++++++------------------
dll/win32/browseui/CAutoComplete.h | 58 +----
2 files changed, 239 insertions(+), 300 deletions(-)
diff --git a/dll/win32/browseui/CAutoComplete.cpp b/dll/win32/browseui/CAutoComplete.cpp
index b2ebc12ba68..d23b6d5cb78 100644
--- a/dll/win32/browseui/CAutoComplete.cpp
+++ b/dll/win32/browseui/CAutoComplete.cpp
@@ -40,6 +40,35 @@
static HHOOK s_hMouseHook = NULL; // hook handle
static HWND s_hWatchWnd = NULL; // the window handle to watch
+struct PREFIX_INFO
+{
+ LPCWSTR psz;
+ INT cch;
+};
+static const PREFIX_INFO s_prefixes[] =
+{
+ { L"https://", 8 },
+ { L"http://www.", 11 },
+ { L"http://", 7 },
+ { L"www.", 4 },
+};
+
+static inline BOOL DropPrefix(const CStringW& str, CStringW& strBody)
+{
+ for (size_t iPrefix = 0; iPrefix < _countof(s_prefixes); ++iPrefix)
+ {
+ LPCWSTR psz = s_prefixes[iPrefix].psz;
+ INT cch = s_prefixes[iPrefix].cch;
+ if (::StrCmpNIW(str, psz, cch) == 0)
+ {
+ strBody = str.Mid(cch);
+ return TRUE;
+ }
+ }
+ strBody = str;
+ return FALSE;
+}
+
// mouse hook procedure to watch the mouse click
//
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/m…
static LRESULT CALLBACK MouseProc(INT nCode, WPARAM wParam, LPARAM lParam)
@@ -80,33 +109,41 @@ static LRESULT CALLBACK MouseProc(INT nCode, WPARAM wParam, LPARAM
lParam)
typedef CSimpleArray<CStringW> list_t;
-static inline INT pivot(list_t& a, INT i, INT j)
+static inline INT compare1(const CStringW& str1, const CStringW& str2)
+{
+ CStringW s1, s2;
+ DropPrefix(str1, s1);
+ DropPrefix(str2, s2);
+ return s1.CompareNoCase(s2);
+}
+
+static inline INT pivot(list_t& list, INT i, INT j)
{
INT k = i + 1;
- while (k <= j && a[i].CompareNoCase(a[k]) == 0)
+ while (k <= j && compare1(list[i], list[k]) == 0)
k++;
if (k > j)
return -1;
- if (a[i].CompareNoCase(a[k]) >= 0)
+ if (compare1(list[i], list[k]) >= 0)
return i;
return k;
- }
+}
-static inline INT partition(list_t& a, INT i, INT j, const CStringW& x)
+static inline INT partition(list_t& list, INT i, INT j, const CStringW& x)
{
INT left = i, right = j;
while (left <= right)
{
- while (left <= j && a[left].CompareNoCase(x) < 0)
+ while (left <= j && compare1(list[left], x) < 0)
left++;
- while (right >= i && a[right].CompareNoCase(x) >= 0)
+ while (right >= i && compare1(list[right], x) >= 0)
right--;
if (left > right)
break;
- CStringW tmp = a[left];
- a[left] = a[right];
- a[right] = tmp;
+ CStringW tmp = list[left];
+ list[left] = list[right];
+ list[right] = tmp;
left++;
right--;
@@ -114,16 +151,16 @@ static inline INT partition(list_t& a, INT i, INT j, const
CStringW& x)
return left;
}
-static void quicksort(list_t& a, INT i, INT j)
+static void quicksort(list_t& list, INT i, INT j)
{
if (i == j)
return;
- INT p = pivot(a, i, j);
+ INT p = pivot(list, i, j);
if (p == -1)
return;
- INT k = partition(a, i, j, a[p]);
- quicksort(a, i, k - 1);
- quicksort(a, k, j);
+ INT k = partition(list, i, j, list[p]);
+ quicksort(list, i, k - 1);
+ quicksort(list, k, j);
}
static inline void DoSort(list_t& list)
@@ -142,7 +179,7 @@ static INT DoUnique(list_t& list)
INT result = first;
while (++first != last)
{
- if (list[result].CompareNoCase(list[first]) != 0)
+ if (compare1(list[result], list[first]) != 0)
list[++result] = list[first];
}
return ++result;
@@ -158,7 +195,6 @@ static inline void DoUniqueAndTrim(list_t& list)
}
//////////////////////////////////////////////////////////////////////////////
-// CACEditCtrl
// range of WCHAR (inclusive)
struct RANGE
@@ -217,176 +253,103 @@ EditWordBreakProcW(LPWSTR lpch, INT index, INT count, INT code)
{
case WB_ISDELIMITER:
return IsWordBreak(lpch[index]);
-
case WB_LEFT:
+ {
if (index)
--index;
while (index && !IsWordBreak(lpch[index]))
--index;
return index;
-
+ }
case WB_RIGHT:
+ {
if (!count)
break;
while (index < count && lpch[index] &&
!IsWordBreak(lpch[index]))
++index;
return index;
-
- default:
- break;
+ }
}
return 0;
}
-CACEditCtrl::CACEditCtrl() : m_pDropDown(NULL), m_fnOldWordBreakProc(NULL)
+static LRESULT CALLBACK
+EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+ UINT_PTR uSubclassID, DWORD_PTR dwData)
{
+ CAutoComplete *pThis = reinterpret_cast<CAutoComplete *>(dwData);
+ return pThis->EditWndProc(hwnd, uMsg, wParam, lParam);
}
-VOID CACEditCtrl::HookWordBreakProc(BOOL bHook)
+LRESULT CAutoComplete::EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- if (bHook)
+ LRESULT ret;
+ HWND hwndGotFocus;
+ switch (uMsg)
{
- m_fnOldWordBreakProc = reinterpret_cast<EDITWORDBREAKPROCW>(
- SendMessageW(EM_SETWORDBREAKPROC, 0,
- reinterpret_cast<LPARAM>(EditWordBreakProcW)));
- }
- else
- {
- SendMessageW(EM_SETWORDBREAKPROC, 0,
- reinterpret_cast<LPARAM>(m_fnOldWordBreakProc));
- }
-}
-
-// WM_CHAR
-// This message is posted to the window with the keyboard focus when WM_KEYDOWN is
translated.
-LRESULT CACEditCtrl::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
-{
- TRACE("CACEditCtrl::OnChar(%p, %p)\n", this, wParam);
- ATLASSERT(m_pDropDown);
- return m_pDropDown->OnEditChar(wParam, lParam);
-}
-
-// WM_CUT / WM_PASTE / WM_CLEAR @implemented
-LRESULT CACEditCtrl::OnCutPasteClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnCutPasteClear(%p)\n", this);
- ATLASSERT(m_pDropDown);
- LRESULT ret = DefWindowProcW(uMsg, wParam, lParam); // do default
- m_pDropDown->OnEditUpdate(TRUE);
- return ret;
-}
-
-// WM_DESTROY
-// This message is sent when a window is being destroyed.
-LRESULT CACEditCtrl::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnDestroy(%p)\n", this);
- ATLASSERT(m_pDropDown);
- CAutoComplete *pDropDown = m_pDropDown;
-
- // unhook word break procedure
- HookWordBreakProc(FALSE);
-
- // unsubclass because we don't watch any more
- HWND hwndEdit = UnsubclassWindow();
-
- // close the drop-down window
- if (pDropDown)
- {
- pDropDown->PostMessageW(WM_CLOSE, 0, 0);
- }
-
- return ::DefWindowProcW(hwndEdit, uMsg, wParam, lParam); // do default
-}
-
-// WM_GETDLGCODE
-// By responding to this message, an application can take control of a particular type
of
-// input and process the input itself.
-LRESULT CACEditCtrl::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnGetDlgCode(%p)\n", this);
- ATLASSERT(m_pDropDown);
-
- LRESULT ret = DefWindowProcW(uMsg, wParam, lParam); // get default
-
- if (m_pDropDown)
- {
- // some special keys need default processing. we handle them here
- switch (wParam)
- {
- case VK_RETURN:
- if (m_pDropDown->IsWindowVisible() || ::GetKeyState(VK_CONTROL) <
0)
- m_pDropDown->OnEditKeyDown(VK_RETURN, 0);
- break;
- case VK_TAB:
- if (m_pDropDown->IsWindowVisible() &&
m_pDropDown->UseTab())
- ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
- break;
- case VK_ESCAPE:
- if (m_pDropDown->IsWindowVisible())
+ case WM_CHAR:
+ return OnEditChar(wParam, lParam);
+ case WM_CUT: case WM_PASTE: case WM_CLEAR:
+ ret = ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
+ OnEditUpdate(TRUE);
+ return ret;
+ case WM_GETDLGCODE:
+ ret = ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
+ // some special keys need default processing. we handle them here
+ switch (wParam)
+ {
+ case VK_RETURN:
+ if (IsWindowVisible() || ::GetKeyState(VK_CONTROL) < 0)
+ OnEditKeyDown(VK_RETURN, 0);
+ break;
+ case VK_TAB:
+ if (IsWindowVisible() && UseTab())
+ ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the
list
+ break;
+ case VK_ESCAPE:
+ if (IsWindowVisible())
+ ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the
list
+ break;
+ default:
+ {
ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
- break;
- default:
+ break;
+ }
+ }
+ return ret;
+ case WM_KEYDOWN:
+ if (OnEditKeyDown(wParam, lParam))
+ return TRUE; // eat
+ break;
+ case WM_SETFOCUS:
+ break;
+ case WM_KILLFOCUS:
+ // hide the list if lost focus
+ hwndGotFocus = (HWND)wParam;
+ if (hwndGotFocus != m_hwndEdit && hwndGotFocus != m_hWnd)
+ HideDropDown();
+ break;
+ case WM_SETTEXT:
+ if (!m_bInSetText)
+ HideDropDown(); // it's mechanical WM_SETTEXT
+ break;
+ case WM_DESTROY:
+ {
+ if (m_fnOldWordBreakProc)
{
- ret |= DLGC_WANTALLKEYS; // we want all keys to manipulate the list
- break;
+ ::SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
reinterpret_cast<LPARAM>(m_fnOldWordBreakProc));
+ m_fnOldWordBreakProc = NULL;
}
+ ::RemoveWindowSubclass(hwnd, EditSubclassProc, 0);
+ if (::IsWindow(m_hWnd))
+ PostMessageW(WM_CLOSE, 0, 0);
+ // remove reference to m_hwndEdit
+ Release();
+ break;
}
}
- return ret;
-}
-
-// WM_KEYDOWN
-// This message is posted to the window with the keyboard focus when a non-system key is
pressed.
-LRESULT CACEditCtrl::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnKeyDown(%p, %p)\n", this, wParam);
- ATLASSERT(m_pDropDown);
- if (m_pDropDown->OnEditKeyDown(wParam, lParam))
- return 1; // eat
- bHandled = FALSE; // do default
- return 0;
-}
-
-// WM_KILLFOCUS @implemented
-// This message is sent to a window immediately before it loses the keyboard focus.
-LRESULT CACEditCtrl::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnKillFocus(%p)\n", this);
- ATLASSERT(m_pDropDown);
-
- // hide the list if lost focus
- HWND hwndGotFocus = (HWND)wParam;
- if (hwndGotFocus != m_hWnd && hwndGotFocus != m_pDropDown->m_hWnd)
- {
- m_pDropDown->HideDropDown();
- }
-
- bHandled = FALSE; // do default
- return 0;
-}
-
-// WM_SETFOCUS
-// This message is sent to a window after it has gained the keyboard focus.
-LRESULT CACEditCtrl::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnSetFocus(%p)\n", this);
- ATLASSERT(m_pDropDown);
- bHandled = FALSE; // do default
- return 0;
-}
-
-// WM_SETTEXT
-// An application sends this message to set the text of a window.
-LRESULT CACEditCtrl::OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
-{
- TRACE("CACEditCtrl::OnSetText(%p)\n", this);
- ATLASSERT(m_pDropDown);
- if (!m_pDropDown->m_bInSetText)
- m_pDropDown->HideDropDown(); // it's mechanical WM_SETTEXT
- bHandled = FALSE; // do default
- return 0;
+ return ::DefSubclassProc(hwnd, uMsg, wParam, lParam); // do default
}
//////////////////////////////////////////////////////////////////////////////
@@ -503,7 +466,7 @@ LRESULT CACListView::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL
if (iItem != -1)
{
m_pDropDown->SelectItem(iItem); // select the item
- CString strText = GetItemText(iItem); // get text of item
+ CStringW strText = GetItemText(iItem); // get text of item
m_pDropDown->SetEditText(strText); // set text
m_pDropDown->SetEditSel(0, strText.GetLength()); // select all
m_pDropDown->HideDropDown(); // hide
@@ -545,10 +508,6 @@ LRESULT CACListView::OnNCHitTest(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL &
//////////////////////////////////////////////////////////////////////////////
// CACScrollBar
-CACScrollBar::CACScrollBar() : m_pDropDown(NULL)
-{
-}
-
HWND CACScrollBar::Create(HWND hwndParent)
{
ATLASSERT(m_hWnd == NULL);
@@ -563,10 +522,6 @@ HWND CACScrollBar::Create(HWND hwndParent)
//////////////////////////////////////////////////////////////////////////////
// CACSizeBox
-CACSizeBox::CACSizeBox() : m_pDropDown(NULL), m_bDowner(TRUE), m_bLongList(FALSE)
-{
-}
-
HWND CACSizeBox::Create(HWND hwndParent)
{
ATLASSERT(m_hWnd == NULL);
@@ -684,6 +639,7 @@ CAutoComplete::CAutoComplete()
: m_bInSetText(FALSE), m_bInSelectItem(FALSE)
, m_bDowner(TRUE), m_dwOptions(ACO_AUTOAPPEND | ACO_AUTOSUGGEST)
, m_bEnabled(TRUE), m_hwndCombo(NULL), m_hFont(NULL), m_bResized(FALSE)
+ , m_hwndEdit(NULL), m_fnOldEditProc(NULL), m_fnOldWordBreakProc(NULL)
{
}
@@ -693,7 +649,8 @@ HWND CAutoComplete::CreateDropDown()
DWORD dwStyle = WS_POPUP | /*WS_VISIBLE |*/ WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_BORDER;
DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY;
Create(NULL, NULL, NULL, dwStyle, dwExStyle);
- TRACE("CAutoComplete::CreateDropDown(%p): m_hWnd == %p\n", this, m_hWnd);
+ TRACE("CAutoComplete::CreateDropDown(%p): m_hWnd=%p, m_hwndEdit=%p\n",
+ this, m_hWnd, m_hwndEdit);
return m_hWnd;
}
@@ -705,6 +662,9 @@ CAutoComplete::~CAutoComplete()
::DeleteObject(m_hFont);
m_hFont = NULL;
}
+ // quit holding them
+ m_pEnum.Release();
+ m_pACList.Release();
}
BOOL CAutoComplete::CanAutoSuggest()
@@ -729,6 +689,11 @@ BOOL CAutoComplete::IsComboBoxDropped()
return (BOOL)::SendMessageW(m_hwndCombo, CB_GETDROPPEDSTATE, 0, 0);
}
+BOOL CAutoComplete::FilterPrefixes()
+{
+ return !!(m_dwOptions & ACO_FILTERPREFIXES) && m_bEnabled;
+}
+
INT CAutoComplete::GetItemCount()
{
return m_outerList.GetSize();
@@ -743,20 +708,16 @@ CStringW CAutoComplete::GetItemText(INT iItem)
CStringW CAutoComplete::GetEditText()
{
- BSTR bstrText = NULL;
- CStringW strText;
- if (m_hwndEdit.GetWindowTextW(bstrText))
- {
- strText = bstrText;
- ::SysFreeString(bstrText);
- }
- return strText;
+ WCHAR szText[L_MAX_URL_LENGTH];
+ if (::GetWindowTextW(m_hwndEdit, szText, _countof(szText)))
+ return szText;
+ return L"";
}
VOID CAutoComplete::SetEditText(LPCWSTR pszText)
{
m_bInSetText = TRUE; // don't hide drop-down
- m_hwndEdit.SetWindowTextW(pszText);
+ ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>(pszText));
m_bInSetText = FALSE;
}
@@ -771,7 +732,7 @@ CStringW CAutoComplete::GetStemText()
VOID CAutoComplete::SetEditSel(INT ich0, INT ich1)
{
- m_hwndEdit.SendMessageW(EM_SETSEL, ich0, ich1);
+ ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_SETSEL, ich0, ich1);
}
VOID CAutoComplete::ShowDropDown()
@@ -817,23 +778,52 @@ VOID CAutoComplete::DoAutoAppend()
// get the common string
CStringW strCommon;
+ BOOL bFound = FALSE;
for (INT iItem = 0; iItem < cItems; ++iItem)
{
- const CString& strItem = m_innerList[iItem]; // get the text of the item
+ const CStringW& strItem = m_innerList[iItem]; // get the text of the item
- if (iItem == 0) // the first item
+ CStringW strBody;
+ if (DropPrefix(strItem, strBody) &&
+ ::StrCmpNIW(strBody, strText, strText.GetLength()) == 0)
{
- strCommon = strItem; // store the text
+ if (!bFound)
+ {
+ bFound = TRUE;
+ strCommon = strBody;
+ continue;
+ }
+ for (INT ich = 0; ich < strBody.GetLength(); ++ich)
+ {
+ if (strCommon.GetLength() <= ich)
+ break;
+ if (ChrCmpIW(strCommon[ich], strBody[ich]) != 0)
+ {
+ strCommon = strCommon.Left(ich);
+ break;
+ }
+ }
continue;
}
- for (INT ich = 0; ich < strCommon.GetLength(); ++ich)
+ if (::StrCmpNIW(strItem, strText, strText.GetLength()) == 0)
{
- if (ich < strItem.GetLength() &&
- ::ChrCmpIW(strCommon[ich], strItem[ich]) != 0)
+ if (!bFound)
{
- strCommon = strCommon.Left(ich); // shrink the common string
- break;
+ bFound = TRUE;
+ strCommon = strItem;
+ continue;
+ }
+
+ for (INT ich = 0; ich < strItem.GetLength(); ++ich)
+ {
+ if (strCommon.GetLength() <= ich)
+ break;
+ if (ChrCmpIW(strCommon[ich], strItem[ich]) != 0)
+ {
+ strCommon = strCommon.Left(ich);
+ break;
+ }
}
}
}
@@ -842,13 +832,10 @@ VOID CAutoComplete::DoAutoAppend()
return; // no suggestion
// append suggestion
- INT cchOld = strText.GetLength();
- INT cchAppend = strCommon.GetLength() - cchOld;
- strText += strCommon.Right(cchAppend);
- SetEditText(strText);
+ SetEditText(strCommon);
// select the appended suggestion
- SetEditSel(cchOld, strText.GetLength());
+ SetEditSel(strText.GetLength(), strCommon.GetLength());
}
// go back a word ([Ctrl]+[Backspace])
@@ -856,8 +843,8 @@ VOID CAutoComplete::DoBackWord()
{
// get current selection
INT ich0, ich1;
- m_hwndEdit.SendMessageW(EM_GETSEL, reinterpret_cast<WPARAM>(&ich0),
- reinterpret_cast<LPARAM>(&ich1));
+ ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_GETSEL,
+ reinterpret_cast<WPARAM>(&ich0),
reinterpret_cast<LPARAM>(&ich1));
if (ich0 <= 0 || ich0 != ich1) // there is selection or left-side end
return; // don't do anything
// get text
@@ -870,7 +857,7 @@ VOID CAutoComplete::DoBackWord()
// select range
SetEditSel(ich0, ich1);
// replace selection with empty text (this is actually deletion)
- m_hwndEdit.SendMessageW(EM_REPLACESEL, TRUE, (LPARAM)L"");
+ ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, EM_REPLACESEL, TRUE,
(LPARAM)L"");
}
VOID CAutoComplete::UpdateScrollBar()
@@ -940,7 +927,7 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
}
}
// select all
- INT cch = m_hwndEdit.GetWindowTextLengthW();
+ INT cch = ::CallWindowProcW(m_fnOldEditProc, m_hwndEdit, WM_GETTEXTLENGTH, 0,
0);
SetEditSel(0, cch);
// hide
HideDropDown();
@@ -963,7 +950,7 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
// is suggestion available?
if (!CanAutoSuggest())
return FALSE; // do default
- m_hwndEdit.DefWindowProcW(WM_KEYDOWN, VK_DELETE, 0); // do default
+ ::DefSubclassProc(m_hwndEdit, WM_KEYDOWN, VK_DELETE, 0); // do default
OnEditUpdate(FALSE);
return TRUE; // eat
}
@@ -976,10 +963,6 @@ BOOL CAutoComplete::OnEditKeyDown(WPARAM wParam, LPARAM lParam)
}
break;
}
- default:
- {
- break;
- }
}
return FALSE; // default
}
@@ -989,7 +972,7 @@ LRESULT CAutoComplete::OnEditChar(WPARAM wParam, LPARAM lParam)
TRACE("CACEditCtrl::OnEditChar(%p, %p)\n", this, wParam);
if (wParam == L'\n' || wParam == L'\t')
return 0; // eat
- LRESULT ret = m_hwndEdit.DefWindowProcW(WM_CHAR, wParam, lParam); // do default
+ LRESULT ret = ::DefSubclassProc(m_hwndEdit, WM_CHAR, wParam, lParam); // do default
if (CanAutoSuggest() || CanAutoAppend())
OnEditUpdate(wParam != VK_BACK);
return ret;
@@ -997,7 +980,7 @@ LRESULT CAutoComplete::OnEditChar(WPARAM wParam, LPARAM lParam)
VOID CAutoComplete::OnEditUpdate(BOOL bAppendOK)
{
- CString strText = GetEditText();
+ CStringW strText = GetEditText();
if (m_strText.CompareNoCase(strText) == 0)
{
// no change
@@ -1105,7 +1088,7 @@ BOOL CAutoComplete::OnListUpDown(UINT vk)
// @implemented
STDMETHODIMP CAutoComplete::Enable(BOOL fEnable)
{
- TRACE("(%p)->(%d)\n", this, fEnable);
+ TRACE("(%p)->Enable(%d)\n", this, fEnable);
m_bEnabled = fEnable;
return S_OK;
}
@@ -1114,37 +1097,42 @@ STDMETHODIMP
CAutoComplete::Init(HWND hwndEdit, IUnknown *punkACL,
LPCOLESTR pwszRegKeyPath, LPCOLESTR pwszQuickComplete)
{
- TRACE("(%p)->(0x%08lx, %p, %s, %s)\n",
+ TRACE("(%p)->Init(0x%08lx, %p, %s, %s)\n",
this, hwndEdit, punkACL, debugstr_w(pwszRegKeyPath),
debugstr_w(pwszQuickComplete));
-
// sanity check
if (m_hwndEdit || !punkACL)
- {
- ATLASSERT(0);
return E_FAIL;
- }
-
- // set this pointer to m_hwndEdit
- m_hwndEdit.m_pDropDown = this;
-
+ if (!hwndEdit)
+ return E_INVALIDARG;
// do subclass textbox to watch messages
- m_hwndEdit.SubclassWindow(hwndEdit);
+ m_fnOldEditProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwndEdit,
GWLP_WNDPROC));
+ if (!m_fnOldEditProc)
+ return E_FAIL;
+ if (!::SetWindowSubclass(hwndEdit, EditSubclassProc, 0,
reinterpret_cast<DWORD_PTR>(this)))
+ return E_FAIL;
+ m_hwndEdit = hwndEdit;
+ // add reference to m_hwndEdit
+ AddRef();
// set word break procedure
- m_hwndEdit.HookWordBreakProc(TRUE);
+ m_fnOldWordBreakProc = reinterpret_cast<EDITWORDBREAKPROCW>(
+ ::SendMessageW(m_hwndEdit, EM_SETWORDBREAKPROC, 0,
+ reinterpret_cast<LPARAM>(EditWordBreakProcW)));
// save position
- m_hwndEdit.GetWindowRect(&m_rcEdit);
+ ::GetWindowRect(m_hwndEdit, &m_rcEdit);
// get an IEnumString
ATLASSERT(!m_pEnum);
punkACL->QueryInterface(IID_IEnumString, (VOID **)&m_pEnum);
TRACE("m_pEnum: %p\n", static_cast<void *>(m_pEnum));
+ if (m_pEnum)
+ m_pEnum->AddRef(); // hold not to be freed
// get an IACList
ATLASSERT(!m_pACList);
punkACL->QueryInterface(IID_IACList, (VOID **)&m_pACList);
TRACE("m_pACList: %p\n", static_cast<void *>(m_pACList));
-
- AddRef(); // add reference
+ if (m_pACList)
+ m_pACList->AddRef(); // hold not to be freed
UpdateDropDownState(); // create/hide the drop-down window if necessary
@@ -1238,13 +1226,8 @@ STDMETHODIMP CAutoComplete::ResetEnumerator()
{
FIXME("(%p): stub\n", this);
- HideDropDown();
-
- if (IsWindowVisible())
- {
- OnEditUpdate(FALSE);
- }
-
+ Reset();
+ m_innerList.RemoveAll();
return S_OK;
}
@@ -1305,11 +1288,7 @@ VOID CAutoComplete::UpdateDropDownState()
{
// create the drop-down window if not existed
if (!m_hWnd)
- {
- AddRef();
- if (!CreateDropDown())
- Release();
- }
+ CreateDropDown();
}
else
{
@@ -1424,7 +1403,7 @@ VOID CAutoComplete::RepositionDropDown()
// get m_hwndEdit position
RECT rcEdit;
- m_hwndEdit.GetWindowRect(&rcEdit);
+ ::GetWindowRect(m_hwndEdit, &rcEdit);
INT x = rcEdit.left, y = rcEdit.bottom;
// get list extent
@@ -1572,6 +1551,15 @@ INT CAutoComplete::UpdateOuterList()
{
// is the beginning matched?
const CStringW& strTarget = m_innerList[iItem];
+ CStringW strBody;
+ if (DropPrefix(strTarget, strBody))
+ {
+ if (::StrCmpNIW(strBody, strText, strText.GetLength()) == 0)
+ {
+ m_outerList.Add(strTarget);
+ continue;
+ }
+ }
if (::StrCmpNIW(strTarget, strText, strText.GetLength()) == 0)
{
m_outerList.Add(strTarget);
@@ -1614,13 +1602,11 @@ VOID CAutoComplete::UpdateCompletion(BOOL bAppendOK)
RepositionDropDown();
else
HideDropDown();
- return;
}
if (CanAutoAppend() && bAppendOK) // can we auto-append?
{
DoAutoAppend();
- return;
}
}
@@ -1659,28 +1645,21 @@ LRESULT CAutoComplete::OnCreate(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL &b
m_hFont = reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
m_hwndList.SetFont(m_hFont);
+ // add reference to CAutoComplete::m_hWnd
+ AddRef();
return 0; // success
}
-// WM_DESTROY
-// This message is sent when a window is being destroyed.
-LRESULT CAutoComplete::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
+// WM_NCDESTROY
+LRESULT CAutoComplete::OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
{
- TRACE("CAutoComplete::OnDestroy(%p)\n", this);
+ TRACE("CAutoComplete::OnNCDestroy(%p)\n", this);
// hide
if (IsWindowVisible())
HideDropDown();
- // unsubclass EDIT control
- if (m_hwndEdit)
- {
- m_hwndEdit.HookWordBreakProc(FALSE);
- m_hwndEdit.UnsubclassWindow();
- }
-
// clear CAutoComplete pointers
- m_hwndEdit.m_pDropDown = NULL;
m_hwndList.m_pDropDown = NULL;
m_hwndScrollBar.m_pDropDown = NULL;
m_hwndSizeBox.m_pDropDown = NULL;
@@ -1692,8 +1671,8 @@ LRESULT CAutoComplete::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL &
// clean up
m_hwndCombo = NULL;
+ // remove reference to CAutoComplete::m_hWnd
Release();
-
return 0;
}
@@ -1709,7 +1688,7 @@ LRESULT CAutoComplete::OnExitSizeMove(UINT uMsg, WPARAM wParam,
LPARAM lParam, B
UINT uSWP_ = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED |
SWP_NOACTIVATE;
SetWindowPos(NULL, 0, 0, 0, 0, uSWP_);
- m_hwndEdit.SetFocus(); // restore focus
+ ::SetFocus(m_hwndEdit); // restore focus
return 0;
}
@@ -1943,8 +1922,6 @@ LRESULT CAutoComplete::OnNCHitTest(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL
// This message is sent when the window size is changed.
LRESULT CAutoComplete::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled)
{
- TRACE("CAutoComplete::OnSize(%p)\n", this);
-
// calculate the positions of the controls
CRect rcList, rcScrollBar, rcSizeBox;
CalcRects(m_bDowner, rcList, rcScrollBar, rcSizeBox);
@@ -1974,6 +1951,8 @@ LRESULT CAutoComplete::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOO
BOOL bShow = (BOOL)wParam;
if (bShow)
{
+ if (s_hWatchWnd != m_hWnd && ::IsWindowVisible(s_hWatchWnd))
+ ::ShowWindowAsync(s_hWatchWnd, SW_HIDE);
s_hWatchWnd = m_hWnd; // watch this
// unhook mouse if any
@@ -2034,7 +2013,7 @@ LRESULT CAutoComplete::OnTimer(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL &bH
// m_hwndEdit is moved?
RECT rcEdit;
- m_hwndEdit.GetWindowRect(&rcEdit);
+ ::GetWindowRect(m_hwndEdit, &rcEdit);
if (!::EqualRect(&rcEdit, &m_rcEdit))
{
// if so, hide
diff --git a/dll/win32/browseui/CAutoComplete.h b/dll/win32/browseui/CAutoComplete.h
index eb979baf314..f779fdaf4bf 100644
--- a/dll/win32/browseui/CAutoComplete.h
+++ b/dll/win32/browseui/CAutoComplete.h
@@ -24,53 +24,11 @@
#include "atltypes.h"
#include "rosctrls.h"
-class CACEditCtrl;
class CACListView;
class CACScrollBar;
class CACSizeBox;
class CAutoComplete;
-//////////////////////////////////////////////////////////////////////////////
-// CACEditCtrl --- auto-completion textbox
-
-class CACEditCtrl
- : public CWindowImpl<CACEditCtrl, CWindow, CControlWinTraits>
-{
-public:
- CAutoComplete* m_pDropDown;
- static LPCWSTR GetWndClassName() { return WC_EDITW; }
-
- CACEditCtrl();
- VOID HookWordBreakProc(BOOL bHook);
-
- // message map
- BEGIN_MSG_MAP(CACEditCtrl)
- MESSAGE_HANDLER(WM_CHAR, OnChar)
- MESSAGE_HANDLER(WM_CLEAR, OnCutPasteClear)
- MESSAGE_HANDLER(WM_CUT, OnCutPasteClear)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
- MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
- MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
- MESSAGE_HANDLER(WM_PASTE, OnCutPasteClear)
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
- MESSAGE_HANDLER(WM_SETTEXT, OnSetText)
- END_MSG_MAP()
-
-protected:
- // protected variables
- EDITWORDBREAKPROCW m_fnOldWordBreakProc;
- // message handlers
- LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnCutPasteClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled);
- LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
-};
-
//////////////////////////////////////////////////////////////////////////////
// CACListView --- auto-completion list control
@@ -121,8 +79,7 @@ class CACScrollBar : public CWindowImpl<CACScrollBar>
public:
CAutoComplete* m_pDropDown;
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
-
- CACScrollBar();
+ CACScrollBar() : m_pDropDown(NULL) { }
HWND Create(HWND hwndParent);
protected:
@@ -139,8 +96,7 @@ class CACSizeBox : public CWindowImpl<CACSizeBox>
public:
CAutoComplete* m_pDropDown;
static LPCWSTR GetWndClassName() { return WC_SCROLLBARW; }
-
- CACSizeBox();
+ CACSizeBox() : m_pDropDown(NULL), m_bDowner(TRUE), m_bLongList(FALSE) { }
HWND Create(HWND hwndParent);
VOID SetStatus(BOOL bDowner, BOOL bLongList);
@@ -188,6 +144,7 @@ public:
BOOL CanAutoAppend();
BOOL UseTab();
BOOL IsComboBoxDropped();
+ BOOL FilterPrefixes();
INT GetItemCount();
CStringW GetItemText(INT iItem);
@@ -203,6 +160,7 @@ public:
VOID DoBackWord();
VOID UpdateScrollBar();
+ LRESULT EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnEditChar(WPARAM wParam, LPARAM lParam);
BOOL OnEditKeyDown(WPARAM wParam, LPARAM lParam);
VOID OnEditUpdate(BOOL bAppendOK);
@@ -234,11 +192,13 @@ protected:
HFONT m_hFont; // the font
BOOL m_bResized; // re-sized by size-box?
RECT m_rcEdit; // in screen coordinates, to watch the position
+ HWND m_hwndEdit; // the textbox
+ WNDPROC m_fnOldEditProc; // old textbox procedure
+ EDITWORDBREAKPROCW m_fnOldWordBreakProc;
// The following variables are non-POD:
CStringW m_strText; // internal text (used in selecting item and reverting text)
CStringW m_strStemText; // dirname + '\\'
CStringW m_strQuickComplete; // used for [Ctrl]+[Enter]
- CACEditCtrl m_hwndEdit; // subclassed to watch
CACListView m_hwndList; // this listview is virtual
CACScrollBar m_hwndScrollBar; // scroll bar contol
CACSizeBox m_hwndSizeBox; // the size grip
@@ -259,7 +219,7 @@ protected:
// message map
BEGIN_MSG_MAP(CAutoComplete)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
@@ -276,7 +236,7 @@ protected:
END_MSG_MAP()
// message handlers
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
- LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
&bHandled);