프날 오토핫키 강좌
프날 오토핫키 강좌

프날 오토핫키 질문 커뮤니티

* 질문 공지사항(질문 요령) 필독해주세요.: https://pnal.kr/pages/how-to-question
* 최근 10개의 질문/답변만 보여집니다. 넘어간 질문을 삭제하고 싶으신 경우 질문란에 삭제할 글 내용과 함께 삭제 요청을 남겨주세요.
* 댓/답글 작성시 "비밀글" 설정을 해제해주세요. 어차피 비회원제라 비밀 답글로 답변 드리면 작성자분도 읽을 수 없습니다.
* 메인 질문은 위쪽 양식을 이용해주시고, 답글로는 간단한 인사나 질문만 해주세요.

질문 답변 목록

  • Q. 겉으로 보기에는 같은 문자인데 검색이 안 됩니다. [...] [답글]

    오토핫키로 성경검색 프로그램을 만들고 있는데, 웹상에서 성구를 드래그해서 검색하는 식으로 작동하는 걸 만들었습니다. 근데 아래의 문자가 검색이 안 되는 현상을 발견했습니다. 근데 아래에 두 문자가 겉보기에는 같은데, 이걸 복사해서 검색을 하면 첫번째 성구는 검색이 안 되고, 두번째 거는 검색이 됩니다.
    만든 프로그램에서 검색이 안 되는건 물론이고, 이걸 간단한 메모장에서 컨트롤+에프로 검색을 해도 검색이 안됩니다.
    겉으로 봤을 때는 같은 문자 인 것 같은데, 메모장에서 utf-8이라든지 다른 형식으로 저장해봐도 검색이 안 되는데 이유를 모르겠더라고요.

    성구는 아래와 같고
    (1) 마​10:28

    (2) 마10:28


    * 메모장의 내용은 이렇습니다.
    (3) 마10:28=몸은 죽여도 영혼은 능히 죽이지 못하는 자들을 두려워하지 말고 오직 몸과 영혼을 능히 지옥에 멸하시는 자를 두려워하라
    --

    위 내용을 메모장에 복사 붙여넣기해서 검색을 해보면,
    (2) 번과 (3) 번의 "마10:28"은 같은 문자로 메모장에서도 인식을 하고 검색이 되는데,
    (1) 번은 (2), (3)번과 다른 문자로 인식이 되는 것 같아 검색이 안 되는데 이유를 모르겠습니다.
    오토핫키 스크립트에서 복붙해서 검색해도 마찬가지이고, 엑셀이나 여러 프로그램에서 복붙을 해도 검색이 안 되는데 원인을 전혀 모르겠어서 질문드립니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      오토핫키랑은 관련이 없지만 또 이런 질문은 언제나 환영입니다. 코딩하다 생긴 문제니까요.

      저도 겉보기엔 똑같아보이는데 실제론 다른 문자열로 인식되어서 이것저것 확인해보았습니다.

      1. 진짜 같은 문자열인가?
      강의에서 나온대로 if문을 사용해보겠습니다. (1)번의 마10:28과, (2)번의 마10:28 문자열을 복사해서
      if ("마10:28" = "마10:28")
      과 같이 조건문을 구성해주고 확인해보니 해당 조건이 "거짓"임을 알 수 있습니다. 두 문자열은 궁극적으로 다르다는 것이지요.


      2. 각 문자가 서로 다른가? 어디가 다른가?
      즉, "마" = "마", "1" = "1", "0" = "0", ... 한 글자씩 서로 같은지 확인해보았는데, 이렇게 비교하니 서로 다른 부분 없이 같았습니다. 아니 각 글자가 같은데 왜 전체 문자열은 다르다고 나올까요?


      3. 글자수 확인 (진실 발견)
      저도 이유를 모르던 와중에, 혹시 하는 마음에 StrLen() 함수로 (강좌에 있습니다.) 글자 수를 세보았습니다. 그러자 놀랍게도 1,2,3번에 있는 "마10:28" 문자열이 각각 7, 6, 6 글자로 나오는 것을 알게 되었습니다. 즉, 1번의 "마10:28"은 7글자라는 것이지요.

      이로써 알 수 있는 사실은, 실제로 (1)번의 글자와 (2)(3)번의 문자열은 다르다는 것이었죠. 1번은 7글자니까요.

      그러면 보이지 않는 어떤 한 글자가 (1)번의 문자열에 껴있다는 것인데, 그래서 각 글자마다 Loop, Parse(*강좌에 역시 있습니다.)를 돌리면서 각 글자의 유니코드 값을 가져와보니, 글자 "마"와 "1" 사이에 투명하고 너비가 없는 문자열 하나가 껴있음을 알게되었습니다. 유니코드는 8203번이고, 공식 명칭은 ZERO WIDTH SPACE라고 합니다. 즉, 너비 없는 공백이네요. 이 문자가 "마"와 "1" 사이에 껴있었기 때문에 (1)번 문자열만 다르게 인식된 것입니다.

      이해하셨나요? 실제로 (1)번 문자열은 (2)(3)번과 다르다는 것이고, 뭐가 다르다면 중간에 너비가 0인 공백이 "마"와 "1"이라는 글자 사이에 하나 껴있었다는 것입니다.

      그럼 어떻게 이 공백을 제거하냐... 강좌엔 없는 함수지만 그냥 StrReplace() 함수에 원본 문자열을 넣고, 유니코드 8203번 문자(너비 없는 공백)을 제거하라고 하면 됩니다. 아래와 같게 구성됩니다.

      string := "마​10:28" ;실제 1번 문자열입니다.
      string := StrReplace(string, Chr(8203))

      이 과정을 거친 후 string 변수엔 2, 3번과 동일하고 깨끗한, 투명문자가 없는 6글자의 "마10:28"이 들어있을 것입니다.

      도움이 되셨으려나 모르겠네요. 전체 코드도 올립니다.


      string := "마​10:28" ;1번 문자열
      string := StrReplace(string, Chr(8203))
      if (string = "마10:28") ;수정된 1번 문자열과 2,3번의 깨끗한 "마10:28" 문자열과 비교
      MSgBox, 두 문자열이 같습니다! 공백이 제거되었다는 뜻입니다


      위 코드의 2번 라인을 지웠다 넣었다 해보시면서 결과를 확인해보세요.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      감사합니다. 이 부분 정말 막막했는데 덕분에 해결했습니다^^ 자세히 말씀해 주셔서 너무 감동이었고 너무 유익했습니다. 앞으로도 좋은 강의 부탁드리고 오늘도 좋은 하루 되세요!


  • Q. drm(보안스크린)에서 이미지 픽셀서치 하는법 [...] [답글]

    현재 사내에 보안스크린 프로그램이 깔려

    캡처가 되지않고 (흑백으로나옴) 이미지나 픽셀서치가

    되지않습니다. 우회하는 법이나 다른방법으로 이미지 픽셀 서치 할 수 있는 방법이 있을까요?

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      보안프로그램에서 막는걸 굳이 우회할 필요는 없습니다. 해당 창의 픽셀값에 접근하는걸 프로그램이 막겠다는데, 그걸 우회해서까지 자동화를 하겠다면 그건 회사 보안 프로그램을 만든 사람의 의사에 반해서 자동화를 구현하려는 것이지요. (물론 우리가 그런 목적이 있다는건 아닐지라도, 회사측에선 달가워하지 않으니까 보안 프로그램이 적용되어있겠죠?) 그래서 그냥 그 프로그램에선 오토핫키를 못쓰는구나 생각하시는게 도의에도 맞고 우회등을 생각하지 않아도 되니 스트레스도 덜 받습니다.

      물론 허용되는 경우엔 자동화를 통해 쉽게 작업을 처리할 수 있지만, 아쉽게도 해당 회사 프로그램에는 사용하지 못하네요.

      다만, 흑백으로 처리된다는 점에서 흑백으로 처리된 이미지가 나온다면 그 이미지에서 이미지를 따와서 서치를 진행할 수는 있겠습니다. 보통 보안 프로그램은 캡처시 전체 화면이 보통 까맣게 나오는데, 굳이 흑백으로 출력한다는 뜻은, 의외로 이런 작업에 대한 융통성있게 처리하기 위해서 흑백으로 출력시킬수도 있습니다. (즉, 원본 캡처는 막아야겠으나 픽셀 작업은 허용하는 목적으로, 그러니까 딱 원본 캡처만 막겠다는 수준으로 보안 수준이 설계되었을수도 있습니다.). 그렇다면 그냥 흑백으로 나온 캡처본에서 이미지를 또 캡처해서 이미지서치를 진행해도 무방하겠지요


  • Q. 안녕하세요 프날님 강좌 항상 잘보고 있습니다. [...] [답글]

    https://pnal.kr/14

    강의에서 이스케이프 시퀀스 ` 를 쓰는데요

    `& 를쓰면 & 입력이 되지 않네요

    & 문자는 어떻게 입력해야하나요?

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      간단하게 &&두번쓰면 입력이 되네요!

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      `&는 이스케이프 시퀀스가 아닙니다. & 기호가 특수하게 사용되지 않기 때문에 ^^; 그냥 &로 써주시면 됩니다.

      다만 GUI의 특정 컨트롤(예:Text. 더 있는지는 모르겠네요)로 사용하거나 하는 경우엔 & 기호가 단축키 기호로 사용되기 때문에 이 경우엔 &&로 써줄 수 있겠네요

      https://www.autohotkey.com/board/topic/61575-cant-display-ampersand-in-a-text-control/

      위와 같은 경우이죠. 만약 이런 경우엔 &&로 써주시면 되는데(그리고 질문자님이 해결하신 케이스도 아마 이러한 케이스일 것 같은데), 이걸 "이스케이프 시퀀스"라고 부를 수 있는진 모르겠으나, 말 그대로 이스케이핑 한 행동은 맞는 것 같습니다 ^^; 잘 해결되셨다니 다행입니다. 저도 이 상황에 대해 강의를 쓰면서 다루지 않았었는데, 미처 생각하지 못했던 부분을 슬기롭게 해결하셨네요


  • Q. v라벨 질문드립니다. [...] [답글]

    Gui, Add, CheckBox, v변수1 g체크 , 네모
    Gui, Add, CheckBox, v변수2 g체크 , 세모
    Gui, Add, CheckBox, v변수3 g체크 , 정사각형
    Gui, Add, CheckBox, v변수4 g체크 , 동그라미
    Gui, Add, CheckBox, v변수5 g체크 , 마름모
    Gui, Add, CheckBox, v변수6 g체크 , 타원

    사각형 := ["네모", "정사각형", "마름모"]


    체크박스의 v라벨들을 a_index로 활용하기 위해 위와 같이 변수1, 변수2 ... 로 주었는데
    일괄처리가 아닌 몇 개만 뽑아서 처리해야 되는 경우가 생겨서 배열로 사각형만 따로 뺐습니다.

    체크박스의 경우
    GuiControl,, 변수1, 1 로 하는 것과
    GuiControl,, 네모, 1 로 하는 것이 동일하게 체크가 되어서

    Loop, % 사각형.Length()
    {
    GuiControl,, % 사각형[A_Index], 1
    }
    return

    를 이용해서 체크를 하는 것 까지는 됐는데 조건부로 체크를 해제하려니 막혀서 질문드립니다.

    각 항목마다 체크가 되어있다면 체크해제, 체크가 안되어있다면 체크를 하고 싶은데 Loop를 이용해서
    한번에 하려면 어떻게 해야 되는지 알고 싶습니다.

    변수는 가능하면 위와 같은 형태로 진행하고 싶습니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      말 그대로 사각형[A_Index]를 if문 안에서 값을 검사하여 지금 체크되어있으면 체크 해제, 체크해제 되어있으면 체크하면 되는데요...

      추천드리는 방법은 그냥 사각형 배열의 요소를 "네모" "정사각형" "마름모"가 아니라, 1 3 5 등 해당 사각형의 숫자로 두고 그냥 v레이블 값으로 가져오는게 나을것같고요

      말씀하신대로 지금처럼 사각형 배열의 값을 Text로 하시겠다면

      Loop, % 사각형.Length()
      {
      GuiControlGet, var,, % 사각형[A_Index]
      if (var = 1)
      GuiControl,, % 사각형[A_Index], 0
      else
      GuiControl,, % 사각형[A_Index], 1
      }

      이런 방법이 있겠습니다. (GuiControlGet은 해당 컨트롤의 값을 가져오는 명령어입니다.)


  • Q. 안녕하세요 프날님 강좌 항상 잘보고 있습니다. [...] [답글]

    다름이 아니라 문자열을 byte로 변경하는 방법이 오토핫키에 있는지 궁금합니다.

    키보드나 마우스 조작이 아닌 메모리수정으로 프로그램자동화를 만들어보고 있는데요

    메모리를 읽어오면 4byte로 읽어 오는것 같습니다ㅠ 이를 byte로 변경 하는 방법과

    byte를 문자열로 변경하는 방법과 (msgbox 에서 잘되는지 확인하기 위함)

    또 문자열을 byte 변경하는 방법을 아시는지 여쭤봅니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      이야기에 앞서 메모리 수정 방식으로 꼭 옳은 방향의 자동화만 이용하시길 바랍니다 ^^; 보통 메모리까지 관심을 가지는 경우가 없거든요. 제 강의를 따라오셨으니 문제 없는 곳에 사용하시는 것이라고 믿고 있습니다

      바이트로 바꾼다는게 무슨 뜻이지요?
      타 언어처럼 문자열 -> 바이트 배열, 단일 문자 -> 바이트 변환을 말씀하시는 것이라면, 이는 문자열 인코딩에 따라 값이 차이나게 될 것입니다.

      예를 들어서 UTF-8은 한글이 3바이트로 인코딩됩니다.(가 -> 0xea 0xb0 0x80)

      무튼 UTF-8 기준으로 제가 만들어둔 String to Hex 함수가 있었는데요, 아쉽게도 파일이 날라가서... ㅠㅠ 인터넷에 찾아보니까 저보다 훨씬 대단하신 분들이 더 짧게 만들어둔 코드가 있네요.

      https://www.autohotkey.com/boards/viewtopic.php?t=68782

      위 링크에 Str2Hex함수는 문자열을 입력받고 Hex값을 뱉는 함수입니다. 이를 참고하시면 될 것 같습니다. 그 밑의 Hex2Str은 그 반대의 역할이고요 ^^

      메모리를 읽어왔는데 4Byte로 읽어온다는 것은 모르겠네요. 1Byte만 읽어올수도 있지 않나요? ReadProcessMemory를 사용하실 것 같은데 nSize 매개변수를 바꾸면 읽어오는 사이즈를 바꿀 수 있습니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      메모리를 사용하는 이유는
      OCR이나 그런걸로 글자를 구분지을때
      오류가 많이 난다고 해서요 byte 값으로 그 문자가 있는지 찾은후에 수정하려고 했거든요 ㅠㅠ


  • Q. 엔터할 때 edit를 추가하는 건에 대해서 [...] [답글]

    안녕하세요?
    엔터키를 누르면 edit가 하나씩 아래에 생성되는 걸 만들고 싶은데
    스크롤이 생기고 난 이후부터는 스크롤을 내린 만큼의 좌표값에서 엔터를 눌렀을 때 edit 창이 그만큼 아래에서 생성이 됩니다...
    3시간째 붙잡고 있기는 한데 각각 요소에서 gui, add할 때 내장되어 있는 y값이 변경되어서 edit가 일정한 높이 아래에서 생성이 되지 않는 것 같은데 조언 좀 주실 수 있는지요.. ㅠㅠ
    아래는 코드입니다.

    #NoEnv
    ; www.autohotkey.com/board/topic/26033-scrollable-gui-proof-of-concept/

    OnMessage(0x115, "OnScroll") ; WM_VSCROLL
    OnMessage(0x114, "OnScroll") ; WM_HSCROLL

    Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL

    Gui, Add, Edit, W100,
    Gui, Show, W200 H200

    Gui, +LastFound
    GroupAdd, MyGui, % "ahk_id " . WinExist()

    return
    enter::
    Gui, Add, Edit, W100,
    GuiSize:
    UpdateScrollBars(A_Gui, A_GuiWidth, A_GuiHeight)
    return

    GuiClose:
    ExitApp

    #IfWinActive ahk_group MyGui
    WheelUp::
    WheelDown::
    +WheelUp::
    +WheelDown::
    ; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
    OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, WinExist())
    return
    #IfWinActive

    UpdateScrollBars(GuiNum, GuiWidth, GuiHeight)
    {
    static SIF_RANGE=0x1, SIF_PAGE=0x2, SIF_DISABLENOSCROLL=0x8, SB_HORZ=0, SB_VERT=1

    ; Gui, %GuiNum%:Default
    Gui, +LastFound

    ; Calculate scrolling area.
    Left := Top := 9999
    Right := Bottom := 0
    WinGet, ControlList, ControlList
    Loop, Parse, ControlList, `n
    {
    GuiControlGet, c, Pos, %A_LoopField%
    if (cX < Left)
    Left := cX
    if (cY < Top)
    Top := cY
    if (cX + cW > Right)
    Right := cX + cW
    if (cY + cH > Bottom)
    Bottom := cY + cH
    }
    Left -= 8
    Top -= 8
    Right += 8
    Bottom += 8
    ScrollWidth := Right-Left
    ScrollHeight := Bottom-Top

    ; Initialize SCROLLINFO.
    VarSetCapacity(si, 28, 0)
    NumPut(28, si) ; cbSize
    NumPut(SIF_RANGE | SIF_PAGE, si, 4) ; fMask

    ; Update horizontal scroll bar.
    NumPut(ScrollWidth, si, 12) ; nMax
    NumPut(GuiWidth, si, 16) ; nPage
    DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_HORZ, "uint", &si, "int", 1)

    ; Update vertical scroll bar.
    ; NumPut(SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, si, 4) ; fMask
    NumPut(ScrollHeight, si, 12) ; nMax
    NumPut(GuiHeight, si, 16) ; nPage
    DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_VERT, "uint", &si, "int", 1)

    if (Left < 0 && Right < GuiWidth)
    x := Abs(Left) > GuiWidth-Right ? GuiWidth-Right : Abs(Left)
    if (Top < 0 && Bottom < GuiHeight)
    y := Abs(Top) > GuiHeight-Bottom ? GuiHeight-Bottom : Abs(Top)
    if (x || y)
    DllCall("ScrollWindow", "uint", WinExist(), "int", x, "int", y, "uint", 0, "uint", 0)
    }

    OnScroll(wParam, lParam, msg, hwnd)
    {
    static SIF_ALL=0x17, SCROLL_STEP=10

    bar := msg=0x115 ; SB_HORZ=0, SB_VERT=1

    VarSetCapacity(si, 28, 0)
    NumPut(28, si) ; cbSize
    NumPut(SIF_ALL, si, 4) ; fMask
    if !DllCall("GetScrollInfo", "uint", hwnd, "int", bar, "uint", &si)
    return

    VarSetCapacity(rect, 16)
    DllCall("GetClientRect", "uint", hwnd, "uint", &rect)

    new_pos := NumGet(si, 20) ; nPos

    action := wParam & 0xFFFF
    if action = 0 ; SB_LINEUP
    new_pos -= SCROLL_STEP
    else if action = 1 ; SB_LINEDOWN
    new_pos += SCROLL_STEP
    else if action = 2 ; SB_PAGEUP
    new_pos -= NumGet(rect, 12, "int") - SCROLL_STEP
    else if action = 3 ; SB_PAGEDOWN
    new_pos += NumGet(rect, 12, "int") - SCROLL_STEP
    else if (action = 5 || action = 4) ; SB_THUMBTRACK || SB_THUMBPOSITION
    new_pos := wParam>>16
    else if action = 6 ; SB_TOP
    new_pos := NumGet(si, 8, "int") ; nMin
    else if action = 7 ; SB_BOTTOM
    new_pos := NumGet(si, 12, "int") ; nMax
    else
    return

    min := NumGet(si, 8, "int") ; nMin
    max := NumGet(si, 12, "int") - NumGet(si, 16) ; nMax-nPage
    new_pos := new_pos > max ? max : new_pos
    new_pos := new_pos < min ? min : new_pos

    old_pos := NumGet(si, 20, "int") ; nPos

    x := y := 0
    if bar = 0 ; SB_HORZ
    x := old_pos-new_pos
    else
    y := old_pos-new_pos
    ; Scroll contents of window and invalidate uncovered area.
    DllCall("ScrollWindow", "uint", hwnd, "int", x, "int", y, "uint", 0, "uint", 0)

    ; Update scroll bar.
    NumPut(new_pos, si, 20, "int") ; nPos
    DllCall("SetScrollInfo", "uint", hwnd, "int", bar, "uint", &si, "int", 1)
    }

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      너무 어렵네요 ^^;

      저는 GUI와 관련해 말씀하신것처럼 동적인 작업을 할 필요가 있다면 그냥 타언어를 쓰는 경우가 많거든요. 더 체계적이고 더 보기에 좋은 코드가 짜여지다보니... 오토핫키로는 저런 심화적인 GUI 작업을 하기가 까다롭습니다.

      아무튼... 수정까지 해드리기엔 제 능력이 뛰어난 것은 아니라 좀 오래 걸릴 것 같고요, 아이디어만 제공드리면...

      GetScrollInfo 함수(DllCall로 쓰며 winuser.h에 있습니다.)를 이용하여 현재 스크롤의 위치를 가져온 후, 그 위치만큼 뺀 위치에 Edit를 생성되게 하는 법을 생각해볼 수 있습니다.

      지금 있는 OnScroll 함수 안에서 new_pos 변수를 global로 만들고 Msgbox로 출력해보시면 현재 스크롤 위치가 나오는데, 이를 이용해보세요.

      어렵네요 ^^;


  • Q. 안녕하세요 질문있습니다 [...] [답글]

    항상 믿음직한 프날님 pixelgetcolor 를 이용해서 RGB값을 추출할 수 있잖아요. 근데 이 값이 0xAAAAAA 이런식으로 추출이 되더라고요. 제가 원하는건 R(255) G(255) B(255) 이런식의 숫자값으로 얻고싶은데 이건 아무래도 오토핫키로는 무리일까요?

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      색상값은 16진수로 6자리로 나오며, 두 자리씩 각가 RGB값이기 때문에
      SubStr()(본편 강좌참고)을 이용해서 두 자리씩 끊으시면 됩니다.

      0xAABBCC에서
      AA/BB/CC로 가져온다음
      앞에 각각 0x만 붙여주면 됩니다
      0xAA/0xBB/0xCC

      이는 16진수로서, 10진수와 표현하는 법만 다른거고 동일하게 연산됩니다.
      10진수로 보이게 하고싶으면 0을 더해서 쓰면됩니다. 0xAA + 0은 170이라고 출력됩니다.


  • Q. 안녕하십니까 프날님 항상강좌 잘보고있습니다!! [...] [답글]

    다름이 아니라 isObject에 대해 자세히 알고 싶어서 질문드립니다!!

    검색해봤는데 제대로된 자료를 제가 못찾는건지 찾을수가 없더라구요

    IsObject를 사용하면 값이 객체인지 판별할 수 있습니다:

    Result := IsObject(expression)

    이정도인데 IsObject가 역할 뭔지 궁금합니다

    프날님이 알려주시면 제 마음속에 저장해놓겠습니다

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      객체에 대해 이해가 필요한 부분입니다.

      https://pnal.kr/pages/array4

      위 링크의 설명과 같이, 객체는 여러 요소가 하나로 모아져있는 개념적인 집합을 의미합니다. 객체 안엔 함수나 변수가 있을 수 있어요.
      우리가 "자동차"라는 객체를 생각하면, 이 자동차가 가지는 여러 속성들... 색, 크기, 형태, 클락션(), 가속(), 감속(), 기어변경() 등이 있죠. (괄호가 붙은 것은 '동작, 함수'이고, 안붙은거는 '변수'입니다.)
      이들을 하나로 묶어주지 않으면 자동차가 여러대일때 각 변수와 함수를 엄청 많이 써줘야하고 각 변수가 어떤 자동차의 변수인지 구분하기도 어렵습니다. 그래서 '자동차'라는 객체로 묶어서 자동차에 포함되는 개념으로 색, 크기, 형태, 클락션(), 가속(), 감속()을 넣어두면, 나중에 자동차를 새로 만들어도 그 객체의 속성을 그대로 가져와서 필요한 속성만 변경하여 쓸 수 있는거죠

      객체를 구현하는 틀은 클래스가 담당하거나, 혹은 기타 다른 무언가가 될 수 있습니다. 오토핫키에선 주로 클래스나 배열이 객체를 만듭니다.

      객체의 이름이 A라면, isObject(A)의 반환값은 1이 되겠지요. 그런데 A가 객체가 아니라면 0을 반환할 것입니다.

      위 링크에서 단순 배열은 객체라고 했습니다. 따라서,

      a := 1
      MsgBox, % isObject(a)

      이건 0을 출력하지만

      a := [1]
      MsgBox, % isObject(a)

      이건 1을 출력합니다. 왜냐하면 a는 단순배열, 즉 객체이기 때문이죠.

      말 그대로 객체인지 아닌지를 반환하는 함수인데, 객체의 개념이 불명확하게 느껴지시거나 평소에 관련 개념을 사용하고 계시지 않았다면 말씀해주신 함수는 무시하셔도 됩니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      답변감사합니다. 그럼 저같이 심화적으로 오토핫키를 쓰지 않는 사람은 그냥

      if (변수 = 1) 을 쓰거나

      다른방법으로 쓰는게 더 낫겟군요!


  • Q. 크롬 id. Pid 질문 ( title 중복 경우) [...] [답글]

    안녕하세요,, 오토핫키 공부하는 학생입니다. 크롬 창 관련해서 도저히 문제가 안풀려서 질문드립니다.





    제가 만약에 크롬 창을 띄워서 네이버 지도를 띄워 놓고

    Winget, w_id1, ID, A



    WinGet, w_id2, pid, A



    를 했습니다.





    네이버 지도 옆에 추가 탭창을 만들어 또 네이버 지도를 띄워 놓고

    Winget, w_id3, ID, A



    WinGet, w_id4, pid, A



    를 입력하면



    w_id1 = w_id3

    w_id2 = w_id4 가 되어 버려 서로를 구분할 수 업게 됩니다;;;



    즉 저는 크롬을 열고 텝을 추가하여 네이버 지도 2개를 열어 놓으면

    그 2개를 구별할 수 없게 되는거 같습니다.



    title을 받아서 탭들을 이동하면서 일치하는 것을 찾아보려 했으나 위 같은 경우 이름까지 같아서 구분이 안되더군요;;



    목적은 네이버지도 1에는 일산을 네이버 지도 2에는 부산을 띄워 놓고

    핫키를 누르면 탭을 넘어가게 하고 싶습니다.





    위 같은 경우 둘을 구분 할 수 있는 고유의 숫자 같은 방법이 있을까요 ???

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      외부에서 열린 크롬이라면 구분 못합니다. 프로그램 내에서 Selenium등의 API를 통해서 크롬을 열어 조작하면 되긴 합니다만, 개발 난이도가 지금보다 확 높이지니 이 부분은 넘어가도록 하고요...

      두 타이틀을 다르게 설정하는 과정이 있으면 어떻까 싶네요. WinSetTitle로, 두 타이틀을 변경시켜서 조작해보세요(이때 크롬 탭에 적혀있는 글씨는 바뀌지 않습니다만, 실제 타이틀은 바뀝니다.)

      지도1의 title을 map1으로,
      지도2의 title을 map2로 바꿔서, 타이틀로 구분지을 수 있습니다. 즉, 이동할 두 탭을 미리 수동으로 "설정"하는 과정을 넣으라는 것이지요. 한 번 설정하면 페이지를 이동하기 전까진 재설정할 필요는 없으니까요.

      여담으로, 크롬 탭 이동은 Ctrl+숫자로 가능하니, 탭을 넘길 땐 이 방법을 쓰시는게 좋을 것 같네요.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      물론 크롬이 아니라면 DOM제어라는 방법을 통해 인터넷 익스플로러 내부의 요소를 이용하여 두 탭을 구분지을 수 있을 것입니다.

      DOM을 쓰지 않아도 IE는 주소창 컨트롤이 따로 있으므로 해당 주소창의 ClassNN으로 주소가 다른지 확인하면 되니 편할거고요...

      다만 크롬은 전체 화면을 하나로 렌더링하기 때문에 상술한 Selenium등을 쓰지 않는이상 어렵긴 합니다 ^^;


  • Q. 스크립트 가독성 질문드립니다. [...] [답글]

    num1 := A_Index*4-3
    num2 := A_Index*4-2
    num3 := A_Index*4-1
    num4 := A_Index*4
    x1 := pos%num1%
    y1 := pos%num2%
    x2 := pos%num3%
    y2 := pos%num4%

    를 num1,2,3,4없이 표현할 수 있는지 궁금합니다.

    • A. 답변 드립니다.Q. 추가 질문입니다. [...]

      안녕하세요.

      가짜 배열 형태는 지양해야합니다. (https://pnal.kr/pages/array2 참고)

      Loop가 어떻게 쓰여졌는지 없는데 A_index만 쓰여있어서 전체 Loop가 어떻게 구성되어있는지... 보통 저런식이면 Loop를 안쪽에서 한번 더 쓸 일이 있을수도 있는데,
      일단 보이는 스크립트에 A_index가 있으니까 임의로 2회 Loop로 예시를 구성하겠습니다.

      pos1 := "a"
      pos2 := "b"
      pos3 := "c"
      pos4 := "d"
      pos5 := "e"
      pos6 := "f"
      pos7 := "g"
      pos8 := "h"

      Loop, 2
      {
      num1 := A_Index*4-3
      num2 := A_Index*4-2
      num3 := A_Index*4-1
      num4 := A_Index*4
      x1 := pos%num1%
      y1 := pos%num2%
      x2 := pos%num3%
      y2 := pos%num4%
      MsgBox, % A_index "회 반복: " x1 ", " y1 ", " x2 ", " y2
      }

      이제 이걸 가독성 좋게 수정해보자고요.

      지금은 pos1, pos2, pos3, ... 변수가 적어주신 스크립트 바깥에 있는 것 같습니다. 이걸 가짜배열이라고 하고요... 배열도 아닌데 배열처럼 순번이 매겨져있는 변수라서 별 효용가치도 없고 스크립트만 복잡해집니다.

      pos배열을 하나 만들고요, pos[1], pos[2], ... 등 배열의 요소로서 현재 pos1, pos2,... 변수의 값을 가지게 한다음에

      x1 := pos[A_index * 4 - 3]
      y1 := pos[A_index * 4 - 2]
      x2 := pos[A_index * 4 - 1]
      y2 := pos[A_index * 4]

      이런 식으로 적어주면 되긴 합니다.

      전체 테스트 스크립트는 아래와 같습니다.

      pos := ["a", "b", "c", "d", "e", "f", "g", "h"]

      Loop, 2
      {
      x1 := pos[A_index * 4 - 3]
      y1 := pos[A_index * 4 - 2]
      x2 := pos[A_index * 4 - 1]
      y2 := pos[A_index * 4]
      MsgBox, % A_index "회 반복: " x1 ", " y1 ", " x2 ", " y2
      }


      그런데, 일단 보내주신 스크립트가 어떤 역할을 하는지 나와있지는 않아서, 앞뒤 맥락을 보고 더 깔끔한 방법이 있을 것 같습니다. 그 맥락을 보시고 본인이 배열을 이용하여 수정해보세요.


      아, pos라는 변수명으로 보아 아마 좌표가 담겨있는 변수 같은데, 지금 스크립트만으론 아마 pos1엔 x1좌표, pos2엔 y1좌표, pos3엔 x2좌표, pos4엔 y2좌표, pos5엔 다시 x1좌표... 이런 식으로 들어가있는게 아닌가 싶은데,

      다차원 배열로 쪼개면 더 낫지 않을까 싶습니다. 하다못해 pos1 과 pos5처럼 같은 x1끼리, 같은 x2끼리... 값이 다른데 반복만으로 구분하니까 가독성이 떨어지므로 4개 묶음으로 행을 쪼개도 될 것 같습니다.

      pos := [["a", "b", "c", "d"], ["e", "f", "g", "h"]]

      Loop, 2
      {
      x1 := pos[A_index][1]
      y1 := pos[A_index][2]
      x2 := pos[A_index][3]
      y2 := pos[A_index][4]
      MsgBox, % A_index "회 반복: " x1 ", " y1 ", " x2 ", " y2
      }


      이러면 더 깔끔하죠?
      이렇게 pos를 현재 가짜배열 형태가 아닌, 위 스크립트처럼 배열 형태로 만들어보는것이 좋을 것 같습니다. 저렇게 되면, pos[A_index][2]만 보고도 "아, A_index번째 세트의 두번째 요소구나"라고 알기 쉽지요. 지금처럼 A_index * 4 - 1 이런식보다 알기 쉽습니다. (3차원 배열을 쓰면 (x1, y1)과 (x2, y2)로 쪼갤 수 있긴 한데, 배열의 차원이 많아질수록 가독성이 떨어지기 때문에 꼭 필요한 경우가 아니면 2차원으로 써주는게 낫습니다.)

      배열은 아래 링크에서 배우실 수 있습니다.
      https://pnal.kr/pages/array1