Skip to content

Commit

Permalink
Merge pull request pywinauto#994 from eltimen/uia-setfocus-workaround
Browse files Browse the repository at this point in the history
Add workaround to fix set_focus() failure on UIA (call win32 in this case)
  • Loading branch information
vasily-v-ryabov authored Nov 4, 2020
2 parents 5235ee6 + 62e197b commit df8b9d3
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 12 deletions.
11 changes: 1 addition & 10 deletions pywinauto/base_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,16 +410,7 @@ def top_level_parent(self):
a top level window already!)
"""
if not ("top_level_parent" in self._cache.keys()):
parent = self.parent()

if parent:
if self.parent() == self.root():
self._cache["top_level_parent"] = self
else:
return self.parent().top_level_parent()
else:
self._cache["top_level_parent"] = self

self._cache["top_level_parent"] = self.backend.generic_wrapper_class(self.element_info.top_level_parent)
return self._cache["top_level_parent"]

#-----------------------------------------------------------
Expand Down
22 changes: 20 additions & 2 deletions pywinauto/controls/uiawrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from .. import WindowNotFoundError # noqa #E402
from ..timings import Timings
from .win_base_wrapper import WinBaseWrapper
from .hwndwrapper import HwndWrapper
from ..base_wrapper import BaseMeta

from ..windows.uia_defines import IUIA
Expand Down Expand Up @@ -408,9 +409,26 @@ def set_focus(self):
pass
try:
self.element_info.element.SetFocus()

# SetFocus() can return S_OK even if the element isn't focused actually
active_element = UIAElementInfo.get_active()
if self.element_info != active_element and self.element_info != active_element.top_level_parent:
if self.handle:
warnings.warn("Failed to set focus on element, trying win32 backend", RuntimeWarning)
HwndWrapper(self.element_info).set_focus()
else:
warnings.warn("The element has not been focused because UIA SetFocus() failed "
"and we can't use win32 backend instead because "
"the element doesn't have native handle", RuntimeWarning)
except comtypes.COMError as exc:
warnings.warn('The window has not been focused due to ' \
'COMError: {}'.format(exc), RuntimeWarning)
if self.handle:
warnings.warn("Failed to set focus on element due to COMError: {}, "
"trying win32 backend".format(exc), RuntimeWarning)
HwndWrapper(self.element_info).set_focus()
else:
warnings.warn("The element has not been focused due to COMError: {}, "
"and we can't use win32 backend instead because "
"the element doesn't have native handle".format(exc), RuntimeWarning)

return self

Expand Down
20 changes: 20 additions & 0 deletions pywinauto/element_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,26 @@ def parent(self):
"""Return the parent of the element"""
raise NotImplementedError()

@property
def top_level_parent(self):
"""
Return the top level window of this element
The TopLevel parent is different from the parent in that the parent
is the element that owns this element - but it may not be a dialog/main
window. For example most Comboboxes have an Edit. The ComboBox is the
parent of the Edit control.
This will always return a valid window element (if the control has
no top level parent then the control itself is returned - as it is
a top level window already!)
"""
parent = self.parent
if parent and parent != self.__class__():
return parent.top_level_parent
else:
return self

def children(self, **kwargs):
"""Return children of the element"""
raise NotImplementedError()
Expand Down

0 comments on commit df8b9d3

Please sign in to comment.