Handle WM_CHARs and pass them to TREEVIEW_ProcessLetterKeys. See also
LISTVIEW_ProcessLetterKeys in listview.c.
This commit is contained in:
parent
1afa24aeac
commit
2ad985527f
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -119,9 +120,16 @@ typedef struct tagTREEVIEW_INFO
|
|||
int stateImageHeight;
|
||||
int stateImageWidth;
|
||||
HDPA items;
|
||||
|
||||
DWORD lastKeyPressTimestamp; /* Added */
|
||||
WPARAM charCode; /* Added */
|
||||
INT nSearchParamLength; /* Added */
|
||||
CHAR szSearchParam[ MAX_PATH ]; /* Added */
|
||||
} TREEVIEW_INFO;
|
||||
|
||||
|
||||
/******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/
|
||||
#define KEY_DELAY 450
|
||||
|
||||
/* bitflags for infoPtr->uInternalStatus */
|
||||
|
||||
|
@ -3976,6 +3984,156 @@ TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* TREEVIEW_ProcessLetterKeys
|
||||
*
|
||||
* Processes keyboard messages generated by pressing the letter keys
|
||||
* on the keyboard.
|
||||
* What this does is perform a case insensitive search from the
|
||||
* current position with the following quirks:
|
||||
* - If two chars or more are pressed in quick succession we search
|
||||
* for the corresponding string (e.g. 'abc').
|
||||
* - If there is a delay we wipe away the current search string and
|
||||
* restart with just that char.
|
||||
* - If the user keeps pressing the same character, whether slowly or
|
||||
* fast, so that the search string is entirely composed of this
|
||||
* character ('aaaaa' for instance), then we search for first item
|
||||
* that starting with that character.
|
||||
* - If the user types the above character in quick succession, then
|
||||
* we must also search for the corresponding string ('aaaaa'), and
|
||||
* go to that string if there is a match.
|
||||
*
|
||||
* RETURNS
|
||||
*
|
||||
* Zero.
|
||||
*
|
||||
* BUGS
|
||||
*
|
||||
* - The current implementation has a list of characters it will
|
||||
* accept and it ignores averything else. In particular it will
|
||||
* ignore accentuated characters which seems to match what
|
||||
* Windows does. But I'm not sure it makes sense to follow
|
||||
* Windows there.
|
||||
* - We don't sound a beep when the search fails.
|
||||
* - The search should start from the focused item, not from the selected
|
||||
* item. One reason for this is to allow for multiple selections in trees.
|
||||
* But currently infoPtr->focusedItem does not seem very usable.
|
||||
*
|
||||
* SEE ALSO
|
||||
*
|
||||
* TREEVIEW_ProcessLetterKeys
|
||||
*/
|
||||
static INT TREEVIEW_ProcessLetterKeys(
|
||||
HWND hwnd, /* handle to the window */
|
||||
WPARAM charCode, /* the character code, the actual character */
|
||||
LPARAM keyData /* key data */
|
||||
)
|
||||
{
|
||||
TREEVIEW_INFO *infoPtr;
|
||||
HTREEITEM nItem;
|
||||
HTREEITEM endidx,idx;
|
||||
TVITEMEXA item;
|
||||
CHAR buffer[MAX_PATH];
|
||||
DWORD timestamp,elapsed;
|
||||
|
||||
/* simple parameter checking */
|
||||
if (!hwnd || !charCode || !keyData)
|
||||
return 0;
|
||||
|
||||
infoPtr=(TREEVIEW_INFO*)GetWindowLongA(hwnd, 0);
|
||||
if (!infoPtr)
|
||||
return 0;
|
||||
|
||||
/* only allow the valid WM_CHARs through */
|
||||
if (!isalnum(charCode) &&
|
||||
charCode != '.' && charCode != '`' && charCode != '!' &&
|
||||
charCode != '@' && charCode != '#' && charCode != '$' &&
|
||||
charCode != '%' && charCode != '^' && charCode != '&' &&
|
||||
charCode != '*' && charCode != '(' && charCode != ')' &&
|
||||
charCode != '-' && charCode != '_' && charCode != '+' &&
|
||||
charCode != '=' && charCode != '\\'&& charCode != ']' &&
|
||||
charCode != '}' && charCode != '[' && charCode != '{' &&
|
||||
charCode != '/' && charCode != '?' && charCode != '>' &&
|
||||
charCode != '<' && charCode != ',' && charCode != '~')
|
||||
return 0;
|
||||
|
||||
/* compute how much time elapsed since last keypress */
|
||||
timestamp = GetTickCount();
|
||||
if (timestamp > infoPtr->lastKeyPressTimestamp) {
|
||||
elapsed=timestamp-infoPtr->lastKeyPressTimestamp;
|
||||
} else {
|
||||
elapsed=infoPtr->lastKeyPressTimestamp-timestamp;
|
||||
}
|
||||
|
||||
/* update the search parameters */
|
||||
infoPtr->lastKeyPressTimestamp=timestamp;
|
||||
if (elapsed < KEY_DELAY) {
|
||||
if (infoPtr->nSearchParamLength < sizeof(infoPtr->szSearchParam)) {
|
||||
infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
|
||||
}
|
||||
if (infoPtr->charCode != charCode) {
|
||||
infoPtr->charCode=charCode=0;
|
||||
}
|
||||
} else {
|
||||
infoPtr->charCode=charCode;
|
||||
infoPtr->szSearchParam[0]=charCode;
|
||||
infoPtr->nSearchParamLength=1;
|
||||
/* Redundant with the 1 char string */
|
||||
charCode=0;
|
||||
}
|
||||
|
||||
/* and search from the current position */
|
||||
nItem=NULL;
|
||||
if (infoPtr->selectedItem != NULL) {
|
||||
endidx=infoPtr->selectedItem;
|
||||
/* if looking for single character match,
|
||||
* then we must always move forward
|
||||
*/
|
||||
if (infoPtr->nSearchParamLength == 1)
|
||||
idx=TREEVIEW_GetNextListItem(infoPtr,endidx);
|
||||
else
|
||||
idx=endidx;
|
||||
} else {
|
||||
endidx=NULL;
|
||||
idx=infoPtr->root->firstChild;
|
||||
}
|
||||
do {
|
||||
if (idx == NULL) {
|
||||
if (endidx == NULL)
|
||||
break;
|
||||
idx=infoPtr->root->firstChild;
|
||||
}
|
||||
|
||||
/* get item */
|
||||
ZeroMemory(&item, sizeof(item));
|
||||
item.mask = TVIF_TEXT;
|
||||
item.hItem = idx;
|
||||
item.pszText = buffer;
|
||||
item.cchTextMax = sizeof(buffer);
|
||||
TREEVIEW_GetItemA( infoPtr, &item );
|
||||
|
||||
/* check for a match */
|
||||
if (strncasecmp(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) {
|
||||
nItem=idx;
|
||||
break;
|
||||
} else if ( (charCode != 0) && (nItem == NULL) &&
|
||||
(nItem != infoPtr->selectedItem) &&
|
||||
(strncasecmp(item.pszText,infoPtr->szSearchParam,1) == 0) ) {
|
||||
/* This would work but we must keep looking for a longer match */
|
||||
nItem=idx;
|
||||
}
|
||||
idx=TREEVIEW_GetNextListItem(infoPtr,idx);
|
||||
} while (idx != endidx);
|
||||
|
||||
if (nItem != NULL) {
|
||||
if (TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, nItem, TVC_BYKEYBOARD)) {
|
||||
TREEVIEW_EnsureVisible(infoPtr, nItem, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scrolling ************************************************************/
|
||||
|
||||
static LRESULT
|
||||
|
@ -4874,7 +5032,8 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
case TVM_SORTCHILDRENCB:
|
||||
return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam);
|
||||
|
||||
/* WM_CHAR */
|
||||
case WM_CHAR:
|
||||
return TREEVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
|
||||
|
||||
case WM_COMMAND:
|
||||
return TREEVIEW_Command(infoPtr, wParam, lParam);
|
||||
|
|
Loading…
Reference in New Issue