- Add support for navigating a toolbar with the arrow keys.
- Fix WrapToolbar in the case of no parent window.
- Use the newly added NMTBINITCUSTOMIZE for sending the
TBN_INITCUSTOMIZE so that it is safe on 64-bit platforms.
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index 2b62dfc..f3d5c94 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -41,7 +41,6 @@
* - WM_WININICHANGE
* - Notifications:
* - NM_CHAR
- * - NM_KEYDOWN
* - TBN_GETOBJECT
* - TBN_SAVE
* - Button wrapping (under construction).
@@ -1278,12 +1277,21 @@
btnPtr = infoPtr->buttons;
x = infoPtr->nIndent;
- /* this can get the parents width, to know how far we can extend
- * this toolbar. We cannot use its height, as there may be multiple
- * toolbars in a rebar control
- */
- GetClientRect( GetParent(hwnd), &rc );
- infoPtr->nWidth = rc.right - rc.left;
+ if (GetParent(hwnd))
+ {
+ /* this can get the parents width, to know how far we can extend
+ * this toolbar. We cannot use its height, as there may be multiple
+ * toolbars in a rebar control
+ */
+ GetClientRect( GetParent(hwnd), &rc );
+ infoPtr->nWidth = rc.right - rc.left;
+ }
+ else
+ {
+ GetWindowRect( hwnd, &rc );
+ infoPtr->nWidth = rc.right - rc.left;
+ }
+
bButtonWrap = FALSE;
TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
@@ -2193,6 +2201,7 @@
WCHAR Buffer[256];
int i = 0;
int index;
+ NMTBINITCUSTOMIZE nmtbic;
infoPtr = custInfo->tbInfo;
@@ -2202,10 +2211,9 @@
if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT))
return FALSE;
- /* UNDOCUMENTED: dialog hwnd immediately follows NMHDR */
- memcpy(&nmtb.iItem, &hwnd, sizeof(hwnd));
+ nmtbic.hwndDialog = hwnd;
/* Send TBN_INITCUSTOMIZE notification */
- if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_INITCUSTOMIZE) ==
+ if (TOOLBAR_SendNotify (&nmtbic.hdr, infoPtr, TBN_INITCUSTOMIZE) ==
TBNRF_HIDEHELP)
{
TRACE("TBNRF_HIDEHELP requested\n");
@@ -5783,6 +5791,77 @@
}
+static void
+TOOLBAR_SetRelativeHotItem(TOOLBAR_INFO *infoPtr, INT iDirection, DWORD dwReason)
+{
+ INT i;
+ INT nNewHotItem = infoPtr->nHotItem;
+
+ for (i = 0; i < infoPtr->nNumButtons; i++)
+ {
+ /* did we wrap? */
+ if ((nNewHotItem + iDirection < 0) ||
+ (nNewHotItem + iDirection >= infoPtr->nNumButtons))
+ {
+ NMTBWRAPHOTITEM nmtbwhi;
+ nmtbwhi.idNew = infoPtr->buttons[nNewHotItem].idCommand;
+ nmtbwhi.iDirection = iDirection;
+ nmtbwhi.dwReason = dwReason;
+
+ if (TOOLBAR_SendNotify(&nmtbwhi.hdr, infoPtr, TBN_WRAPHOTITEM))
+ return;
+ }
+
+ nNewHotItem += iDirection;
+ nNewHotItem = (nNewHotItem + infoPtr->nNumButtons) % infoPtr->nNumButtons;
+
+ if ((infoPtr->buttons[nNewHotItem].fsState & TBSTATE_ENABLED) &&
+ !(infoPtr->buttons[nNewHotItem].fsStyle & BTNS_SEP))
+ {
+ TOOLBAR_SetHotItemEx(infoPtr, nNewHotItem, dwReason);
+ break;
+ }
+ }
+}
+
+static LRESULT
+TOOLBAR_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
+ NMKEY nmkey;
+
+ nmkey.nVKey = (UINT)wParam;
+ nmkey.uFlags = HIWORD(lParam);
+
+ if (TOOLBAR_SendNotify(&nmkey.hdr, infoPtr, NM_KEYDOWN))
+ return DefWindowProcW(hwnd, WM_KEYDOWN, wParam, lParam);
+
+ switch ((UINT)wParam)
+ {
+ case VK_LEFT:
+ case VK_UP:
+ TOOLBAR_SetRelativeHotItem(infoPtr, -1, HICF_ARROWKEYS);
+ break;
+ case VK_RIGHT:
+ case VK_DOWN:
+ TOOLBAR_SetRelativeHotItem(infoPtr, 1, HICF_ARROWKEYS);
+ break;
+ case VK_SPACE:
+ case VK_RETURN:
+ if ((infoPtr->nHotItem >= 0) &&
+ (infoPtr->buttons[infoPtr->nHotItem].fsState & TBSTATE_ENABLED))
+ {
+ SendMessageW (infoPtr->hwndNotify, WM_COMMAND,
+ MAKEWPARAM(infoPtr->buttons[infoPtr->nHotItem].idCommand, BN_CLICKED),
+ (LPARAM)hwnd);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
static LRESULT
TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
@@ -6080,7 +6159,7 @@
if (btnPtr->fsState & TBSTATE_ENABLED)
{
SendMessageW (infoPtr->hwndNotify, WM_COMMAND,
- MAKEWPARAM(infoPtr->buttons[nHit].idCommand, 0), (LPARAM)hwnd);
+ MAKEWPARAM(infoPtr->buttons[nHit].idCommand, BN_CLICKED), (LPARAM)hwnd);
}
}
@@ -6320,6 +6399,7 @@
/* paranoid!! */
infoPtr->dwStructSize = sizeof(TBBUTTON);
infoPtr->nRows = 1;
+ infoPtr->nWidth = 0;
/* fix instance handle, if the toolbar was created by CreateToolbarEx() */
if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) {
@@ -6640,6 +6720,21 @@
static LRESULT
+TOOLBAR_SetFocus (HWND hwnd, WPARAM wParam)
+{
+ TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
+
+ TRACE("nHotItem = %d\n", infoPtr->nHotItem);
+
+ /* make first item hot */
+ if (infoPtr->nNumButtons > 0)
+ TOOLBAR_SetHotItemEx(infoPtr, 0, HICF_OTHER);
+
+ return 0;
+}
+
+
+static LRESULT
TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam)
/*****************************************************
*
@@ -7092,7 +7187,9 @@
case WM_GETFONT:
return TOOLBAR_GetFont (hwnd, wParam, lParam);
-/* case WM_KEYDOWN: */
+ case WM_KEYDOWN:
+ return TOOLBAR_KeyDown (hwnd, wParam, lParam);
+
/* case WM_KILLFOCUS: */
case WM_LBUTTONDBLCLK:
@@ -7140,6 +7237,9 @@
case WM_PAINT:
return TOOLBAR_Paint (hwnd, wParam);
+ case WM_SETFOCUS:
+ return TOOLBAR_SetFocus (hwnd, wParam);
+
case WM_SETREDRAW:
return TOOLBAR_SetRedraw (hwnd, wParam, lParam);
diff --git a/include/commctrl.h b/include/commctrl.h
index fc756ee..3055876 100644
--- a/include/commctrl.h
+++ b/include/commctrl.h
@@ -1235,6 +1235,7 @@
#define TBN_RESTORE (TBN_FIRST-21)
#define TBN_SAVE (TBN_FIRST-22)
#define TBN_INITCUSTOMIZE (TBN_FIRST-23)
+#define TBN_WRAPHOTITEM (TBN_FIRST-24) /* this is undocumented and the name is a guess */
#define TBNRF_HIDEHELP 0x00000001
@@ -1552,6 +1553,22 @@
INT cyButtonSpacing;
} TBMETRICS, *LPTBMETRICS;
+/* these are undocumented and the names are guesses */
+typedef struct
+{
+ NMHDR hdr;
+ HWND hwndDialog;
+} NMTBINITCUSTOMIZE;
+
+typedef struct
+{
+ NMHDR hdr;
+ INT idNew;
+ INT iDirection; /* left is -1, right is 1 */
+ DWORD dwReason; /* HICF_* */
+} NMTBWRAPHOTITEM;
+
+
HWND WINAPI
CreateToolbar(HWND, DWORD, UINT, INT, HINSTANCE,
UINT, LPCTBBUTTON, INT);