|
|
/* Copyright 1996 Microsoft */
#ifndef _AUTOCOMP_HPP_
#define _AUTOCOMP_HPP_
#include "accdel.h"
// TODO List:
// 1. Convert AutoComplete to be a Free Threaded object and move it and all it's
// lists into MultiApartment model.
// 2. Get thread out of ThreadPool API in shlwapi.dll instead of creating thead our
// selves.
// 3. See if SHWaitForSendMessageThread() will cause a lock if bg thread is in SendMessage().
// If so, make sure the bg loop's hard loop doesn't call SendMessage() in this case without
// first looking for QUIT message.
// WARNING On Usage:
// This object is marked Apartment model and this abuses COM. These are rules
// that need to be followed to prevent bugs. This object will be used within three scopes.
// The first scope is the caller doing: 1a) CoInitialize(), 1b) CoCreateInstance().
// 1c) p->Init(), 1d) p->Release(), 1e) CoUninitialize().
// The second scope is the object doing: 2a) Subclass();AddRef(), 2b) WM_DESTROY;Release();
// 1c) p->Init(), 1d) p->Release(), 1e) CoUninitialize().
// The third scope is the background thread doing: 3a) (in thread proc) CoInitialize(),
// 3b) CoUninitialize().
// This object requires that 1E come after 2B and that should be the only requirement
// for the use of this object.
//
// PRIVATE
//
#define AC_LIST_GROWTH_CONST 50
const WCHAR CH_WILDCARD = L'\1'; // indicates a wildcard search
//
// Debug Flags
//
#define AC_WARNING TF_WARNING + TF_AUTOCOMPLETE
#define AC_ERROR TF_ERROR + TF_AUTOCOMPLETE
#define AC_GENERAL TF_GENERAL + TF_AUTOCOMPLETE
#define AC_FUNC TF_FUNC + TF_AUTOCOMPLETE
// Enable test regkey
#define ALLOW_ALWAYS_DROP_UP
//
// WndProc messages to the dropdown window
//
enum { AM_BUTTONCLICK = WM_APP + 400, AM_UPDATESCROLLPOS, AM_DESTROY };
//
// Flags passed from background thread when the search is completed
enum { SRCH_LIMITREACHED = 0x01, // out of memory or we reached our limit
SRCH_USESORTINDEX = 0x02, // use sort index to order results
};
#define ACO_UNINITIALIZED 0x80000000 // if autocomplete options have not been initialized
//
// PUBLIC
//
HRESULT SHUseDefaultAutoComplete(HWND hwndEdit, IBrowserService * pbs, IN OPTIONAL IAutoComplete2 ** ppac, OUT OPTIONAL IShellService ** ppssACLISF, OUT OPTIONAL BOOL fUseCMDMRU);
// Forward references
class CAutoComplete; class CACString* CreateACString(LPCWSTR pszStr);
//+-------------------------------------------------------------------------
// CACString - Autocomplete string shared by foreground & background threads
//--------------------------------------------------------------------------
class CACString { public: ULONG AddRef(); ULONG Release(); ULONG GetSortIndex() { return m_ulSortIndex; } void SetSortIndex(ULONG ulIndex) { m_ulSortIndex = ulIndex; } LPCWSTR GetStr() const { return m_sz; } LPCWSTR GetStrToCompare() const { return m_sz + m_iIgnore; } int GetLength() const { return m_cChars; } int GetLengthToCompare() const { return m_cChars - m_iIgnore; } const WCHAR& operator [] (int nIndex) const { return m_sz[nIndex]; } operator LPCWSTR() { return m_sz; } BOOL HasPrefix() { return m_iIgnore; } BOOL PrefixLength() { return m_iIgnore; }
// Note, the following compare functions ignore the prefix of the CACString
int CompareSortingIndex(CACString& r); int StrCmpI(LPCWSTR psz) { return ::StrCmpI(m_sz + m_iIgnore, psz); } int StrCmpI(CACString& r) { return ::StrCmpI(m_sz + m_iIgnore, r.m_sz + r.m_iIgnore); } int StrCmpNI(LPCWSTR psz, int cch) { return ::StrCmpNI(m_sz + m_iIgnore, psz, cch); }
protected: friend CACString* CreateACString(LPCWSTR pszStr, int iIgnore, ULONG ulSortIndex);
// Prevent creation on stack
CACString();
LONG m_cRef; // reference count
int m_cChars; // length of string (excluding null)
int m_iIgnore; // # prefix characters to ignore when comparing strings
ULONG m_ulSortIndex; // can be used instead of default alphabetical sorting
WCHAR m_sz[1]; // first character of the string
};
//+-------------------------------------------------------------------------
// CACThread - Autocomplete thread that runs in the background
//--------------------------------------------------------------------------
class CACThread : public IUnknown { public: // *** IUnknown ***
virtual STDMETHODIMP_(ULONG) AddRef(); virtual STDMETHODIMP_(ULONG) Release(); virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
CACThread(CAutoComplete& rAutoComp); virtual ~CACThread();
BOOL Init(IEnumString* pes, IACList* pacl);
void GotFocus(); void LostFocus(); BOOL HasFocus() { return m_fWorkItemQueued != 0; } BOOL StartSearch(LPCWSTR pszSearch, DWORD dwOptions); void StopSearch(); void SyncShutDownBGThread(); BOOL IsDisabled() { return m_fDisabled; }
// Helper functions
static BOOL MatchesSpecialPrefix(LPCWSTR pszSearch); static int GetSpecialPrefixLen(LPCWSTR psz);
protected: LONG m_cRef; CAutoComplete* m_pAutoComp; // portion of autocomplete that runs on main thread
LONG m_fWorkItemQueued; // if request made to shlwapi thread pool
LONG m_idThread; HANDLE m_hCreateEvent; // thread startup syncronizatrion
BOOL m_fDisabled:1; // is autocomplete disabled?
LPWSTR m_pszSearch; // String we are currently searching for
HDPA m_hdpa_list; // list of completions
DWORD m_dwSearchStatus;// see SRCH_* flags
IEnumString* m_pes; // Used internally for real AutoComplete functionality.
IEnumACString* m_peac; // Used with IEnumString to get sort index
IACList* m_pacl; // Additional methods for autocomplete lists (optional).
void _SendAsyncShutDownMsg(BOOL fFinalShutDown); void _FreeThreadData(); HRESULT _ThreadLoop(); HRESULT _Next(LPWSTR szUrl, ULONG cchUrl, ULONG* pulSortIndex); HRESULT _ProcessMessage(MSG * pMsg, DWORD * pdwTimeout, BOOL * pfStayAlive); void _Search(LPWSTR pszSearch, DWORD dwOptions); BOOL _AddToList(LPTSTR pszUrl, int cchMatch, ULONG ulSortIndex); void _DoExpand(LPCWSTR pszSearch); static DWORD WINAPI _ThreadProc(LPVOID lpv); static int CALLBACK _DpaCompare(LPVOID p1, LPVOID p2, LPARAM lParam); };
//+-------------------------------------------------------------------------
// CAutoComplete - Main autocomplete class that runs on the main UI thread
//--------------------------------------------------------------------------
class CAutoComplete : public IAutoComplete2 , public IAutoCompleteDropDown , public IEnumString , public CDelegateAccessibleImpl { public: //////////////////////////////////////////////////////
// Public Interfaces
//////////////////////////////////////////////////////
// *** IUnknown ***
virtual STDMETHODIMP_(ULONG) AddRef(); virtual STDMETHODIMP_(ULONG) Release(); virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
// *** IEnumString ***
virtual STDMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched); virtual STDMETHODIMP Skip(ULONG celt) { return E_NOTIMPL; } virtual STDMETHODIMP Reset(); virtual STDMETHODIMP Clone(IEnumString **ppenum) { return E_NOTIMPL; }
// *** IAutoComplete ***
virtual STDMETHODIMP Init(HWND hwnd, IUnknown *punkACL, LPCOLESTR pwszRegKeyPath, LPCOLESTR pwszQuickCompleteString); virtual STDMETHODIMP Enable(BOOL fEnable);
// *** IAutoComplete2 ***
virtual STDMETHODIMP SetOptions(DWORD dwFlag); virtual STDMETHODIMP GetOptions(DWORD* pdwFlag);
// *** IAutoCompleteDropDown ***
virtual STDMETHODIMP GetDropDownStatus(DWORD *pdwFlags, LPWSTR *ppwszString); virtual STDMETHODIMP ResetEnumerator();
// *** IAccessible ***
STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName);
protected: // Methods called by the background thread
friend CACThread; void SearchComplete(HDPA hdpa, DWORD dwSearchStatus) { PostMessage(m_hwndEdit, m_uMsgSearchComplete, dwSearchStatus, (LPARAM)hdpa); } BOOL IsEnabled();
// Constructor / Destructor (protected so we can't create on stack)
CAutoComplete(); virtual ~CAutoComplete();
// Instance creator
friend HRESULT CAutoComplete_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi); BOOL _Init();
// Private variables
LONG m_cRef;
CACThread* m_pThread; // background autocomplete thread
TCHAR m_szQuickComplete[MAX_PATH]; TCHAR m_szRegKeyPath[MAX_PATH]; DWORD m_dwFlags; HWND m_hwndEdit; HWND m_hwndCombo; // if m_hwndEdit is part of a combobox
HFONT m_hfontListView; LPTSTR m_pszCurrent; int m_iCurrent; DWORD m_dwLastSearchFlags; WNDPROC m_pOldListViewWndProc;
IEnumString * m_pes; // Used internally for real AutoComplete functionality.
IACList * m_pacl; // Additional methods for autocomplete lists (optional).
HDPA m_hdpa; // sorted completions list
HDPA m_hdpaSortIndex; // matches from m_hdpa ordered by sort index
LPWSTR m_pszLastSearch; // string last sent for completion
int m_iFirstMatch; // first match in list (-1 if no matches)
int m_iLastMatch; // last match in list (-1 if no matches)
int m_iAppended; // item completed in the edit box
BITBOOL m_fEditControlUnicode:1; // if the edit control is unicode.
BITBOOL m_fNeedNewList:1; // last search was truncated
BITBOOL m_fDropDownResized:1; // user has resized drop down
BITBOOL m_fAppended:1; // if something currently appended
BITBOOL m_fSearchForAdded:1; // if last item in dpa is "Search for <>"
BITBOOL m_fSearchFor:1; // if "Search for <>" is to be displayed
BITBOOL m_fImeCandidateOpen:1; // if the IME's candidate window is visible
DWORD m_dwOptions; // autocomplete options (ACO_*)
EDITWORDBREAKPROC m_oldEditWordBreakProc; // original word break proc for m_hwndEdit
// Member variables for drop-down auto-suggest window
HWND m_hwndDropDown; // Shows completions in drop-down window
HWND m_hwndList; // Shows completions in drop-down window
HWND m_hwndScroll; // scrollbar
HWND m_hwndGrip; // gripper for resizing the dropdown
int m_nStatusHeight; // height of status in drop-down
int m_nDropWidth; // width of drop-down window
int m_nDropHeight; // height of drop-down window
int m_cxGripper; // width/height of gripper
BITBOOL m_fDroppedUp:1; // if dropdown is over top the edit box
#ifdef ALLOW_ALWAYS_DROP_UP
BITBOOL m_fAlwaysDropUp:1; // TEST regkey to always drop up
#endif
BITBOOL m_fSettingText:1; // if setting the edit text
BITBOOL m_fInHotTracking:1; // if new selection is due to hot-tracking
// Member Variables used for external IEnumString
IEnumString * m_pesExtern; // Used internally for real AutoComplete functionality.
LPTSTR m_szEnumString;
// Registered messages sent to edit window
UINT m_uMsgSearchComplete; UINT m_uMsgItemActivate;
static HHOOK s_hhookMouse; // windows hook installed when drop-down visible
static HWND s_hwndDropDown; // dropdown currently visible
static BOOL s_fNoActivate; // keep topmost-window from losing activation
void _OnSearchComplete(HDPA hdpa, DWORD dwSearchStatus); BOOL _GetItem(int iIndex, LPWSTR pswText, int cchMax, BOOL fDisplayName); void _UpdateCompletion(LPCWSTR pszTyped, int iChanged, BOOL fAppend); void _HideDropDown(); void _ShowDropDown(); void _PositionDropDown(); void _SeeWhatsEnabled(); BOOL _IsAutoSuggestEnabled() { return m_dwOptions & ACO_AUTOSUGGEST; } BOOL _IsRTLReadingEnabled() { return m_dwOptions & ACO_RTLREADING; } BOOL _IsAutoAppendEnabled() { return (m_dwOptions & ACO_AUTOAPPEND) || (m_dwOptions & ACO_UNINITIALIZED); } BOOL _IsComboboxDropped() { return (m_hwndCombo && ComboBox_GetDroppedState(m_hwndCombo)); } void _UpdateGrip(); void _UpdateScrollbar();
static BOOL _IsWhack(TCHAR ch); static BOOL _IsBreakChar(WCHAR wch); BOOL _WantToAppendResults(); int _JumpToNextBreak(int iLoc, DWORD dwFlags); BOOL _CursorMovement(WPARAM wParam); void _RemoveCompletion(); void _GetEditText(); void _SetEditText(LPCWSTR psz); void _UpdateText(int iStartSel, int iEndSel, LPCTSTR pszCurrent, LPCTSTR pszNew); BOOL _OnKeyDown(WPARAM wParam); LRESULT _OnChar(WPARAM wParam, LPARAM lParam); void _StartCompletion(BOOL fAppend, BOOL fEvenIfEmpty = FALSE); BOOL _StartSearch(LPCWSTR pszSearch); void _StopSearch(); BOOL _ResetSearch(); void _GotFocus(); LPTSTR _QuickEnter(); BOOL _AppendNext(BOOL fAppendToWhack); BOOL _AppendPrevious(BOOL fAppendToWhack); void _Append(CACString& rStr, BOOL fAppendToWhack); BOOL _SetQuickCompleteStrings(LPCOLESTR pcszRegKeyPath, LPCOLESTR pcszQuickCompleteString); void _SubClassParent(HWND hwnd); void _UnSubClassParent(HWND hwnd);
LRESULT _DropDownWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _EditWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _ListViewWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void _DropDownDrawItem(LPDRAWITEMSTRUCT pdis); BOOL _DropDownNotify(LPNMHDR pnmhdr);
static int _DPADestroyCallback(LPVOID p, LPVOID d); static void _FreeDPAPtrs(HDPA hdpa); static int CALLBACK _DPACompareSortIndex(LPVOID p1, LPVOID p2, LPARAM lParam); static int CALLBACK EditWordBreakProcW(LPWSTR lpch, int ichCurrent, int cch, int code); static LRESULT CALLBACK s_EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); static LRESULT CALLBACK s_DropDownWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK s_ListViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK s_ParentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); static LRESULT CALLBACK s_GripperWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); static LRESULT CALLBACK s_MouseHook(int nCode, WPARAM wParam, LPARAM lParam); };
#endif
|