| 2096 | |
| 2097 | |
| 2098 | bool ControlSetTab(ResultToken &aResultToken, HWND aHwnd, DWORD aTabIndex) |
| 2099 | { |
| 2100 | DWORD_PTR dwResult; |
| 2101 | // MSDN: "If the tab control does not have the TCS_BUTTONS style, changing the focus also changes |
| 2102 | // the selected tab. In this case, the tab control sends the TCN_SELCHANGING and TCN_SELCHANGE |
| 2103 | // notification codes to its parent window." |
| 2104 | if (!SendMessageTimeout(aHwnd, TCM_SETCURFOCUS, aTabIndex, 0, SMTO_ABORTIFHUNG, 2000, &dwResult)) |
| 2105 | return false; |
| 2106 | // Tab controls with the TCS_BUTTONS style need additional work: |
| 2107 | if (GetWindowLong(aHwnd, GWL_STYLE) & TCS_BUTTONS) |
| 2108 | { |
| 2109 | // Problem: |
| 2110 | // TCM_SETCURFOCUS does not change the selected tab if TCS_BUTTONS is set. |
| 2111 | // |
| 2112 | // False solution #1 (which used to be recommended in the docs): |
| 2113 | // Send a TCM_SETCURSEL method afterward. TCM_SETCURSEL changes the selected tab, |
| 2114 | // but doesn't notify the control's parent, so it doesn't update the tab's contents. |
| 2115 | // |
| 2116 | // False solution #2: |
| 2117 | // Send a WM_NOTIFY message to the parent window to notify it. Can't be done. |
| 2118 | // MSDN says: "For Windows 2000 and later systems, the WM_NOTIFY message cannot |
| 2119 | // be sent between processes." |
| 2120 | // |
| 2121 | // Solution #1: |
| 2122 | // Send VK_LEFT/VK_RIGHT as many times as needed. |
| 2123 | // |
| 2124 | // Solution #2: |
| 2125 | // Set the focus to an adjacent tab and then send VK_LEFT/VK_RIGHT. |
| 2126 | // - Must choose an appropriate tab index and vk depending on which tab is being |
| 2127 | // selected, since VK_LEFT/VK_RIGHT don't wrap around. |
| 2128 | // - Ends up tempting optimisations which increase code size, such as to avoid |
| 2129 | // TCM_SETCURFOCUS if an adjacent tab is already focused. |
| 2130 | // - Still needs VK_SPACE afterward to actually select the tab. |
| 2131 | // |
| 2132 | // Solution #3 (the one below): |
| 2133 | // Set the focus to the appropriate tab and then send VK_SPACE. |
| 2134 | // - Since we've already set the focus, all we need to do is send VK_SPACE. |
| 2135 | // - If the tab index is invalid and the user has focused but not selected |
| 2136 | // another tab, that tab will be selected. This seems harmless enough. |
| 2137 | // |
| 2138 | PostMessage(aHwnd, WM_KEYDOWN, VK_SPACE, 0x00000001); |
| 2139 | PostMessage(aHwnd, WM_KEYUP, VK_SPACE, 0xC0000001); |
| 2140 | } |
| 2141 | return true; |
| 2142 | } |
| 2143 | |
| 2144 | |
| 2145 | |