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 <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -119,9 +120,16 @@ typedef struct tagTREEVIEW_INFO
|
|||||||
int stateImageHeight;
|
int stateImageHeight;
|
||||||
int stateImageWidth;
|
int stateImageWidth;
|
||||||
HDPA items;
|
HDPA items;
|
||||||
|
|
||||||
|
DWORD lastKeyPressTimestamp; /* Added */
|
||||||
|
WPARAM charCode; /* Added */
|
||||||
|
INT nSearchParamLength; /* Added */
|
||||||
|
CHAR szSearchParam[ MAX_PATH ]; /* Added */
|
||||||
} TREEVIEW_INFO;
|
} TREEVIEW_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
/******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/
|
||||||
|
#define KEY_DELAY 450
|
||||||
|
|
||||||
/* bitflags for infoPtr->uInternalStatus */
|
/* bitflags for infoPtr->uInternalStatus */
|
||||||
|
|
||||||
@ -3976,6 +3984,156 @@ TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item)
|
|||||||
return TRUE;
|
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 ************************************************************/
|
/* Scrolling ************************************************************/
|
||||||
|
|
||||||
static LRESULT
|
static LRESULT
|
||||||
@ -4874,7 +5032,8 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||||||
case TVM_SORTCHILDRENCB:
|
case TVM_SORTCHILDRENCB:
|
||||||
return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam);
|
return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam);
|
||||||
|
|
||||||
/* WM_CHAR */
|
case WM_CHAR:
|
||||||
|
return TREEVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
return TREEVIEW_Command(infoPtr, wParam, lParam);
|
return TREEVIEW_Command(infoPtr, wParam, lParam);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user