soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SFocusManager.cpp
1#include "souistd.h"
3#include "core/SWindowMgr.h"
4#include "core/SAccelerator.h"
5
6#pragma warning(disable : 4800)
7
8SNSBEGIN
9
11 : root_(root)
12 , cycle_(cycle)
13{
14}
15
16SWindow *FocusSearch::FindNextFocusableView(SWindow *starting_view, bool reverse, bool check_starting_view)
17{
18 if (root_->GetChildrenCount() == 0)
19 return NULL;
20
21 if (!starting_view)
22 {
23 if (reverse)
24 {
25 starting_view = root_->GetWindow(GSW_LASTCHILD);
26 while (starting_view->GetChildrenCount())
27 starting_view = starting_view->GetWindow(GSW_LASTCHILD);
28 }
29 else
30 {
31 starting_view = root_->GetWindow(GSW_FIRSTCHILD);
32 }
33 check_starting_view = true;
34 }
35
36 SWindow *pRet = NULL;
37 SWindow *pStartGroupOwner = NULL;
38 if (starting_view && starting_view->IsSiblingsAutoGroupped())
39 pStartGroupOwner = starting_view->GetParent();
40
41 if (reverse)
42 {
43 bool can_go_down = !IsFocusable(starting_view);
44 pRet = FindPreviousFocusableViewImpl(starting_view, check_starting_view, true, can_go_down, pStartGroupOwner);
45 }
46 else
47 {
48 pRet = FindNextFocusableViewImpl(starting_view, check_starting_view, true, true, pStartGroupOwner);
49 }
50 if (!pRet && cycle_ && starting_view)
51 {
52 cycle_ = false;
53 pRet = FindNextFocusableView(NULL, reverse, false);
54 }
55 return pRet;
56}
57
58// Strategy for finding the next focusable view:
59// - keep going down the first child, stop when you find a focusable view or
60// a focus traversable view (in that case return it) or when you reach a view
61// with no children.
62// - go to the right sibling and start the search from there (by invoking
63// FindNextFocusableViewImpl on that view).
64// - if the view has no right sibling, go up the parents until you find a parent
65// with a right sibling and start the search from there.
66SWindow *FocusSearch::FindNextFocusableViewImpl(SWindow *starting_view, bool check_starting_view, bool can_go_up, bool can_go_down, SWindow *pSkipGroupOwner)
67{
68 if (check_starting_view)
69 {
70 if (IsViewFocusableCandidate(starting_view, pSkipGroupOwner))
71 {
72 SWindow *v = starting_view->GetSelectedSiblingInGroup();
73 if (!v)
74 v = starting_view;
75 // The selected view might not be focusable (if it is disabled for
76 // example).
77 if (IsFocusable(v))
78 {
79 return v;
80 }
81 }
82 }
83
84 // First let's try the left child.
85 if (can_go_down)
86 {
87 SWindow *pChild = starting_view->GetWindow(GSW_FIRSTCHILD);
88 if (pChild)
89 {
90 SWindow *v = FindNextFocusableViewImpl(pChild, true, false, true, pSkipGroupOwner);
91 if (v)
92 {
93 return v;
94 }
95 }
96 }
97
98 // Then try the right sibling.
99 SWindow *sibling = starting_view->GetWindow(GSW_NEXTSIBLING);
100 if (sibling)
101 {
102 SWindow *v = FindNextFocusableViewImpl(sibling, true, false, true, pSkipGroupOwner);
103 if (v)
104 {
105 return v;
106 }
107 }
108
109 // Then go up to the parent sibling.
110 if (can_go_up)
111 {
112 SWindow *parent = starting_view->GetParent();
113 while (parent)
114 {
115 sibling = parent->GetWindow(GSW_NEXTSIBLING);
116 if (sibling)
117 {
118 return FindNextFocusableViewImpl(sibling, true, true, true, pSkipGroupOwner);
119 }
120 parent = parent->GetParent();
121 }
122 }
123
124 // We found nothing.
125 return NULL;
126}
127
128// Strategy for finding the previous focusable view:
129// - keep going down on the right until you reach a view with no children, if it
130// it is a good candidate return it.
131// - start the search on the left sibling.
132// - if there are no left sibling, start the search on the parent (without going
133// down).
134SWindow *FocusSearch::FindPreviousFocusableViewImpl(SWindow *starting_view, bool check_starting_view, bool can_go_up, bool can_go_down, SWindow *pSkipGroupOwner)
135{
136 if (can_go_down)
137 { // find the last focusable window
138 SWindow *pChild = starting_view->GetWindow(GSW_LASTCHILD);
139 if (pChild)
140 {
141 SWindow *pRet = FindPreviousFocusableViewImpl(pChild, true, false, true, pSkipGroupOwner);
142 if (pRet)
143 return pRet;
144 }
145 }
146
147 if (check_starting_view && IsViewFocusableCandidate(starting_view, pSkipGroupOwner))
148 {
149 SWindow *v = starting_view->GetSelectedSiblingInGroup();
150 if (!v)
151 v = starting_view;
152 // The selected view might not be focusable (if it is disabled for example).
153 if (IsFocusable(v))
154 {
155 return v;
156 }
157 }
158
159 SWindow *pPrevSibling = starting_view->GetWindow(GSW_PREVSIBLING);
160 if (pPrevSibling)
161 {
162 return FindPreviousFocusableViewImpl(pPrevSibling, true, true, true, pSkipGroupOwner);
163 }
164 if (can_go_up)
165 {
166 SWindow *pParent = starting_view->GetWindow(GSW_PARENT);
167 if (pParent)
168 return FindPreviousFocusableViewImpl(pParent, true, true, false, pSkipGroupOwner);
169 }
170
171 return NULL;
172}
173
174bool FocusSearch::IsViewFocusableCandidate(SWindow *v, SWindow *pGroupOwner)
175{
176 if (!IsFocusable(v))
177 return false;
178 if (pGroupOwner && v->IsSiblingsAutoGroupped() && v->GetParent() == pGroupOwner)
179 return false;
180 return true;
181}
182
183bool FocusSearch::IsFocusable(const SWindow *view) const
184{
185 if (!view)
186 return false;
187 return view->IsFocusable() && view->IsVisible(TRUE) && !view->IsDisabled(TRUE);
188}
189
190//////////////////////////////////////////////////////////////////////////
192 : m_pOwner(NULL)
193 , focused_view_(0)
194 , focused_backup_(0)
195{
196}
197
201
203{
204 m_pOwner = pOwner;
205}
206
208{
209 if (vKey != VK_TAB)
210 return FALSE;
211 SWindow *pFocus = SWindowMgr::GetWindow(focused_view_);
212 if (pFocus && pFocus->OnGetDlgCode() & SC_WANTTAB)
213 return FALSE;
214 if (GetKeyState(VK_CONTROL) & 0x8000)
215 return FALSE;
216 else
217 return TRUE;
218}
219
221{
222 // tab traversal
223 if (IsTabTraversalKey(vKey))
224 {
225 AdvanceFocus(GetKeyState(VK_SHIFT) & 0x8000);
226 return TRUE;
227 }
228
229 // Intercept arrow key messages to switch between grouped views.
230 SWindow *pFocusWnd = SWindowMgr::GetWindow(focused_view_);
231 if (pFocusWnd && pFocusWnd->IsSiblingsAutoGroupped() && (vKey == VK_LEFT || vKey == VK_RIGHT || vKey == VK_UP || vKey == VK_DOWN))
232 {
233 UINT ucode = (vKey == VK_RIGHT || vKey == VK_DOWN) ? GSW_NEXTSIBLING : GSW_PREVSIBLING;
234 SWindow *pNext = pFocusWnd->GetWindow(ucode);
235 while (pNext)
236 {
237 if (pNext->IsSiblingsAutoGroupped())
238 {
240 break;
241 }
242 pNext = pNext->GetWindow(ucode);
243 }
244 if (!pNext)
245 {
246 pNext = pFocusWnd->GetParent()->GetWindow(ucode == GSW_NEXTSIBLING ? GSW_FIRSTCHILD : GSW_LASTCHILD);
247 while (pNext)
248 {
249 if (pNext->IsSiblingsAutoGroupped())
250 {
252 break;
253 }
254 pNext = pNext->GetWindow(ucode);
255 }
256 }
257 return TRUE;
258 }
259 // Process keyboard accelerators.
260 SAccelerator accelerator(vKey, GetKeyState(VK_CONTROL) & 0x8000, GetKeyState(VK_MENU) & 0x8000, GetKeyState(VK_SHIFT) & 0x8000);
261 if (ProcessAccelerator(&accelerator))
262 {
263 // If a shortcut was activated for this keydown message, do not propagate
264 // the event further.
265 return TRUE;
266 }
267
268 return FALSE;
269}
270
272{
273 // Let's revalidate the focused view.
274 ValidateFocusedView();
275 SWindow *pFocus = SWindowMgr::GetWindow(focused_view_);
276 SWindow *pSwnd = GetNextFocusableView(pFocus, reverse, true);
277 if (pSwnd)
278 {
280 }
281}
282
283SWindow *SFocusManager::GetNextFocusableView(SWindow *original_starting_view, bool bReverse, bool bLoop)
284{
285
286 FocusSearch fs(m_pOwner, bLoop);
287 return fs.FindNextFocusableView(original_starting_view, bReverse, false);
288}
289
291{
292 if (swnd == focused_view_)
293 {
294 if (swnd == 0 && focused_backup_)
295 { // clear focus
296 focused_backup_ = swnd;
297 }
298 return;
299 }
300
301 if (focused_backup_ != 0)
302 { //当前是在最小化状态,直接修改状态
303 focused_backup_ = swnd;
304 return;
305 }
306
307 // Update the reason for the focus change (since this is checked by
308 // some listeners), then notify all listeners.
309 SWindow *pOldFocus = SWindowMgr::GetWindow(focused_view_);
310 SWindow *pNewFocus = SWindowMgr::GetWindow(swnd);
311
312 focus_change_reason_ = reason;
313 focused_view_ = 0;
314 if (pOldFocus)
315 {
316 pOldFocus->SSendMessage(WM_KILLFOCUS, (WPARAM)swnd);
317 }
318 if (pNewFocus && !pNewFocus->IsDisabled(TRUE) && pNewFocus->IsFocusable())
319 {
320 focused_view_ = swnd;
321 pNewFocus->SSendMessage(WM_SETFOCUS, (WPARAM)focused_view_, (LPARAM)reason);
322 }
323}
324
329
330void SFocusManager::ValidateFocusedView()
331{
332 if (focused_view_)
333 {
334 SWindow *pFocus = SWindowMgr::GetWindow(focused_view_);
335 if (pFocus)
336 {
337 pFocus = pFocus->GetRoot();
338 if (pFocus != m_pOwner)
339 {
340 focused_view_ = 0;
341 }
342 }
343 else
344 {
345 focused_view_ = 0;
346 }
347 }
348}
349
354
356{
357 return focused_view_;
358}
359
361{
362 ValidateFocusedView();
363 focused_backup_ = focused_view_;
364 focused_view_ = 0;
365 SWindow *pWnd = SWindowMgr::GetWindow(focused_backup_);
366
367 if (pWnd)
368 {
369 pWnd->SSendMessage(WM_KILLFOCUS);
370 }
371 else
372 {
373 focused_backup_ = -1; //标识一下当前是最小化状态
374 }
375}
376
378{
379 SWindow *pWnd = SWindowMgr::GetWindow(focused_backup_);
380 if (pWnd && !pWnd->IsDisabled(TRUE) && pWnd->IsVisible(TRUE))
381 {
382 focused_view_ = focused_backup_;
383 pWnd->SSendMessage(WM_SETFOCUS, 0, (LPARAM)kReasonFocusRestore);
384 }
385 focused_backup_ = 0;
386}
387
389{
390 DWORD dwAcc = pAcc->GetAcc();
391 AcceleratorTargetList &targets = accelerators_[dwAcc];
392 targets.AddHead(target);
393}
394
396{
397 DWORD dwAcc = pAcc->GetAcc();
398 if (!accelerators_.Lookup(dwAcc))
399 return;
400 AcceleratorTargetList *targets = &accelerators_[dwAcc];
401 SPOSITION pos = targets->Find(target);
402 if (pos)
403 targets->RemoveAt(pos);
404}
405
407{
408 SPOSITION pos = accelerators_.GetStartPosition();
409 while (pos)
410 {
411 AcceleratorTargetList &targets = accelerators_.GetValueAt(pos);
412 SPOSITION pos2 = targets.Find(target);
413 if (pos2)
414 targets.RemoveAt(pos2);
415 accelerators_.GetNext(pos);
416 }
417}
418
419bool SFocusManager::ProcessAccelerator(const IAccelerator *pAcc)
420{
421 DWORD dwAcc = pAcc->GetAcc();
422 if (!accelerators_.Lookup(dwAcc))
423 return false;
424
425 // We have to copy the target list here, because an AcceleratorPressed
426 // event handler may modify the list.
427 AcceleratorTargetList targets = accelerators_[dwAcc];
428
429 SPOSITION pos = targets.GetHeadPosition();
430
431 while (pos)
432 {
433 IAcceleratorTarget *pTarget = targets.GetNext(pos);
434 if (pTarget->OnAcceleratorPressed(pAcc))
435 {
436 return true;
437 }
438 }
439 return false;
440}
441SNSEND
Accelerator management module.
Focus management module for DUI windows.
SOUI系统中的DUI窗口管理模块
@ GSW_FIRSTCHILD
Definition SWnd.h:195
@ GSW_LASTCHILD
Definition SWnd.h:196
@ GSW_PREVSIBLING
Definition SWnd.h:197
@ GSW_NEXTSIBLING
Definition SWnd.h:198
@ GSW_PARENT
Definition SWnd.h:199
Implements the algorithm to find the next view to focus.
FocusSearch(SWindow *root, bool cycle)
Constructor.
SWindow * FindNextFocusableView(SWindow *starting_view, bool reverse, bool check_starting_view)
Finds the next focusable view.
Accelerator key mapping.
void AdvanceFocus(bool reverse)
Advances the focus.
void SetFocusedHwndWithReason(SWND swnd, FocusChangeReason reason)
Sets the focused window with a reason.
void SetFocusedHwnd(SWND swnd)
Sets the focused window.
BOOL IsTabTraversalKey(UINT vKey)
Checks if a key is a tab traversal key.
BOOL OnKeyDown(UINT vKey)
Handles key down events.
void SetOwner(SWindow *pOwner)
Sets the owner window.
~SFocusManager(void)
Destructor.
FocusChangeReason
Reason for focus change.
void UnregisterAccelerators(IAcceleratorTarget *target) OVERRIDE
Unregisters all keyboard accelerators for a target.
void UnregisterAccelerator(const IAccelerator *pAcc, IAcceleratorTarget *target) OVERRIDE
Unregisters a keyboard accelerator for a target.
void RestoreFocusedView()
Restores the focused view.
void ClearFocus()
Clears the focused window.
void StoreFocusedView()
Stores the focused view.
SWND GetFocusedHwnd() const
Gets the focused window.
void RegisterAccelerator(const IAccelerator *pAcc, IAcceleratorTarget *target) OVERRIDE
Registers a keyboard accelerator for a target.
SFocusManager()
Constructor.
Base class for SOUI DUI windows.
Definition SWnd.h:286
UINT OnGetDlgCode() SCONST OVERRIDE
Retrieves the dialog code for the window.
Definition Swnd.cpp:1991
SWND GetSwnd() SCONST OVERRIDE
Retrieves the window handle.
Definition Swnd.cpp:489
SWindow * GetParent() const
Retrieves the parent window.
Definition Swnd.cpp:3488
BOOL IsSiblingsAutoGroupped() SCONST OVERRIDE
Checks if siblings are auto-grouped.
Definition Swnd.cpp:3441
UINT GetChildrenCount() SCONST OVERRIDE
Retrieves the number of child windows.
Definition Swnd.cpp:533
BOOL IsVisible(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is visible.
Definition Swnd.cpp:646
SWindow * GetRoot() const
Retrieves the root window in the hierarchy.
Definition Swnd.cpp:3493
LRESULT SSendMessage(UINT uMsg, WPARAM wParam=0, LPARAM lParam=0, BOOL *pbMsgHandled=NULL) OVERRIDE
Sends a message to the window.
Definition Swnd.cpp:364
SWindow * GetWindow(int uCode) const
Retrieves a window based on a given code.
Definition Swnd.cpp:3456
BOOL IsDisabled(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is disabled.
Definition Swnd.cpp:638
BOOL IsFocusable() SCONST OVERRIDE
Checks if the window is focusable.
Definition Swnd.cpp:1996
virtual SWindow * GetSelectedSiblingInGroup()
Get selected sibling in group.
Definition SWnd.h:1598
static SWindow * GetWindow(SWND swnd)
Retrieves the SWindow pointer from a given handle.
Interface for an accelerator key.
DWORD GetAcc() SCONST PURE
Get the accelerator key combination.
Interface for handling accelerator key presses.
BOOL OnAcceleratorPressed(const IAccelerator *acc) PURE
Handle an accelerator key press.