reklama
Aktuality  |  Články  |  Recenze
Doporučení  |  Diskuze
Grafické karty a hry  |  Procesory
Storage a RAM
Monitory  |  Ostatní
Akumulátory, EV
Robotika, AI
Průzkum vesmíru
Digimanie  |  TV Freak  |  Svět mobilně

Kde (popr. jak) naprogramovat autoklik.

durib (1141)|9.10.2009 13:38
Zdravim. Potrebuju program, ktery vyhodnoti situaci na monitoru (asi podminka kdyz) a dle toho pak provede zvolene instrukce (klik mysi na urcitou cast obrazovky). Existuje neco podobneho uz naprogramovaneho? Jestli ne, v cem se takove veci nejlepe programuji? Mam Windows XP. Diky za odpoved.
Dojigiri (1629)|9.10.2009 17:08
Ono záleží na co přesně má reagovat (objevení se nějakýho konkrétního okna a klepnutí na tlačítko v něm? - dělat to obecně přes skenování plochy a zpracování přímo obrazových dat by byla hodně náročná záležitost), v jednoduchým případě např. cyklický procházení oken přes EnumWindows a hledání okna s určitým názvem, v něm pak lze vyhledat např. určitej button (EnumChildWindows) a po jeho nalezení odeslat např. přes SendMessage že bylo stisknutý tlačítko. Apod.

Jestli je něco takovýho hotovýho nevím, povětšinou podobný úkoly vyžadujou konkrétní přístup podle konkrétní činnosti, kterou je potřeba provést (programovat něco takovýho obecně by bylo asi vcelku složitý).

Všechno se to většinou dělá přes WinAPI (http://msdn.microsoft.com/en-us/library/dd469351%28VS.85%29.aspx), obecně programovat přes WinAPI není úplně triviální. Funkce WinAPI lze volat z různých jazyků, např. C/C++ (který osobně preferuju), Pascal, C#, lze i VB ... nelze použít Javu (resp. lze, ale pouze přes JNI = naprogramování DLL v C/C++ a její volání z Javy).
xmarek (1676)|10.10.2009 15:20
[quote=Dojigiri;300923] ... nelze použít Javu (resp. lze, ale pouze přes JNI = naprogramování DLL v C/C++ a její volání z Javy).[/quote]Tento postup osobně nedoporučuji. Ne, že by to bylo nemožné, ale vyžaduje to nemalé zkušenosti z JNI a C++/C. A v tomto konkrétním případě je to už jednodušší napsat v "core" C++/C. Osobně používám JNI ke komunikaci se zařízeními připojenými přes USB (Seriový, Paralelní port).
durib (1141)|11.10.2009 19:54
Diky za rychlou odpoved. Konkretne to potrebuju na vyhodnoceni barvy aspon 1 pixelu. Barva se meni nahodne. Dle zjisteni barvy by to udelalo tu, ci onu cinnost. Pres nazev okna atd to nejspise nepujde. dik.
Dojigiri (1629)|12.10.2009 09:09
Tak tam bys musel asi vzít screenshot obrazovky a procházet pixely. Pokud víš kterej pixel to přesně je (jaký má souřadnice X a Y), anebo je to dopočítatelný z nějakýho okna (tj. objevuje se to v nějak konkrétně pojmenovaným okně - pak by se muselo najít to okno a udělat jenom screenshot toho konkrétního okna). Jak vzít screenshot obrazovky je např. vidět v tomhle příkladu:
http://groups.google.com/group/win32-programming/browse_thread/thread/55c030edbaeaf026
(funkce CaptureScreen)

Případně se můžeš podívat na Windows Scripting a zajímavě vypadá tenhle program:
http://www.autoitscript.com/
(ale ani jedno nepoužívám takže nevím jestli konkrétně tohle bude umět)
durib (1141)|12.10.2009 19:14
Dik za ten AutoIT, dival jsem se a je tam nejspise i mouseclick. Jeste tam zkusim vyhledat ten screenshot, ale ten tam nejspise nebude. Znam pozici i pozadovanou "barvu" pixelu. V cem je programovane to, co je na tom odkazu? Vidim to tak, ze dle barvy by to spustilo urcity soubor se skriptem -je to sice Pat a Mat reseni, ale snad bude fungovat:p
Dojigiri (1629)|12.10.2009 22:38
Ten příklad co jsem linkoval je v C, takže by měl jít přeložit překladačem C nebo C++ - pro Windows lze např. zdarma stáhnout Microsoft Visual Studio Express 2008 (stáhnout buď Visual C++ 2008 Express web instalaci, anebo celou offline instalaci dole), asi nejlepší volba, ale je to obrovský - cca 800 MB, anebo menší překladače MinGW (bez IDE), případně ještě Dev C++ (vcelku starý, ale funkční i s vývojovým prostředím, jeden čas jsem používal docela rád).
durib (1141)|14.10.2009 14:26
Dekuji. A prosim jeste o trpelivost se mnou, programoval jsem jen v Pascalu:(
Mohl byste mi napsat, jak by vypadal prikaz pro zjisteni barvy urciteho pixelu? Monitor 1440x900 a pixel je na X=200 Y=350. Barva je 238.205.125. Pak jeste podminkovy prikaz neco jako IF "barva" THEN "open file"
Jak teda na to? Stacil by udelat "screen save" z jednoho pixelu a ten pak analyzovat, ale jak programu "rict", aby to udelal- s tim jsem v koncich. diky
Logout (4018)|14.10.2009 14:44
Jak udělat screenshot máš tady, omezit to na jeden pixel snad zvládneš...
http://www.itags.org/programming/1200426/
teda tam se získává obsah jednoho okna, pokud neumíš najít okno, imho svuj DC má i celá obrazovka - tady je to na celou obrazovku
http://www.codeproject.com/KB/dialog/screencap.aspx
a8nr (176)|14.10.2009 16:51
[quote=Dojigiri;300923]nelze použít Javu (resp. lze, ale pouze přes JNI = naprogramování DLL v C/C++ a její volání z Javy).[/quote]
Mohlo by jít použít JNA, čímž by odpadlo vytváření dll, nicméně v tomto případě bude volba jiného jazyka lepší.
Dojigiri (1629)|14.10.2009 17:40
Tak šlo by to třeba nějak takhle (měl jsem připravenou kostru programu protože nedavno jsem dělal něco podobnýho tak jsem to zkusil):

[code]
#include

#define WIN32_LEAN_AND_MEAN
#include

#include
#include


// Settings.
const COLORREF testColor = RGB(238, 205, 125);
const int posX = 200;
const int posY = 350;


int SystemError(LPTSTR sFuncName)
{
const int code = GetLastError();
LPTSTR buff;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, code, 0,
(LPTSTR)&buff, 0, NULL);
MessageBox(NULL, buff, sFuncName, MB_OK | MB_ICONERROR);
LocalFree(buff);
return code;
}


HDC hDesktopDc = NULL;

void OnExit()
{
if (hDesktopDc) {
ReleaseDC(HWND_DESKTOP, hDesktopDc);
}
}

const LPTSTR appName = _T("PixelCheck");

int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Check command line parameters.
if (!lpCmdLine || !*lpCmdLine) {
LPTSTR buff;
FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
_T("Usage: %1 "), 0, 0,
(LPTSTR)&buff, 0, (va_list *)&appName);
MessageBox(NULL, buff, appName, MB_ICONERROR | MB_OK);
LocalFree(buff);
return EXIT_FAILURE;
}

hDesktopDc = GetWindowDC(HWND_DESKTOP);
if (!hDesktopDc) {
return SystemError(_T("GetWindowDC"));
}
// Release the DC on exit.
atexit(OnExit);

bool status = false;
for (;;) {
const COLORREF color = GetPixel(hDesktopDc, posX, posY);
if (CLR_INVALID == color) {
return SystemError(_T("GetPixel"));
} else {
if (color == testColor) {
if (!status) {
status = true;
// Run the file.
const int execResult = (int)ShellExecuteA(NULL, NULL, lpCmdLine, "", NULL, SW_SHOWNORMAL);
if (execResult <= 32) {
SystemError(_T("ShellExecute"));
}
}
} else {
status = false;
}

}
Sleep(200);
}

return EXIT_SUCCESS;
}
[/code]

To si můžeš případně poštelovat a přeložit - parametr programu je cesta exe nebo něčeho, co se má spustit (spustí se cokoliv, co otevře explorer, případně i složka). Zavře se to tak, že to zabiješ ve správci úkolů (šlo by samozřejmě udělat okno, kterým bys to zavřel, ovšem okno má svojí message loop, takže by smyčka pro testování barvy okna musela běžet v jiným vlákně; nebo by šlo pomocí instalace globálního hooku navázat zpracování na změnu screenu, takže by se to spustilo vždycky při změně něčeho na obrazovce, ale to už je zase taky složitostí trochu jinde, je potřeba udělat DLL s hook procedurou atd.).

A fakt se ta barva objevuje celým screen a ne v nějakým okně jo? To je mi trochu divný (jo a btw. asi to nebude fungovat pro fullscreen video, nebo v directX hře apod. - pouze přímo pod Windows).

(co se týká toho tvýho IF, tak jak vidíš v kódu to zase neni tak jednoduchý, protože asi nechceš, aby se ti to spouštělo pořád dokola, když barva trvá, takže je potřeba si pamatovat stav, a jenom když se barva změní zpátky na jinou, stav shodit a při příští změně na požadovanou barvu opět spustit požadovanou aplikaci ...)
durib (1141)|14.10.2009 22:46
Dekuji, ted se tim musim prokousat :) Jinak barva se meni v okne, ne na plose (to jsem tam nepsal) a po kazdem provedeni ukonu se "refreshuje" na novy vystup, ktery je bud stejny, nebo jiny.
Kazdopadne pokud to udela screen save, staci jen, aby to okno bylo videt ne?

V AutoIT vlastnosti oken jsem si vsiml, ze dokaze rozpoznat i barvu pixelu. Vi nekdo, jestli s ni umi i pracovat?
Dojigiri (1629)|15.10.2009 09:33
No pokud je to v okně, to bude skoro to samý, akorát že by se to okno muselo nejdřív najít podle názvu okna (nejlíp přes EnumWindows) jeho handle a ten pak použít pro GetWindowDC. Což by bylo samozřejmě lepší než když se to bude dělat pro celej screen (protože by to fungovalo i pro okna který jsou skrytý za jinýma, a pozice asi taky bude pozice v daným okně a ne na celým screen - je fakt, že jsi nikde přímo nepsal, že to je pro celej screen, jenom já to tak pochopil, přivedlo mě k tomu asi vyjádření že "Pres nazev okna atd to nejspise nepujde" ...)

Co se týká AutoIt, ten jsem zatím nějak nezkoumal, ale jak teď na to koukám tak je to v podstatě jenom jinej způsob programování založenej na podobných principech a měl by to umět taky, třeba funkce PixelGetColor by myslím měla vrátit přímo barvu pixelu určitýho okna na určitých souřadnicích. Okno(a) s určitým názvem lze získat WinList nebo WinGetHandle ... hmm vypadá to na docela silnej nástroj na podobný úlohy.

Opět to lze testovat ve smyčce, což je nejjednodušší ... ideální by samozřejmě bylo to navázat na repaint dotyčnýho okna (ale to je možná až zbytečný a vyžadovalo by to opět hook na window proceduru toho dotyčnýho okna) ...
Dojigiri (1629)|15.10.2009 12:19
Teď jsem si chvilku hrál s tím AutoIt, protože vypadá fakt zajímavě :) ... ovšem zase tak růžový to nejni, protože funkce PixelGetColor sice vrací pixel, ovšem z celý obrazovky a ne toho okna, kterej handle se mu dá (akorát je možný vzít souřadnice relativně k oknu, ovšem stále pro celou obrazovku - WTF) - což znamená, že by testovaný okno muselo bejt stále na popředí (jakmile to místo něco překreje, bere se pixel z toho jinýho okna).

Lze to obejít tak, že se volají funkce přímo z WinAPI, což AutoIt taky umí :thumb takže by skript moh vypadat třeba následovně:

[code]
$winName = "My Window";
$posX = 200
$posY = 350
$color = (((238 * 256) + 205) * 256) + 125

$interval = 200

Opt("WinTitleMatchMode", 2)
Opt("PixelCoordMode", 0)

$hUser32 = DllOpen("user32.dll")
$hGdi32 = DllOpen("Gdi32.dll")

$status = False

While True ; Endless loop.
$handle = WinGetHandle($winName);
if @error Then
$status = False
Else
$dc = GetDC($handle)
$current = GetPixel($dc, $posX, $posY)
if ($current == $color) Then
if Not $status Then
$status = True
MsgBox(0, "Colors match", "Color=" & $color)
EndIf
Else
$status = False
EndIf
ReleaseDC($handle, $dc)
EndIf

Sleep($interval)

WEnd

Func GetDC($handle)
$ret = DllCall($hUser32, "ptr", "GetWindowDC", "hwnd", $handle)
Return $ret[0]
EndFunc

Func ReleaseDC($handle, $dc)
$ret = DllCall($hUser32, "int", "ReleaseDC", "hwnd", $handle, "ptr", $dc)
Return $ret[0]
EndFunc

Func GetPixel($dc, $x, $y)
$ret = DllCall($hGdi32, "int", "GetPixel", "ptr", $dc, "int", $x, "int", $y)
Return $ret[0]
EndFunc
[/code]

A místo toho MsgBox si tam můžeš dát takovou akci, kterou potřebuješ provést (třeba poslat klik někam).
durib (1141)|17.10.2009 13:07
Takze misto "My window" dam nazev okna z Title ve AutoIT Window Info?
Ten "dolar" pred znaci promennou?
Proc se ty RGB cisla nasobi a scitaji?
Kdyz mi samotne AutoIT Window Info vyhodi takovou barvu: 0x007C22, muzu pouzit tento udaj?
Taky ale nemuzu zjistit pozici pixelu vzhledem k velikosti okna, pise mi to vzhledem k rozliseni monitoru, takze to asi budu muset dat na fullscreen a pak to premerit jeste jednou ze?
To zatim vse. Velice dekuji za pomoc.
Dojigiri (1629)|17.10.2009 14:49
Ano, místo MyWindow dát název toho okna (měl by být vidět i v záhlaví toho okna). Stačí jeho část (ale zase taková, aby jednoznačně identifikovala to okno), když je WinTitleMatchMode nastavenej na 2, bere to část která je kdekoliv v názvu okna (viz dokumentace AutoIt k WinTitleMatchMode).

RGB se sčítají a násobí, aby se z nich udělalo jedno číslo který značí celkovou barvu (plná červená je 0xFF0000, neboli 255 * 256 * 256, plná zelená je 0x00FF00, neboli 255 * 256, a plná modrá 0x0000FF). Nutno použít takovou barvu, jakou má ten bod, kterej chceš testovat.

Co se týká pozice bodu, opravdu asi nejlíp to půjde změřit při maximalizovaným okně (anebo udělat screen přes Alt+PrtScr, vložit do Malování a zjistit to z obrázku).

Případně můžeš zaměnit funkci GetWindowDC (vrací DC celýho okna včetně titulku, menu atd.) za GetDC (vrací pouze klientskou část okna, tj. bez záhlaví, menu atd.).
durib (1141)|21.10.2009 16:11
Dobre, uz jsem si na vetsinu odpovedel sam :D
Jen jeste potrebuju, aby byla cinnost cteni pixelu provedena az po "refresh" okna. Nekdy se to totiz sekne a reseni v podobe Sleep(5000) neni ono. dik
durib (1141)|21.10.2009 16:17
Aj, pardon. Nevsiml jsem si 2. stranky. Znate jeste zpusob jak urychlit hybani mysi (mouseclick)? - najizdi strasne pomalu. Ono je vlastne blbe, ze tam kurzor "najizdi", chtelo by to spise, aby se tam hned "objevil".
Dojigiri (1629)|21.10.2009 17:05
Pokud používáš funkci MouseClick, zkus místo ní použít ControlClick, ta funguje tak, že není vůbec potřeba přesouvat kurzor myši (akorát je potřeba zjistit ID a součadnice controlu, na který se má klepnout - ale mělo by fungovat i v rámci celýho okna ...)
durib (1141)|21.10.2009 22:08
A jak jeste na ten "refresh" okna pro novou barvu? (na ten controlclick se jeste podivam), diky.
durib (1141)|21.10.2009 22:23
Tak s tim controlclick si nevim rady. AutoIT Win info mi vypise:
>>>> Control <<<<
Class: MozillaWindowClass
Instance: 4
ClassnameNN: MozillaWindowClass4
Advanced (Class): [CLASS:MozillaWindowClass; INSTANCE:4]
ID:
Text:
Position: 0, 28
Size: 640, 509
ControlClick Coords: 517, 475
Style: 0x56000000
ExStyle: 0x00000000
Handle: 0x00010726

A pokud controlclick neumi pracovat jen s koordinaty (neco takoveho v help bylo, ale nevim)...
Dojigiri (1629)|22.10.2009 10:29
Teď jsem vyzkoušel že ControlClick funguje nejen s ID, ale i se jménem třídy ClassNameNN, tj. např.

ControlClick("Mozilla Firefox", "", "MozillaWindowClass4", "main", 1, 360, 265)

(jenže já tam mám MozillaWindowClass5, takže to asi bude závislý na tom, jak se zrovna firefoxu povede spustit, takže by to skutečný classnamenn chtělo vždycky nejdřív nějak zjistit aby se použilo aktuální - myslel jsem, že by mohlo fachčit zadat id jako "[CLASS:MozillaWindowClass]" ale to nefunguje, je potřeba zadat i Instance (což je opět to číslo, který se může měnit, takže jsme tam kde jsme byli)).


A s tím refresh nevím přesně jak to myslíš - jakože skript má provést sám refresh? (= poslat click na tlačítko refresh) anebo má skript čekat na to, až "někdo" udělá refresh? (to by bylo obtížnější a nevím jestli vůbec v AutoIt řešitelný - bylo by nutný navázat hook na window proceduru okna, zjistit, na kterou win message je vlastně třeba reagovat atd.).
durib (1141)|22.10.2009 15:45
Diky controlclick funguje uzasne, hlavne je rychly (ani nestacim sledovat, co dela :D) a neuziva mys k pohybu. K tomu refresh- nekdy se muze stat, ze se cekani na novou "barvu" sekne a ono to pak analyzuje tu starou. Z toho duvodu jsem nastavil Sleep(5000), ale neni to moc elegantni reseni. Existuje-li lepsi jednoduche reseni, budu rad. Jinak se holt bude muset pockat.

Jeste potrebuju poradit s necim jinym: cyklus Do - Until chci zakoncit prikazem "delej dokud nezmacknu ESC, vypis Msgbox a ukonci skript"

Dekuji.