안녕하세요?
어제 모처럼 시간이 나서 헬스장에 가려고 했으나
낙뢰 때문에 부득이 헬스장에 못 가고 이 소스를 짰습니다.
전 세계에서 해마다 놀이기구를 타다가 사망하는 사람보다
낙뢰에 의해 사망하는 사람이 더 많다고 들었습니다 ㅎㄷㄷ
(운동 안 하기에 아주 좋은 핑계네요 ㅠㅠ)
이 스크립트는 새 글 작성시 CMS에서 새 글 표시가 달리는 것을 이용해서
해당 게시글에 자동으로 댓글을 다는 목적으로 제작되었습니다.
커뮤니티를 제작하면 초기에는 무플 방지가 필요하다고 생각되어서요 ㅠㅠ
(커뮤니티를 제작하기도 전에 벌써부터 무플 걱정을 하다니 ㅜㅜ)
물론 PHP로도 구현할 수 있겠지만
CMS와 무관하게 돌아가는 소스를 짜고 싶었습니다.
(실은 제가 어떤 CMS로 커뮤니티를 만들지 아직 정하지 못했거든요 ㅠㅠ)
이 스크립트는 Autohotkey_L을 기준으로 제작되었고
브라우저나 CMS를 가리지 않고 사용할 수 있습니다.
다만 마우스 좌표 기반이다보니 부정확한 경우가 있어서
중복으로 댓글이 달리는 것을 방지하기 위해
마우스 클릭 후 URL이 바뀌는지 여부를 수시로 체크합니다.
만약 커뮤니티에 새 글 아이콘을 24시간 달리도록 설정하셨다면
윈도우 스케쥴러에서 24시간마다 작동하게 하면 자동으로 돌아갑니다.
다음 몇 가지를 셋팅하셔야 됩니다.
1. new.bmp 파일
새 글 작성시 달리는 새 글 표시 아이콘을 new.bmp로 저장합니다.
캡쳐하셔도 돌아갑니다.
다만 오토핫키의 특성상 bmp나 png 파일은 잘 분석하지만
gif나 jpg 파일은 제대로 작동하지 않을 가능성이 큽니다.
(사실 대부분의 아이콘은 gif나 jpg 파일이죠 ㅠㅠ)
그리고 브라우저를 100% 비율로 놓고 사용하지 않으면 캡쳐햐셔야 됩니다 ㅠㅠ
2. reply.bmp
리플 버튼을 캡쳐해서 reply.bmp로 저장합니다.
상당수의 커뮤니티에서 리플 버튼이 이미지 파일로 존재하지는 않을테니
이건 캡쳐하셔야 될 것 같습니다.
3. longtime 변수값
longtime 변수는 커뮤니티 클릭 후 로딩에 걸리는 시간에 따라 적정한 값을 입력하시면 됩니다.
단위는 ms입니다.
국내의 무난한 웹호스팅이라면 3000, 벌쳐나 리노드라면 5000,
그리고 테스트 해보지 않았지만 미국이나 호주 서버는 넉넉히 7000 정도 잡으시면 될 것 같습니다.
4. mention 변수값
리플로 남기고 싶은 문구를 mention1~15 변수에 입력하시면
루프가 돌아가면서 순서대로 해당 문구를 리플로 남깁니다.
물론 15개 이상 지정하셔도 무방합니다.
5. PgUP & PgDN
이건 화면 해상도에 따라서 달라질 수 있는 부분이네요.
new 아이콘과 댓글쓰기 버튼이 화면에 출력될 수 있도록
페이지 업과 다운 횟수를 적절히 조절하시면 됩니다.
6. 크롬 이외의 브라우저
이 소스는 모든 브라우저에서 작동하도록 제작되었으며
chrome.exe 부분을 변경하면 다른 브라우저에서도 작동하는 것을 확인했습니다.
첨언하자면 getactiveURL 함수는 오토핫키 공식포럼에 오픈된 소스를 사용하였습니다.
출처는 다음과 같습니다. (atnbueno 님 작성)
https://autohotkey.com/boards/viewtopic.php?t=3702
사실 크롬에서만 작동하게 하려면 send ^l와 send ^C를 이용해서
불과 몇 줄로 간단하게 작성할 수도 있지만
범용으로 제작하다보니 상당히 긴 길이의 함수를 사용하게 되었네요 ㅠㅠ
제가 크롬, IE, 파폭 등 브라우저에서 돌아가는 것을 확인하였지만
급히 만들다보니 소스에 여러 군더더기가 있습니다.
특히 while 문의 첫번째 루프 돌리는 부분을 더 깔끔하게 만들었어야 했는데 말이죠.
군더더기나 부족한 부분이 있으면 스포어의 회원님들께서 지적해주시면 감사하겠습니다.
마지막으로 이 소스를 조금 수정하면 게시판 도배 등에 악용될 수도 있을테니
부디 좋은 목적으로만 사용해주셨으면 합니다 ㅠㅠ
그럼 편안한 저녁 되시고 여러모로 부족한 제게 많은 가르침을 주시는 스포어 회원 분들께 항상 감사드립니다.
longtime = 6000 times = 0 mention1 = mention2 = mention3 = mention4 = mention5 = mention6 = mention7 = mention8 = mention9 = mention10 = mention11 = mention12 = mention13 = mention14 = mention15 = ModernBrowsers := "ApplicationFrameWindow,Chrome_WidgetWin_0,Chrome_WidgetWin_1,Maxthon3Cls_MainFrm,MozillaWindowClass,Slimjet_WidgetWin_1" LegacyBrowsers := "IEFrame,OperaWindowClass" longtime = 6000 Run, Chrome.exe "www.google.com" sleep, 3000 ret:=IME_CHECK("Google") If %ret% <> 0 { Send,{vk15sc138} } Run, Chrome.exe "URL" sleep %longtime% SendInput, {Home} sleep 2000 SendInput, {PgDn} sleep 2000 sURL := GetActiveBrowserURL() sleep 1500 sURL1 := sURL Imagesearch, vx, vy, 500, 0, 1700, 1200, *80 new.bmp While (Errorlevel=0) ; The Loop { SendInput, {Home} sleep 2000 SendInput, {PgDn} sleep 2000 times := times + 1 If (times > 1) { vylimit := vy + 20 } If (times = 1) { vylimit := vy - 20 } Imagesearch, vx, vy, 500, %vylimit%, 1700, 1200, *80 new.bmp sleep 200 If (Errorlevel = 0) { sleep 200 vx1 := vx - 60 vy1 := vy + 10 sleep 200 Mouseclick, Left, %vx1%, %vy1% sleep, %longtime% SendInput, {END} sleep, 2000 SendInput, {PgUp} sleep, 2000 SendInput, {PgUp} sleep, 2000 sURL := GetActiveBrowserURL() sleep 1500 If (sURL1 = sURL) { Break } Imagesearch wx, wy, 800, 0, 1920, 1200, *90 reply.bmp sleep 200 If (Errorlevel = 0) { wx1 := wx + 20 wx2 := wx - 100 wy1 := wy + 20 Mouseclick, Left, %wx2%, %wy1% SendInput, % mention%times% sleep 200 Mouseclick, Left, %wx1%, %wy1% sleep, %longtime% } } If (Errorlevel > 0) { break } sURL1 := sURL sleep 200 Run, chrome.exe "URL" sleep, %longtime% } Return ; funtion GetActiveBrowserURL() { global ModernBrowsers, LegacyBrowsers WinGetClass, sClass, A If sClass In % ModernBrowsers Return GetBrowserURL_ACC(sClass) Else If sClass In % LegacyBrowsers Return GetBrowserURL_DDE(sClass) ; empty string if DDE not supported (or not a browser) Else Return "" } ; "GetBrowserURL_DDE" adapted from DDE code by Sean, (AHK_L version by maraskan_user) ; Found at http://autohotkey.com/board/topic/17633-/?p=434518 GetBrowserURL_DDE(sClass) { WinGet, sServer, ProcessName, % "ahk_class " sClass StringTrimRight, sServer, sServer, 4 iCodePage := A_IsUnicode ? 0x04B0 : 0x03EC ; 0x04B0 = CP_WINUNICODE, 0x03EC = CP_WINANSI DllCall("DdeInitialize", "UPtrP", idInst, "Uint", 0, "Uint", 0, "Uint", 0) hServer := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", sServer, "int", iCodePage) hTopic := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "WWW_GetWindowInfo", "int", iCodePage) hItem := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "0xFFFFFFFF", "int", iCodePage) hConv := DllCall("DdeConnect", "UPtr", idInst, "UPtr", hServer, "UPtr", hTopic, "Uint", 0) hData := DllCall("DdeClientTransaction", "Uint", 0, "Uint", 0, "UPtr", hConv, "UPtr", hItem, "UInt", 1, "Uint", 0x20B0, "Uint", 10000, "UPtrP", nResult) ; 0x20B0 = XTYP_REQUEST, 10000 = 10s timeout sData := DllCall("DdeAccessData", "Uint", hData, "Uint", 0, "Str") DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hServer) DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hTopic) DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hItem) DllCall("DdeUnaccessData", "UPtr", hData) DllCall("DdeFreeDataHandle", "UPtr", hData) DllCall("DdeDisconnect", "UPtr", hConv) DllCall("DdeUninitialize", "UPtr", idInst) csvWindowInfo := StrGet(&sData, "CP0") StringSplit, sWindowInfo, csvWindowInfo, `" ;"; comment to avoid a syntax highlighting issue in autohotkey.com/boards Return sWindowInfo2 } GetBrowserURL_ACC(sClass) { global nWindow, accAddressBar If (nWindow != WinExist("ahk_class " sClass)) ; reuses accAddressBar if it's the same window { nWindow := WinExist("ahk_class " sClass) accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindow)) } Try sURL := accAddressBar.accValue(0) If (sURL == "") { WinGet, nWindows, List, % "ahk_class " sClass ; In case of a nested browser window as in the old CoolNovo (TO DO: check if still needed) If (nWindows > 1) { accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindows2)) Try sURL := accAddressBar.accValue(0) } } If ((sURL != "") and (SubStr(sURL, 1, 4) != "http")) ; Modern browsers omit "http://" sURL := "http://" sURL If (sURL == "") nWindow := -1 ; Don't remember the window if there is no URL Return sURL } ; "GetAddressBar" based in code by uname ; Found at http://autohotkey.com/board/topic/103178-/?p=637687 GetAddressBar(accObj) { Try If ((accObj.accRole(0) == 42) and IsURL(accObj.accValue(0))) Return accObj Try If ((accObj.accRole(0) == 42) and IsURL("http://" accObj.accValue(0))) ; Modern browsers omit "http://" Return accObj For nChild, accChild in Acc_Children(accObj) If IsObject(accAddressBar := GetAddressBar(accChild)) Return accAddressBar } IsURL(sURL) { Return RegExMatch(sURL, "^(?<Protocol>https?|ftp)://(?<Domain>(?:[\w-]+\.)+\w\w+)(?::(?<Port>\d+))?/?(?<Path>(?:[^:/?# ]*/?)+)(?:\?(?<Query>[^#]+)?)?(?:\#(?<Hash>.+)?)?$") } ; The code below is part of the Acc.ahk Standard Library by Sean (updated by jethrow) ; Found at http://autohotkey.com/board/topic/77303-/?p=491516 Acc_Init() { static h If Not h h:=DllCall("LoadLibrary","Str","oleacc","Ptr") } Acc_ObjectFromWindow(hWnd, idObject = 0) { Acc_Init() If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0 Return ComObjEnwrap(9,pacc,1) } Acc_Query(Acc) { Try Return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1) } Acc_Children(Acc) { If ComObjType(Acc,"Name") != "IAccessible" ErrorLevel := "Invalid IAccessible Object" Else { Acc_Init(), cChildren:=Acc.accChildCount, Children:=[] If DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 { Loop %cChildren% i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child): Return Children.MaxIndex()?Children: } Else ErrorLevel := "AccessibleChildren DllCall Failed" } } IME_CHECK(WinTitle) { WinGet,hWnd,ID,%WinTitle% Return Send_ImeControl(ImmGetDefaultIMEWnd(hWnd),0x005,"") } Send_ImeControl(DefaultIMEWnd, wParam, lParam) { DetectSave := A_DetectHiddenWindows DetectHiddenWindows,ON SendMessage 0x283, wParam,lParam,,ahk_id %DefaultIMEWnd% if (DetectSave <> A_DetectHiddenWindows) DetectHiddenWindows,%DetectSave% return ErrorLevel } ImmGetDefaultIMEWnd(hWnd) { return DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hWnd, Uint) }