[RSHELL]
[reactos.git] / base / shell / rshell / CMenuFocusManager.cpp
1 /*
2 * Shell Menu Band
3 *
4 * Copyright 2014 David Quintana
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20 #include "precomp.h"
21 #include <windowsx.h>
22 #include <CommonControls.h>
23 #include <shlwapi_undoc.h>
24
25 #include "CMenuFocusManager.h"
26 #include "CMenuBand.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus);
29
30 DWORD CMenuFocusManager::TlsIndex = 0;
31
32 CMenuFocusManager * CMenuFocusManager::GetManager()
33 {
34 return reinterpret_cast<CMenuFocusManager *>(TlsGetValue(TlsIndex));
35 }
36
37 CMenuFocusManager * CMenuFocusManager::AcquireManager()
38 {
39 CMenuFocusManager * obj = NULL;
40
41 if (!TlsIndex)
42 {
43 if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
44 return NULL;
45 }
46
47 obj = GetManager();
48
49 if (!obj)
50 {
51 obj = new CComObject<CMenuFocusManager>();
52 TlsSetValue(TlsIndex, obj);
53 }
54
55 obj->AddRef();
56
57 return obj;
58 }
59
60 void CMenuFocusManager::ReleaseManager(CMenuFocusManager * obj)
61 {
62 if (!obj->Release())
63 {
64 TlsSetValue(TlsIndex, NULL);
65 }
66 }
67
68 LRESULT CALLBACK CMenuFocusManager::s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
69 {
70 return GetManager()->GetMsgHook(nCode, wParam, lParam);
71 }
72
73 HRESULT CMenuFocusManager::PushToArray(CMenuBand * item)
74 {
75 if (m_bandCount >= MAX_RECURSE)
76 return E_OUTOFMEMORY;
77
78 m_bandStack[m_bandCount++] = item;
79 return S_OK;
80 }
81
82 HRESULT CMenuFocusManager::PopFromArray(CMenuBand ** pItem)
83 {
84 if (pItem)
85 *pItem = NULL;
86
87 if (m_bandCount <= 0)
88 return E_FAIL;
89
90 m_bandCount--;
91
92 if (pItem)
93 *pItem = m_bandStack[m_bandCount];
94
95 m_bandStack[m_bandCount] = NULL;
96
97 return S_OK;
98 }
99
100 HRESULT CMenuFocusManager::PeekArray(CMenuBand ** pItem)
101 {
102 if (!pItem)
103 return E_FAIL;
104
105 *pItem = NULL;
106
107 if (m_bandCount <= 0)
108 return E_FAIL;
109
110 *pItem = m_bandStack[m_bandCount - 1];
111
112 return S_OK;
113 }
114
115 CMenuFocusManager::CMenuFocusManager() :
116 m_currentBand(NULL),
117 m_currentFocus(NULL),
118 m_bandCount(0)
119 {
120 m_threadId = GetCurrentThreadId();
121 }
122
123 CMenuFocusManager::~CMenuFocusManager()
124 {
125 }
126
127 LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
128 {
129 if (nCode < 0)
130 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
131
132 if (nCode == HC_ACTION)
133 {
134 BOOL callNext = TRUE;
135 MSG* msg = reinterpret_cast<MSG*>(lParam);
136
137 // Do whatever is necessary here
138
139 switch (msg->message)
140 {
141 case WM_CLOSE:
142 break;
143 case WM_SYSKEYDOWN:
144 case WM_KEYDOWN:
145 switch (msg->wParam)
146 {
147 case VK_MENU:
148 case VK_LMENU:
149 case VK_RMENU:
150 m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL);
151 break;
152 case VK_LEFT:
153 m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT);
154 break;
155 case VK_RIGHT:
156 m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT);
157 break;
158 case VK_UP:
159 m_currentBand->_MenuItemHotTrack(VK_UP);
160 break;
161 case VK_DOWN:
162 m_currentBand->_MenuItemHotTrack(VK_DOWN);
163 break;
164 }
165 break;
166 case WM_CHAR:
167 //if (msg->wParam >= 'a' && msg->wParam <= 'z')
168 //{
169 // callNext = FALSE;
170 // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
171 //}
172 break;
173 }
174
175 if (!callNext)
176 return 0;
177 }
178
179 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
180 }
181
182 HRESULT CMenuFocusManager::PlaceHooks(HWND window)
183 {
184 //SetCapture(window);
185 m_hHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId);
186 return S_OK;
187 }
188
189 HRESULT CMenuFocusManager::RemoveHooks(HWND window)
190 {
191 UnhookWindowsHookEx(m_hHook);
192 //ReleaseCapture();
193 return S_OK;
194 }
195
196 HRESULT CMenuFocusManager::UpdateFocus(CMenuBand * newBand)
197 {
198 HRESULT hr;
199 HWND newFocus;
200
201 if (newBand == NULL)
202 {
203 hr = RemoveHooks(m_currentFocus);
204 m_currentFocus = NULL;
205 m_currentBand = NULL;
206 return S_OK;
207 }
208
209 hr = newBand->_GetTopLevelWindow(&newFocus);
210 if (FAILED(hr))
211 return hr;
212
213 if (!m_currentBand)
214 {
215 hr = PlaceHooks(newFocus);
216 if (FAILED(hr))
217 return hr;
218 }
219
220 m_currentFocus = newFocus;
221 m_currentBand = newBand;
222
223 return S_OK;
224 }
225
226 HRESULT CMenuFocusManager::PushMenu(CMenuBand * mb)
227 {
228 HRESULT hr;
229
230 hr = PushToArray(mb);
231 if (FAILED(hr))
232 return hr;
233
234 return UpdateFocus(mb);
235 }
236
237 HRESULT CMenuFocusManager::PopMenu(CMenuBand * mb)
238 {
239 CMenuBand * mbc;
240 HRESULT hr;
241
242 hr = PopFromArray(&mbc);
243 if (FAILED(hr))
244 return hr;
245
246 if (mb != mbc)
247 return E_FAIL;
248
249 hr = PeekArray(&mbc);
250
251 return UpdateFocus(mbc);
252 }