ํ์ด์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ Windows์์ ๋ฐ์คํฌํ GUI ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ํํ๋ ์คํ ์์ค ํ๋ก์ ํธ์ ๋๋ค. ์ง๋ 2๋ ๋์ ์๋ก์ด ์ฃผ์ ๊ธฐ๋ฅ์ด ๋ฑ์ฅํ์ต๋๋ค.
- MS UI ์๋ํ ๊ธฐ์ ์ ์ง์ํฉ๋๋ค. ์ธํฐํ์ด์ค๋ ๋์ผํ๋ฉฐ ์ด์ WinForms, WPF, Qt5, Windows Store(UWP) ๋ฑ Windows์ ์๋ ๊ฑฐ์ ๋ชจ๋ ํญ๋ชฉ์ ์ง์ํฉ๋๋ค.
- ๋ฐฑ์๋/ํ๋ฌ๊ทธ์ธ ์์คํ
(ํ์ฌ ๋ด๋ถ์ ์ผ๋ก ๋ ๊ฐ์ง๊ฐ ์์: ๊ธฐ๋ณธ๊ฐ)
"win32"๊ทธ๋ฆฌ๊ณ ์๋ก์ด"uia"). ๊ทธ๋ฐ ๋ค์ ํฌ๋ก์ค ํ๋ซํผ์ผ๋ก ์ํํ๊ฒ ์ด๋ํฉ๋๋ค. - ๋ง์ฐ์ค ๋ฐ ํค๋ณด๋์ฉ Win32 ํํฌ(pyHook ์ ์ ์ ๋จ์ถํค).
๋ํ ๋ฐ์คํฌํฑ ์๋ํ๋ฅผ ์ํด ์คํ ์์ค์์ ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ ๋ํ ๊ฐ๋ตํ ๊ฐ์๋ฅผ ์ ๊ณตํฉ๋๋ค(์ฌ๊ฐํ ๋น๊ต๋ฅผ ๊ฐ์ฅํ์ง ์๊ณ ).
์ด ๊ธฐ์ฌ๋ ๋ฏผ์คํฌ์์ ์ด๋ฆฐ SQA Days 20 ์ปจํผ๋ฐ์ค ๋ณด๊ณ ์์ ์ผ๋ถ ์ฌ๋ณธ์ ๋๋ค( ะธ ), ๋ถ๋ถ์ ์ผ๋ก ๋ฌ์์์ด ๋ฒ์ pywinauto์ฉ.
- ์ฃผ์ ์ ๊ทผ๋ฒ
- ๊ธฐ๋ณธ ๋ฐ์คํฌํ ์ ๊ทผ์ฑ ๊ธฐ์
์ด ๋ถ์ผ์ ์คํ ์์ค์ ๋ํ ๊ฐ๋ตํ ๊ฐ์๋ถํฐ ์์ํ๊ฒ ์ต๋๋ค. ๋ฐ์คํฌํ GUI ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๋ชจ๋ ๊ฒ์ด Selenium์ด ์๋ ์น์ ๊ฒฝ์ฐ๋ณด๋ค ๋ค์ ๋ณต์กํฉ๋๋ค. ์ฃผ์ ์ ๊ทผ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ขํ ๋ฐฉ๋ฒ
ํด๋ฆญ ํฌ์ธํธ๋ฅผ ํ๋์ฝ๋ฉํ์ฌ ์ฑ๊ณต์ ์ธ ํํธ๋ฅผ ๊ธฐ์ํฉ๋๋ค.
[+] ํฌ๋ก์ค ํ๋ซํผ์ผ๋ก ๊ตฌํ์ด ์ฝ์ต๋๋ค.
[+] ํ
์คํธ ๋
น์์ "๋
น์-์ฌ์"ํ๋ ๊ฒ์ ์ฝ์ต๋๋ค.
[-] ํ๋ฉด ํด์๋, ํ
๋ง, ๊ธ๊ผด, ์ฐฝ ํฌ๊ธฐ ๋ฑ์ ๋ณ๊ฒฝํ๋ ๋ฐ ๊ฐ์ฅ ๋ถ์์ ํฉ๋๋ค.
[-] ๋ง๋ํ ์ง์ ๋
ธ๋ ฅ์ด ํ์ํฉ๋๋ค. ํ
์คํธ๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ์์ฑํ๊ฑฐ๋ ์๋์ผ๋ก ํ
์คํธํ๋ ๊ฒ์ด ๋ ์ฌ์ด ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
[-] ์์
๋ง ์๋ํํฉ๋๋ค. ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๊ณ ๊ฒ์ํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
๋๊ตฌ(ํฌ๋ก์ค ํ๋ซํผ): , , ๊ทธ๋ฆฌ๊ณ ๋ง์ ๋ค๋ฅธ ์ฌ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋ ๋ณต์กํ ๋๊ตฌ์๋ ์ด ๊ธฐ๋ฅ์ด ํฌํจ๋ฉ๋๋ค(ํญ์ ํฌ๋ก์ค ํ๋ซํผ์ธ ๊ฒ์ ์๋).
์ขํ ๋ฐฉ๋ฒ์ด ๋ค๋ฅธ ์ ๊ทผ๋ฒ์ ๋ณด์ํ ์ ์๋ค๋ ์ ์ ๋งํ ๊ฐ์น๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์ ์ ์ ๊ทธ๋ํฝ์ ๊ฒฝ์ฐ ์๋ ์ขํ(์ ์ฒด ํ๋ฉด์ด ์๋ ์ฐฝ/์์์ ์ผ์ชฝ ์๋จ ๋ชจ์๋ฆฌ์์)๋ฅผ ํด๋ฆญํ ์ ์์ต๋๋ค. ์ด๋ ํนํ ๊ทธ๋ํฝ์ ๊ธธ์ด/ํญ์ ๊ณ ๋ คํ๋ ๊ฒฝ์ฐ ๋งค์ฐ ์์ ์ ์ ๋๋ค. ์ ์ฒด ์์(๊ทธ๋ฌ๋ฉด ๋ค๋ฅธ ํ๋ฉด ํด์๋๊ฐ ์์๋์ง ์์ต๋๋ค).
๋ ๋ค๋ฅธ ์ต์ : ํ ์คํธ๋ฅผ ์ํด ์์ ์ ์ธ ์ค์ ์ ๊ฐ์ถ ๋จธ์ ํ๋๋ง ํ ๋นํฉ๋๋ค(ํฌ๋ก์ค ํ๋ซํผ์ ์๋์ง๋ง ์ด๋ค ๊ฒฝ์ฐ์๋ ์ข์ต๋๋ค).
์ฐธ์กฐ ์ด๋ฏธ์ง ์ธ์
[+] ํฌ๋ก์ค ํ๋ซํผ[+-] ์๋์ ์ผ๋ก ์์ ์ ์ด์ง๋ง(์ขํ ๋ฐฉ๋ฒ๋ณด๋ค ์ข์) ์ฌ์ ํ ๋ช ๊ฐ์ง ํธ๋ฆญ์ด ํ์ํฉ๋๋ค.
[-+] ์๋์ ์ผ๋ก ๋๋ฆฝ๋๋ค. ์๋ํ๋ฉด ์ธ์ ์๊ณ ๋ฆฌ์ฆ์ ์ํด์๋ CPU ๋ฆฌ์์ค๊ฐ ํ์ํฉ๋๋ค.
[-] ๋ฌธ์ ์ธ์(OCR)์ ์์น์ ์ผ๋ก ๋ถ๊ฐ๋ฅํฉ๋๋ค. => ๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋ด๊ฐ ์๋ ํ, ๊ธฐ์กด OCR ์๋ฃจ์ ์ ์ด๋ฌํ ์ ํ์ ์์ ์ ๊ทธ๋ค์ง ์ ๋ขฐํ ์ ์์ผ๋ฉฐ ๋๋ฆฌ ์ฌ์ฉ๋์ง ์์ต๋๋ค(์์ง ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ์๊ฒฌ์ ๋ณด๋ด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค).
๋๊ตฌ : , (Sikuli ํธํ, ์์ Python), .
์ ๊ทผ์ฑ ๊ธฐ์
[+] ๊ฐ์ฅ ์ ๋ขฐํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์์คํ ์ด๋ ํ๋ ์์ํฌ์์ ํ ์คํธ๊ฐ ๋ ๋๋ง๋๋ ๋ฐฉ์์ ๊ด๊ณ์์ด ํ ์คํธ๋ก ๊ฒ์ํ ์ ์์ต๋๋ค.[+] ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ ์ ์์ต๋๋ค => ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ๋ ์ฝ๊ฒ ํ์ธํ ์ ์์ต๋๋ค.
[+] ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ฅ ๋น ๋ฆ ๋๋ค. CPU ๋ฆฌ์์ค๋ฅผ ๊ฑฐ์ ์๋ชจํ์ง ์์ต๋๋ค.
[-] ํฌ๋ก์ค ํ๋ซํผ ๋๊ตฌ๋ฅผ ๋ง๋๋ ๊ฒ์ ์ด๋ ต์ต๋๋ค. ๋ชจ๋ ์คํ ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ ๋๋ ๋ ๊ฐ์ ์ ๊ทผ์ฑ ๊ธฐ์ ์ ์ง์ํฉ๋๋ค. Windows/Linux/MacOS๋ TestComplete, UFT ๋๋ Squish์ ๊ฐ์ ์ ๋ฃ ์ ํ์ ์ ์ธํ๊ณ ๋ ์๋ฒฝํ๊ฒ ์ง์๋์ง ์์ต๋๋ค.
[-] ์ด๋ฌํ ๊ธฐ์ ์ ์์น์ ์ผ๋ก ํญ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒ์ ์๋๋๋ค. ์๋ฅผ ๋ค์ด VirtualBox ๋ด๋ถ์ ๋ก๋ฉ ํ๋ฉด์ ํ ์คํธํ๋ ๊ฒ์ ์ด๋ฏธ์ง ์ธ์ ์์ด๋ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ง์ ๊ณ ์ ์ ์ธ ๊ฒฝ์ฐ์๋ ์ ๊ทผ์ฑ ์ ๊ทผ ๋ฐฉ์์ด ์ฌ์ ํ ์ ์ฉ ๊ฐ๋ฅํฉ๋๋ค. ์ด์ ๋ํด์๋ ๋ ์์ธํ ๋ ผ์ํ๊ฒ ์ต๋๋ค.
๋๊ตฌ : C#์์๋ C#(์ ๋ ๋ ํธํ) C#(Appium ํธํ), , (LDTP ํธํ) , ๋ฃจ๋น์์๋ (Linux Desktop Testing Project) ๋ฐ ํด๋น Windows ๋ฒ์ .
LDTP๋ ์๋ง๋ ์ ๊ทผ์ฑ ๊ธฐ์ ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ์ ์ผํ ํฌ๋ก์ค ํ๋ซํผ ์คํ ์์ค ๋๊ตฌ(๋ณด๋ค ์ ํํ๊ฒ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ํ๊ตฐ)์ผ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๊ทธ๋ค์ง ์ธ๊ธฐ๊ฐ ์์ต๋๋ค. ์ง์ ์ฌ์ฉํด๋ณธ ์ ์ ์์ง๋ง ๋ฆฌ๋ทฐ์ ๋ฐ๋ฅด๋ฉด ์ธํฐํ์ด์ค๊ฐ ๊ฐ์ฅ ํธ๋ฆฌํ์ง ์์ต๋๋ค. ๊ธ์ ์ ์ธ ํผ๋๋ฐฑ์ด ์์ผ์๋ฉด ๋๊ธ๋ก ๊ณต์ ํด์ฃผ์ธ์.
๋ฐฑ๋์ด ํ ์คํธ(์ค๋ด ์์ ๊ฑฐ๋ผ๊ณ ๋ ํจ)
ํฌ๋ก์ค ํ๋ซํผ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ๊ฐ๋ฐ์๋ ํ ์คํธ ๊ฐ๋ฅ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ด๋ถ ๋ฉ์ปค๋์ฆ์ ๋ง๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋น์ค TCP ์๋ฒ๋ฅผ ์์ฑํ๊ณ , ์ด์ ๋ํ ์ฐ๊ฒฐ์ ํ ์คํธํ๊ณ , ํด๋ฆญํ ํญ๋ชฉ, ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์์น ๋ฑ ํ ์คํธ ๋ช ๋ น์ ๋ณด๋ ๋๋ค. ์ ๋ขฐํ ์ ์์ง๋ง ๋ณดํธ์ ์ด์ง๋ ์์ต๋๋ค.
๊ธฐ๋ณธ ๋ฐ์คํฌํ ์ ๊ทผ์ฑ ๊ธฐ์
์ข์ ์ค๋๋ Win32 API
WPF ์ถ์ ์ด์ ์ ์์ฑ๋ ๋๋ถ๋ถ์ Windows ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ Windows ์คํ ์ด๋ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ Win32 API๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค. ์ฆ, MFC, WTL, C++ Builder, Delphi, VB6 ๋ฑ ์ด๋ฌํ ๋ชจ๋ ๋๊ตฌ๋ Win32 API๋ฅผ ์ฌ์ฉํฉ๋๋ค. Windows Forms๋ ๋๋ถ๋ถ Win32 API์ ํธํ๋ฉ๋๋ค.
๋๊ตฌ : (VB์ ์ ์ฌ) ๋ฐ Python ๋ํผ , (์์ ์ ์ธ์ด์๋ IDispatch COM ์ธํฐํ์ด์ค๊ฐ ์์ต๋๋ค), (ํ์ด์ฌ) (๋ฃจ๋น) (๋ฃจ๋น).
๋ง์ดํฌ๋ก์ํํธ UI ์๋ํ
์ฃผ์ ์ด์ : MS UI ์๋ํ ๊ธฐ์ ์ ๋๋ฌธ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ Windows์์ ๋๋ถ๋ถ์ GUI ์์ฉ ํ๋ก๊ทธ๋จ์ ์ง์ํฉ๋๋ค. ๋ฌธ์ : Win32 API๋ณด๋ค ๋ฐฐ์ฐ๊ธฐ๊ฐ ๊ทธ๋ฆฌ ์ฝ์ง ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฌด๋ ๊ทธ ์์ ํฌ์ฅ์ง๋ฅผ ๋ง๋ค์ง ์์ ๊ฒ์ ๋๋ค.
์ค์ ๋ก ์ด๊ฒ์ ์ฌ์ฉ์ ์ ์ COM ์ธํฐํ์ด์ค ์ธํธ์
๋๋ค(์ฃผ๋ก UIAutomationCore.dll), ๋ค์ ํ์์ .NET ๋ํผ๋ ์์ต๋๋ค. namespace System.Windows.Automation. ๊ทธ๋ฐ๋ฐ ์ผ๋ถ UI ์์๊ฐ ๋๋ฝ๋ ์ ์๋ ๋ฒ๊ทธ๊ฐ ๋์
๋์์ต๋๋ค. ๋ฐ๋ผ์ UIAutomationCore.dll์ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข์ต๋๋ค(C#์ UiaComWrapper์ ๋ํด ๋ค์ด๋ณธ ์ ์ด ์๋ค๋ฉด ์ด๊ฒ์ด ๋ฐ๋ก ๊ทธ๊ฒ์
๋๋ค).
COM ์ธํฐํ์ด์ค ์ ํ:
(1) ๊ธฐ๋ณธ IUknown โ โ๋ชจ๋ ์
์ ๊ทผ์โ. ๊ฐ์ฅ ๋ฎ์ ์์ค์ด๋ฉฐ ๊ฒฐ์ฝ ์ฌ์ฉ์ ์นํ์ ์ด์ง ์์ต๋๋ค.
(2) IDispatch ๋ฐ ํ์๋ฌผ(์: Excel.Application), win32com.client ํจํค์ง(pyWin32์ ํฌํจ๋จ)๋ฅผ ์ฌ์ฉํ์ฌ Python์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ฐ์ฅ ํธ๋ฆฌํ๊ณ ์๋ฆ๋ค์ด ์ต์
์
๋๋ค.
(3) ํ์ฌ Python ํจํค์ง์ ํจ๊ป ์๋ํ ์ ์๋ ์ฌ์ฉ์ ์ ์ ์ธํฐํ์ด์ค .
๋๊ตฌ : C#์์๋ 0.6.0 +, C#์์๋ (UIAutomationCore.dll์ ๋ํ C ๋ํผ์ ์์ค ์ฝ๋๋ ๊ณต๊ฐ๋์ง ์์ต๋๋ค.) ๋ฃจ๋น์์.
AT-SPI
Linux ์ ํ๊ตฐ์ ๊ฑฐ์ ๋ชจ๋ ์ถ์ด X Window ์์คํ (Fedora 25์์๋ "X"๊ฐ Wayland๋ก ๋ณ๊ฒฝ๋จ)์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์์๋ ๋ถ๊ตฌํ๊ณ "X"๋ฅผ ์ฌ์ฉํ๋ฉด ์ต์์ ์ฐฝ๊ณผ ๋ง์ฐ์ค/ ๊ฑด๋ฐ. ๋ฒํผ, ๋ชฉ๋ก ์์ ๋ฑ์ ๋ํ ์์ธํ ๋ถ์์ ์ํด AT-SPI ๊ธฐ์ ์ด ์์ต๋๋ค. ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ฐฝ ๊ด๋ฆฌ์์๋ ์์ฉ ํ๋ก๊ทธ๋จ์ ์๋ํ๋ GUI๋ฅผ ์ ๊ณตํ๋ ์์ AT-SPI ๋ ์ง์คํธ๋ฆฌ ๋ฐ๋ชฌ์ด ์์ต๋๋ค(์ ์ด๋ Qt ๋ฐ GTK๊ฐ ์ง์๋จ).
๋๊ตฌ : .
์ ์๊ฐ์๋ pyatspi2์๋ PyGObject์ ๊ฐ์ ์ข
์์ฑ์ด ๋๋ฌด ๋ง์ด ํฌํจ๋์ด ์์ต๋๋ค. ๊ธฐ์ ์์ฒด๋ ์ผ๋ฐ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฌ์ฉ ๊ฐ๋ฅ libatspi.so. ์ด์๋ค . pywinauto ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฒฝ์ฐ libatspi.so ๋ฐ ctypes ๋ชจ๋์ ๋ก๋ํ๋ ๋ฐฉ์์ผ๋ก AT-SPI ์ง์์ ๊ตฌํํ ๊ณํ์
๋๋ค. GTK+์ Qt ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฒฝ์ฐ ์ฝ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ํ์ํ ๋ฒ์ ์ ์ฌ์ฉํ๋ ๋ฐ์๋ง ์์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. Linux๋ฅผ ์๋ฒฝํ๊ฒ ์ง์ํ๋ pywinauto 0.7.0์ด 2018๋
์๋ฐ๊ธฐ์ ์ถ์๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
Apple ์ ๊ทผ์ฑ API
MacOS์๋ ์์ฒด ์๋ํ ์ธ์ด์ธ AppleScript๊ฐ ์์ต๋๋ค. ๋ฌผ๋ก Python์์ ์ด์ ๊ฐ์ ๊ฒ์ ๊ตฌํํ๋ ค๋ฉด ObjectiveC์ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. MacOS 10.6๋ถํฐ pyobjc ํจํค์ง๊ฐ ์ฌ์ ์ค์น๋ Python์ ํฌํจ๋์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ ๋ํ pywinauto์ ํฅํ ์ง์์ ์ํ ์ข ์์ฑ์ ๋์ดํ๋ ๊ฒ์ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
๋๊ตฌ: Apple ์คํฌ๋ฆฝํธ ์ธ์ด ์ธ์๋ ์ฃผ๋ชฉํ ๊ฐ์น๊ฐ ์์ต๋๋ค. , ์ผ๋ช
pyatom. LDTP์ ์ธํฐํ์ด์ค ํธํ๋์ง๋ง ๋
๋ฆฝํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๊ธฐ๋ ํฉ๋๋ค. ๊ทธ๊ฒ์ ๊ฐ์ง๊ณ ์๋ค , ๋ด ํ์์ด ์ด ๊ฒ์
๋๋ค. ์๋ ค์ง ๋ฌธ์ ๊ฐ ์์ต๋๋ค: ์ ์ฐํ ํ์ด๋ฐ์ด ์๋ํ์ง ์์ต๋๋ค(๋ฉ์๋ waitFor*). ํ์ง๋ง ์ ๋ฐ์ ์ผ๋ก ๋์ ๊ฒ์ ์๋๋๋ค.
pywinauto๋ฅผ ์์ํ๋ ๋ฐฉ๋ฒ
์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ GUI ๊ฐ์ฒด ๊ฒ์ฌ๊ธฐ(์คํ์ด ๋๊ตฌ๋ผ๊ณ ํจ)๋ก ๋ฌด์ฅํ๋ ๊ฒ์ ๋๋ค. ์์์ ๊ณ์ธต ๊ตฌ์กฐ๊ฐ ์ด๋ป๊ฒ ๊ตฌ์ฑ๋์ด ์๋์ง, ์ด๋ค ์์ฑ์ ์ฌ์ฉํ ์ ์๋์ง ๋ฑ ๋ด๋ถ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฐ๊ตฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ๊ฐ์ฅ ์ ๋ช ํ ํ์ฅ ์กฐ์ฌ๊ด:
- ์คํ์ด++ - Express ๋๋ Community Edition์ ํฌํจํ Visual Studio์ ํฌํจ๋์ด ์์ต๋๋ค. Win32 API๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ์ ํด๋ก ๋ ์๋ ค์ ธ ์์ต๋๋ค AutoIt ์ฐฝ ์ ๋ณด.
- ๊ฒ์ฌ.exe - Windows SDK์ ํฌํจ๋์ด ์์ต๋๋ค. ์ค์นํ๋ค๋ฉด 64๋นํธ Windows์์๋ ํด๋์์ ์ฐพ์ ์ ์์ต๋๋ค.
C:Program Files (x86)Windows Kits<winver>binx64. ์ธ์คํํฐ ์์ฒด์์ ๋ชจ๋๋ฅผ ์ ํํด์ผ ํฉ๋๋ค UI ์๋ํ MS AA(UI ์๋ํ์ ์กฐ์์ธ Active Accessibility) ๋์ .
์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒ ์ ํ๊ฒ ๊ฒํ ํ ํ ์ฌ์ฉํ ๋ฐฑ์๋๋ฅผ ์ ํํฉ๋๋ค. Application ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ๋ฐฑ์๋ ์ด๋ฆ์ ์ง์ ํ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค.
- ๋ฐฑ์๋=โwin32โณ โ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ๋์ง๋ง MFC, WTL, VB6 ๋ฐ ๊ธฐํ ๋ ๊ฑฐ์ ์์ฉ ํ๋ก๊ทธ๋จ๊ณผ ์ ์๋ํฉ๋๋ค.
- ๋ฐฑ์๋=โuiaโ โ MS UI ์๋ํ๋ฅผ ์ํ ์๋ก์ด ๋ฐฑ์๋: WPF ๋ฐ WinForms์ ์๋ฒฝํ๊ฒ ์๋ํฉ๋๋ค. Delphi ๋ฐ Windows Store ์ ํ๋ฆฌ์ผ์ด์
์๋ ์ ํฉํฉ๋๋ค. Qt5 ๋ฐ ์ผ๋ถ Java ์ ํ๋ฆฌ์ผ์ด์
์์ ์๋ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก Inspect.exe๊ฐ ์์์ ํด๋น ์์ฑ์ ํ์ธํ๋ ๊ฒฝ์ฐ ์ด ๋ฐฑ์๋๊ฐ ์ ํฉํฉ๋๋ค. ์์น์ ์ผ๋ก ๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ๋ UI ์๋ํ๋ ์ง์ํฉ๋๋ค(Mozilla๋ ๊ธฐ๋ณธ์ ์ผ๋ก Chrome์ ์์ํ ๋ ๋ช
๋ น์ค ํค๋ฅผ ์
๋ ฅํด์ผ ํฉ๋๋ค).
--force-renderer-accessibilityInspect.exe์ ํ์ด์ง ์์๋ฅผ ๋ณด๋ ค๋ฉด). ๋ฌผ๋ก ์ด ๋ถ์ผ์์ ์ ๋ ๋๊ณผ์ ๊ฒฝ์์ ๊ฑฐ์ ๋ถ๊ฐ๋ฅํ๋ค. ๋ธ๋ผ์ฐ์ ๋ก ์์ ํ๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋๋ค(์ ํ ๊ฐ ์๋๋ฆฌ์ค์ ์ ์ฉํ ์ ์์).
์๋ํ๋ฅผ ์ํ ์ง์ ์
์์ฉ ํ๋ก๊ทธ๋จ์ ๊ด๋ฒ์ํ๊ฒ ์ฐ๊ตฌ๋์์ต๋๋ค. ์ด์ Application ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ์คํํ๊ฑฐ๋ ์ด๋ฏธ ์คํ ์ค์ธ ๊ฐ์ฒด์ ์ฐ๊ฒฐํ ์ฐจ๋ก์
๋๋ค. ์ด๊ฒ์ ๋จ์ง ํ์ค ํด๋์ค์ ๋ณต์ ๊ฐ ์๋๋๋ค. subprocess.Popen, ์ฆ ๋ชจ๋ ์์
์ ํ๋ก์ธ์ค ๊ฒฝ๊ณ๋ก ์ ํํ๋ ์
๋ ฅ ๊ฐ์ฒด์
๋๋ค. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ๋ฌ ์ธ์คํด์ค๊ฐ ์คํ ์ค์ด์ง๋ง ๋๋จธ์ง ์ธ์คํด์ค๋ ๊ฑด๋๋ฆฌ๊ณ ์ถ์ง ์์ ๊ฒฝ์ฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# ะะฟะธัะตะผ ะพะบะฝะพ, ะบะพัะพัะพะต ั
ะพัะธะผ ะฝะฐะนัะธ ะฒ ะฟัะพัะตััะต Notepad.exe
dlg_spec = app.UntitledNotepad
# ะถะดะตะผ ะฟะพะบะฐ ะพะบะฝะพ ัะตะฐะปัะฝะพ ะฟะพัะฒะธััั
actionable_dlg = dlg_spec.wait('visible')์ฌ๋ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๋์์ ๊ด๋ฆฌํ๊ณ ์ถ๋ค๋ฉด ์ด ์์
์ด ๋์์ด ๋ ๊ฒ์
๋๋ค. Desktop. ์๋ฅผ ๋ค์ด, Win10์ ๊ณ์ฐ๊ธฐ์์ ์์์ ๊ณ์ธต ๊ตฌ์กฐ๋ ์ฌ๋ฌ ํ๋ก์ธ์ค์ ๋ถ์ฐ๋์ด ์์ต๋๋ค(๋ฟ๋ง ์๋๋ผ calc.exe). ๊ทธ๋์ ๋ณ๊ฑฐ ์์ Desktop ์ถฉ๋ถํ์ง ์์ต๋๋ค.
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')๋ฃจํธ ๊ฐ์ฒด(Application ๋๋ Desktop)์ ๋ฐฑ์๋๋ฅผ ์ง์ ํด์ผ ํ๋ ์ ์ผํ ์ฅ์์
๋๋ค. ๋ค๋ฅธ ๋ชจ๋ ๊ฒ์ ๋์ค์ ๋
ผ์๋ "์ฌ์->๋ํผ" ๊ฐ๋
์ ํฌ๋ช
ํ๊ฒ ์ํฉ๋๋ค.
์ฐฝ/์์ ์ฌ์
์ด๊ฒ์ด pywinauto ์ธํฐํ์ด์ค๊ฐ ๊ตฌ์ถ๋ ํต์ฌ ๊ฐ๋ ์ ๋๋ค. ์ฐฝ/์์๊ฐ ์์ง ์กด์ฌํ์ง ์๊ฑฐ๋ ์ด๋ฏธ ๋ซํ ์๋๋ผ๋ ๋๋ต์ ์ผ๋ก ๋๋ ๋ ์์ธํ ์ค๋ช ํ ์ ์์ต๋๋ค. ์ฐฝ ์ฌ์(๊ฐ์ฒด ์ฐฝ์ฌ์)์ ์ค์ ์ฐฝ์ด๋ ์์๋ฅผ ๊ฒ์ํ๋ ๊ธฐ์ค์ ์ ์ฅํฉ๋๋ค.
์์ธํ ์ฐฝ ์ฌ์์ ์:
>>> dlg_spec = app.window(title='Untitled - Notepad')
>>> dlg_spec
<pywinauto.application.WindowSpecification object at 0x0568B790>
>>> dlg_spec.wrapper_object()
<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>์ฐฝ ๊ฒ์ ์์ฒด๋ ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ฐ์ํฉ๋๋ค. .wrapper_object(). ์ค์ ์ฐฝ/์์์ ๋ํ ํน์ "๋ํผ"๋ฅผ ๋ฐํํ๊ฑฐ๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค. ElementNotFoundError (๋๋๋ก ElementAmbiguousError, ์ฌ๋ฌ ์์๊ฐ ๋ฐ๊ฒฌ๋ ๊ฒฝ์ฐ, ์ฆ ๊ฒ์ ๊ธฐ์ค์ ๋ช
ํํ ํด์ผ ํฉ๋๋ค. ์ด "๋ํผ"๋ ์์๋ก ์ผ๋ถ ์์
์ ์ํํ๊ฑฐ๋ ํด๋น ์์์์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ๋ฐฉ๋ฒ์ ์ด๋ฏธ ์๊ณ ์์ต๋๋ค.
Python์ ํธ์ถ์ ์จ๊ธธ ์ ์์ต๋๋ค .wrapper_object()์ด๋ฏ๋ก ์ต์ข
์ฝ๋๊ฐ ๋ ์งง์์ง๋๋ค. ๋๋ฒ๊น
๋ชฉ์ ์ผ๋ก๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ค์ ๋ ์ค์ ์ ํํ ๋์ผํ ์์
์ ์ํํฉ๋๋ค.
dlg_spec.wrapper_object().minimize() # debugging
dlg_spec.minimize() # production์ฐฝ ์ฌ์์ ๋ํ ๊ฒ์ ๊ธฐ์ค์ ๋ค์ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์์ ๋๋ค.
# ะผะพะณัั ะธะผะตัั ะฝะตัะบะพะปัะบะพ ััะพะฒะฝะตะน
app.window(title_re='.* - Notepad$').window(class_name='Edit')
# ะผะพะถะฝะพ ะบะพะผะฑะธะฝะธัะพะฒะฐัั ะบัะธัะตัะธะธ (ะบะฐะบ AND) ะธ ะฝะต ะพะณัะฐะฝะธัะธะฒะฐัััั ะพะดะฝะธะผ ะฟัะพัะตััะพะผ ะฟัะธะปะพะถะตะฝะธั
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')๊ฐ๋ฅํ ๋ชจ๋ ๊ธฐ์ค ๋ชฉ๋ก์ ํจ์ ๋ฌธ์์ ์์ต๋๋ค. .
์์ฑ๊ณผ ํค๋ฅผ ํตํ ์ ๊ทผ์ ๋ง๋ฒ
Python์ ์ฌ์ฉํ๋ฉด ์ฐฝ ์ฌ์์ ์ฝ๊ฒ ๋ง๋ค๊ณ ๊ฐ์ฒด ์์ฑ์ ๋์ ์ผ๋ก ์ธ์ํ ์ ์์ต๋๋ค. (๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ ์๋ฉ๋๋ค.) __getattribute__). ๋ฌผ๋ก ์์ฑ ์ด๋ฆ์๋ ๋ณ์ ์ด๋ฆ๊ณผ ๋์ผํ ์ ํ์ด ์ ์ฉ๋ฉ๋๋ค(๊ณต๋ฐฑ, ์ผํ ๋๋ ๊ธฐํ ํน์ ๋ฌธ์๋ฅผ ์ฝ์
ํ ์ ์์). ๋คํ์ค๋ฝ๊ฒ๋ pywinauto๋ ์คํ์ ์์ ๋ณํ์ ๊ฐํ ์์ "์ต์ ์ผ์น" ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํฉ๋๋ค.
app.UntitledNotepad
# ัะพ ะถะต ัะฐะผะพะต, ััะพ
app.window(best_match='UntitledNotepad')์ฌ์ ํ ์ ๋์ฝ๋ ๋ฌธ์์ด(์: ๋ฌ์์์ด์ ๊ฒฝ์ฐ), ๊ณต๋ฐฑ ๋ฑ์ด ํ์ํ ๊ฒฝ์ฐ ์ผ๋ฐ ์ฌ์ ์ธ ๊ฒ์ฒ๋ผ ํค๋ก ์ก์ธ์คํ ์ ์์ต๋๋ค.
app['Untitled - Notepad']
# ัะพ ะถะต ัะฐะผะพะต, ััะพ
app.window(best_match='Untitled - Notepad')๋ง๋ฒ์ ์ด๋ฆ์ ๋ํ ๋ค์ฏ ๊ฐ์ง ๊ท์น
ํ์ค ๋ง๋ฒ ์ด๋ฆ์ ์ฐพ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น? ๊ฒ์ ์ ์์์ ํ ๋น๋ ๊ฒ๋ค์ ๋๋ค. ํ์ค๊ณผ ์ถฉ๋ถํ ์ ์ฌํ ์ด๋ฆ์ ์ง์ ํ๋ฉด ํด๋น ์์๊ฐ ๊ฒ์๋ฉ๋๋ค.
- ์ ๋ชฉ(ํ
์คํธ, ์ด๋ฆ)๋ณ:
app.Properties.OK.click() - ํ
์คํธ ๋ฐ ์์ ์ ํ๋ณ:
app.Properties.OKButton.click() - ์ ํ ๋ฐ ๊ฐ์๋ณ:
app.Properties.Button3.click()(์ด๋ฆButton0ะธButton1๋ฐ๊ฒฌ๋ ์ฒซ ๋ฒ์งธ ์์์ ๋ฐ์ธ๋ฉ๋ฉ๋๋ค.Button2- ๋ ๋ฒ์งธ๊น์ง, ๊ทธ๋ฆฌ๊ณ ์์๋๋ก - ์ด๊ฒ์ด ์ญ์ฌ์ ์ผ๋ก ์ผ์ด๋ ์ผ์ ๋๋ค) - ์ ์ ํ
์คํธ(์ผ์ชฝ ๋๋ ์์ชฝ) ๋ฐ ์ ํ๋ณ:
app.OpenDialog.FileNameEdit.set_text("")(๋์ ํ ์คํธ๊ฐ ์๋ ์์์ ์ ์ฉํจ) - ์ ํ๋ณ ๋ฐ ๋ด๋ถ ํ
์คํธ๋ณ:
app.Properties.TabControlSharing.select("General")
์ผ๋ฐ์ ์ผ๋ก ๋ ๊ฐ ๋๋ ์ธ ๊ฐ์ ๊ท์น์ด ๋์์ ์ ์ฉ๋๋ฉฐ ๋๋ฌผ๊ฒ ๋ ๋ง์ด ์ ์ฉ๋ฉ๋๋ค. ๊ฐ ์์์ ์ฌ์ฉ ๊ฐ๋ฅํ ํน์ ์ด๋ฆ์ ํ์ธํ๋ ค๋ฉด ๋ค์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. print_control_identifiers(). ํ๋ฉด๊ณผ ํ์ผ ๋ชจ๋์ ์์ ํธ๋ฆฌ๋ฅผ ์ธ์ํ ์ ์์ต๋๋ค. ๊ฐ ์์์ ๋ํด ํ์ค ๋ง๋ฒ ์ด๋ฆ์ด ์ธ์๋ฉ๋๋ค. ์ฌ๊ธฐ์์ ํ์ ์์์ ๋ํ ๋ณด๋ค ์์ธํ ์ฌ์์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ์ ์๋ ์์ต๋๋ค. ์คํฌ๋ฆฝํธ์ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
app.Properties.child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")์์ ํธ๋ฆฌ ์์ฒด๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค์ ํฐ ์กฑ๋ณด์ ๋๋ค.
>>> app.Properties.print_control_identifiers()
Control Identifiers:
Dialog - 'Windows NT Properties' (L688, T518, R1065, B1006)
[u'Windows NT PropertiesDialog', u'Dialog', u'Windows NT Properties']
child_window(data-gt-translate-attributes='["title"]' title="Windows NT Properties", control_type="Window")
|
| Image - '' (L717, T589, R749, B622)
| [u'', u'0', u'Image1', u'Image0', 'Image', u'1']
| child_window(auto_id="13057", control_type="Image")
|
| Image - '' (L717, T630, R1035, B632)
| ['Image2', u'2']
| child_window(auto_id="13095", control_type="Image")
|
| Edit - 'Folder name:' (L790, T596, R1036, B619)
| [u'3', 'Edit', u'Edit1', u'Edit0']
| child_window(data-gt-translate-attributes='["title"]' title="Folder name:", auto_id="13156", control_type="Edit")
|
| Static - 'Type:' (L717, T643, R780, B658)
| [u'Type:Static', u'Static', u'Static1', u'Static0', u'Type:']
| child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13080", control_type="Text")
|
| Edit - 'Type:' (L790, T643, R1036, B666)
| [u'4', 'Edit2', u'Type:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13059", control_type="Edit")
|
| Static - 'Location:' (L717, T669, R780, B684)
| [u'Location:Static', u'Location:', u'Static2']
| child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13089", control_type="Text")
|
| Edit - 'Location:' (L790, T669, R1036, B692)
| ['Edit3', u'Location:Edit', u'5']
| child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13065", control_type="Edit")
|
| Static - 'Size:' (L717, T695, R780, B710)
| [u'Size:Static', u'Size:', u'Static3']
| child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13081", control_type="Text")
|
| Edit - 'Size:' (L790, T695, R1036, B718)
| ['Edit4', u'6', u'Size:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13064", control_type="Edit")
|
| Static - 'Size on disk:' (L717, T721, R780, B736)
| [u'Size on disk:', u'Size on disk:Static', u'Static4']
| child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13107", control_type="Text")
|
| Edit - 'Size on disk:' (L790, T721, R1036, B744)
| ['Edit5', u'7', u'Size on disk:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13106", control_type="Edit")
|
| Static - 'Contains:' (L717, T747, R780, B762)
| [u'Contains:1', u'Contains:0', u'Contains:Static', u'Static5', u'Contains:']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13088", control_type="Text")
|
| Edit - 'Contains:' (L790, T747, R1036, B770)
| [u'8', 'Edit6', u'Contains:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")
|
| Image - 'Contains:' (L717, T773, R1035, B775)
| [u'Contains:Image', 'Image3', u'Contains:2']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13096", control_type="Image")
|
| Static - 'Created:' (L717, T786, R780, B801)
| [u'Created:', u'Created:Static', u'Static6', u'Created:1', u'Created:0']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13092", control_type="Text")
|
| Edit - 'Created:' (L790, T786, R1036, B809)
| [u'Created:Edit', 'Edit7', u'9']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13072", control_type="Edit")
|
| Image - 'Created:' (L717, T812, R1035, B814)
| [u'Created:Image', 'Image4', u'Created:2']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13097", control_type="Image")
|
| Static - 'Attributes:' (L717, T825, R780, B840)
| [u'Attributes:Static', u'Static7', u'Attributes:']
| child_window(data-gt-translate-attributes='["title"]' title="Attributes:", auto_id="13091", control_type="Text")
|
| CheckBox - 'Read-only (Only applies to files in folder)' (L790, T825, R1035, B841)
| [u'CheckBox0', u'CheckBox1', 'CheckBox', u'Read-only (Only applies to files in folder)CheckBox', u'Read-only (Only applies to files in folder)']
| child_window(data-gt-translate-attributes='["title"]' title="Read-only (Only applies to files in folder)", auto_id="13075", control_type="CheckBox")
|
| CheckBox - 'Hidden' (L790, T848, R865, B864)
| ['CheckBox2', u'HiddenCheckBox', u'Hidden']
| child_window(data-gt-translate-attributes='["title"]' title="Hidden", auto_id="13076", control_type="CheckBox")
|
| Button - 'Advanced...' (L930, T845, R1035, B868)
| [u'Advanced...', u'Advanced...Button', 'Button', u'Button1', u'Button0']
| child_window(data-gt-translate-attributes='["title"]' title="Advanced...", auto_id="13154", control_type="Button")
|
| Button - 'OK' (L814, T968, R889, B991)
| ['Button2', u'OK', u'OKButton']
| child_window(data-gt-translate-attributes='["title"]' title="OK", auto_id="1", control_type="Button")
|
| Button - 'Cancel' (L895, T968, R970, B991)
| ['Button3', u'CancelButton', u'Cancel']
| child_window(data-gt-translate-attributes='["title"]' title="Cancel", auto_id="2", control_type="Button")
|
| Button - 'Apply' (L976, T968, R1051, B991)
| ['Button4', u'ApplyButton', u'Apply']
| child_window(data-gt-translate-attributes='["title"]' title="Apply", auto_id="12321", control_type="Button")
|
| TabControl - '' (L702, T556, R1051, B962)
| [u'10', u'TabControlSharing', u'TabControlPrevious Versions', u'TabControlSecurity', u'TabControl', u'TabControlCustomize']
| child_window(auto_id="12320", control_type="Tab")
| |
| | TabItem - 'General' (L704, T558, R753, B576)
| | [u'GeneralTabItem', 'TabItem', u'General', u'TabItem0', u'TabItem1']
| | child_window(data-gt-translate-attributes='["title"]' title="General", control_type="TabItem")
| |
| | TabItem - 'Sharing' (L753, T558, R801, B576)
| | [u'Sharing', u'SharingTabItem', 'TabItem2']
| | child_window(data-gt-translate-attributes='["title"]' title="Sharing", control_type="TabItem")
| |
| | TabItem - 'Security' (L801, T558, R851, B576)
| | [u'Security', 'TabItem3', u'SecurityTabItem']
| | child_window(data-gt-translate-attributes='["title"]' title="Security", control_type="TabItem")
| |
| | TabItem - 'Previous Versions' (L851, T558, R947, B576)
| | [u'Previous VersionsTabItem', u'Previous Versions', 'TabItem4']
| | child_window(data-gt-translate-attributes='["title"]' title="Previous Versions", control_type="TabItem")
| |
| | TabItem - 'Customize' (L947, T558, R1007, B576)
| | [u'CustomizeTabItem', 'TabItem5', u'Customize']
| | child_window(data-gt-translate-attributes='["title"]' title="Customize", control_type="TabItem")
|
| TitleBar - 'None' (L712, T521, R1057, B549)
| ['TitleBar', u'11']
| |
| | Menu - 'System' (L696, T526, R718, B548)
| | [u'System0', u'System', u'System1', u'Menu', u'SystemMenu']
| | child_window(data-gt-translate-attributes='["title"]' title="System", auto_id="MenuBar", control_type="MenuBar")
| | |
| | | MenuItem - 'System' (L696, T526, R718, B548)
| | | [u'System2', u'MenuItem', u'SystemMenuItem']
| | | child_window(data-gt-translate-attributes='["title"]' title="System", control_type="MenuItem")
| |
| | Button - 'Close' (L1024, T519, R1058, B549)
| | [u'CloseButton', u'Close', 'Button5']
| | child_window(data-gt-translate-attributes='["title"]' title="Close", control_type="Button")์ด๋ค ๊ฒฝ์ฐ์๋ ์ ์ฒด ํธ๋ฆฌ๋ฅผ ์ธ์ํ๋ ๊ฒ์ด ๋๋ฆด ์ ์์ง๋ง(์๋ฅผ ๋ค์ด iTunes์์๋ ํ๋์ ํญ์ ์ต๋ 3์ฒ ๊ฐ์ ์์๊ฐ ์์ต๋๋ค!) ์ต์
์ ์ฌ์ฉํ ์ ์์ต๋๋ค. depth (๊น์ด): depth=1 - ์์ ์์ฒด, depth=2 - ์ง๊ณ ์๋
๋ง ํด๋น๋ฉ๋๋ค. ์์ฑ ์ ์ฌ์์์ ์ง์ ํ ์๋ ์์ต๋๋ค. child_window.
์
์ง์์ ์ผ๋ก ๋ณด์ถฉํ๊ณ ์์ต๋๋ค . ์ต๊ทผ์๋ WireShark ๋คํธ์ํฌ ๋ถ์๊ธฐ์ ์๋ํ์ ์ฃผ๋ชฉํ ๊ฐ์น๊ฐ ์์ต๋๋ค(์ด๊ฒ์ Qt5 ์ ํ๋ฆฌ์ผ์ด์
์ ์ข์ ์์
๋๋ค. ์ด ์์
์ GUI ์์ด๋ ํด๊ฒฐํ ์ ์์ต๋๋ค. scapy.Sniffer Python ํจํค์ง์์ ). ๋ฆฌ๋ณธ ๋๊ตฌ ๋ชจ์์ ์ฌ์ฉํ MS ๊ทธ๋ฆผํ ์๋ํ์ ์๋ ์์ต๋๋ค.
์ ํ์์ด ์์ฑํ ๋ ๋ค๋ฅธ ํ๋ฅญํ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. (์กฐ๊ธ ํ์ ๋ฉ์ธ ์ ์ฅ์๋ก ์ด๋ํ ์์ ์ ๋๋ค.)
๊ทธ๋ฆฌ๊ณ ๋ฌผ๋ก ํค๋ณด๋(๋จ์ถํค) ๋ฐ ๋ง์ฐ์ค ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋
ํ๋ ์๋ ์์ต๋๋ค.
.
๊ฐ์ฌ์ ๋ง
ํ๋ก์ ํธ ๊ฐ๋ฐ์ ์ง์์ ์ผ๋ก ๋์์ ์ฃผ์๋ ๋ถ๋ค๊ป ํน๋ณํ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ๋์ ์ด๊ฒ์ ์์ํ ์ทจ๋ฏธ์
๋๋ค. UNN์ ๋ด ํ์ ์ค ๋ ๋ช
์ด ์ต๊ทผ ์ด ์ฃผ์ ์ ๋ํ ํ์ฌ ํ์๋ฅผ ์นํธํ์ต๋๋ค. MS UI ์๋ํ ์ง์์ ํฐ ๊ธฐ์ฌ๋ฅผ ํ์ผ๋ฉฐ ์ต๊ทผ์๋ ํ
์คํธ ์์ฑ(๊ฐ์ฅ ๋ณต์กํ ๊ธฐ๋ฅ)์ ๊ธฐ๋ฐ์ผ๋ก ํ "๊ธฐ๋ก ์ฌ์" ์๋ฆฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ์๋ ์ฝ๋ ์์ฑ๊ธฐ๋ฅผ ๋ง๋ค๊ธฐ ์์ํ์ต๋๋ค. ์ง๊ธ๊น์ง๋ "uia" ๋ฐฑ์๋์๋ง ํด๋น๋ฉ๋๋ค. AT-SPI(๋ชจ๋) ๊ธฐ๋ฐ์ ์๋ก์ด Linux์ฉ ๋ฐฑ์๋๋ฅผ ๊ฐ๋ฐ ์ค์
๋๋ค. mouse ะธ keyboard ~์ ๊ทผ๊ฑฐํ์ฌ - ์ด๋ฏธ ๋ฆด๋ฆฌ์ค 0.6.x์ ์์).
์ ๊ฐ Python์ผ๋ก ์๋ํ์ ๋ํ ํน๊ฐ์ ๊ฝค ์ค๋ซ๋์ ๊ฐ์ํด ์๊ธฐ ๋๋ฌธ์ ์ผ๋ถ ์์ฌ ํ์๋ค์ ์๋ํ์ ์์ ๊ธฐ๋ฅ์ด๋ ์์ ๋ฅผ ๊ตฌํํ๋ ์์ ๋ฅผ ํฉ๋๋ค. ์ฐ๊ตฌ ๋จ๊ณ์ ์ผ๋ถ ํต์ฌ ์ฌํญ๋ ํ๋ ํ์๋ค์ ์ํด ๋ฐ๊ตด๋์์ต๋๋ค. ๋๋ก๋ ์ฝ๋ ํ์ง์ ์๊ฒฉํ๊ฒ ๋ชจ๋ํฐ๋งํด์ผ ํ๋ ๊ฒฝ์ฐ๋ ์์ต๋๋ค. ์ฝ 95%์ ์ฝ๋ ์ ์ฉ ๋ฒ์๋ฅผ ๊ฐ์ถ ์ ์ ๋ถ์๊ธฐ(QuantifiedCode, Codacy ๋ฐ Landscape)์ ํด๋ผ์ฐ๋(AppVeyor ์๋น์ค)์ ์๋ ํ ์คํธ๊ฐ ์ด์ ๋ง์ ๋์์ด ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฆฌ๋ทฐ๋ฅผ ๋จ๊ฒจ์ฃผ์๊ณ , ๋ฒ๊ทธ๋ฅผ ์ ๊ธฐํ์๊ณ , Pull Request๋ฅผ ๋ณด๋ด์ฃผ์๋ ๋ชจ๋ ๋ถ๋ค๊ป๋ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
์ถ๊ฐ ๋ฆฌ์์ค
์ฐ๋ฆฌ๋ ์ง๋ฌธ์ ๋ํ ํ์ ์กฐ์น๋ฅผ ์ทจํฉ๋๋ค (์ต๊ทผ์ ๋ฑ์ฅํ ) ๊ทธ๋ฆฌ๊ณ . ์๋ค .
๋งค๋ฌ ์ ๋ฐ์ดํธํฉ๋๋ค . GitHub์ ๋ณ ์์ ๊ด๋ จํ์ฌ Autohotkey(๋งค์ฐ ํฐ ์ปค๋ฎค๋ํฐ์ ์ค๋ ์ญ์ฌ๋ฅผ ๊ฐ์ง๊ณ ์์)์ PyAutoGUI๋ง์ด ๋ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ๊ณ ์์ต๋๋ค. Python' ๋ฑ).
์ถ์ฒ : habr.com
