Treeview typing completion

François Gouget fgouget at codeweavers.com
Sun Feb 11 13:32:35 CST 2001


   This is the same as the listview completion patch except that
treeviews did not have this implemented at all before.

Changelog:

   François Gouget <fgouget at codeweavers.com>

 * dlls/comctl32/treeview.c

   Handle WM_CHARs and pass them to TREEVIEW_ProcessLetterKeys
   See also LISTVIEW_ProcessLetterKeys in listview.c


-- 
François Gouget
fgouget at codeweavers.com
-------------- next part --------------
Index: dlls/comctl32/treeview.c
===================================================================
RCS file: /home/cvs/wine/wine/dlls/comctl32/treeview.c,v
retrieving revision 1.87
diff -u -r1.87 treeview.c
--- dlls/comctl32/treeview.c	2000/11/28 22:40:56	1.87
+++ dlls/comctl32/treeview.c	2001/02/11 18:55:47
@@ -25,6 +25,7 @@
  */
 
 #include <assert.h>
+#include <ctype.h>
 #include <string.h>
 #include <limits.h>
 #include <stdlib.h>
@@ -119,9 +120,16 @@
   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 @@
     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 @@
     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);


More information about the wine-patches mailing list