Ovládání počítače
Jakmile jsem měl zprovozněné snímání z kamery, musel jsem pořád do pilotní verze projektu ještě něco udělat. Rozhodl jsem se, že udělám rozhraní pro ovládání počítače posíláním falešných událostí (stisk klávesy, pohyb myši, kliknutí, …).
Zasílání falešných událostí rozhodně nebylo tak snadné jak jsem si zprvu myslel. Původně jsem měl za to, že to zvládne Qt knihovna a to rovnou přenositelně. Bohužel jsem rychle zjistil, že byla celkem mylná představa. Qt sice umí posílat události, ale jen pro svoje widgety, takže jsem se musel poohlédnout někde jinde. Moc jsem na výběr neměl, jako jediná možnost se zdá knihovna Xlib a její rozšíření XTest pro X Window system. Takže o nějaké přenositelnosti jsem si mohl nechat zdát. No každopádně jsem začal studovat posílání událostí v Xlib. Rošíření XTest není nutné používat, ale ohromně to ulehčí práci. Našel jsem tedy příklad s použitím pouze Xlib kihovny ale i pár příkladů s použitím XTest rozšíření.
Nejprve jsem se pustil od klávesnicových událostí:
Pro odeslání klávesnicové události je potřeba znát název události (klávesy). Z názvu klávesy lze zjistit název keysym konstanty, což je číslo reprezentující konkrétní klávesu. Keysym je pak nutné převést kód události, tzv. keycode, ten už se pak jednoduše předhodí funkci pro vyvolání události.
Název keysym se odvodí tak, že se před název klávesy připojí XK_. Převod keysym na keycode se provede pomocí funkce XKeysymToKeycode.
Pro samotné odeslání události je určena funkce XTestFakeKeyEvent z rozšíření XTest.
Kód pro odeslání události stisku klávesy enter by vypadal takto:
1 2 3 4 5 6 | Display* display = XOpenDisplay(0); KeySym keysym = XK_Return; Keycode keycode = XKeysymToKeycode(display, keysym); XTestFakeKeyEvent(display, keycode, true, CurrentTime); |
Zdrojový kód ukázkové aplikace je zde.
S událostmi pro ovládání myši se pracuje takto:
U myši jsou dva typy událostí – pohyb nebo stisk/uvolnění tlačítka (mezi něž se počítá i točení kolečkem).
Pro pohyb s kurzorem jsou určeny dvě funkce XTestFakeMotionEvent a XTestFakeRelativeMotionEvent. Fuknce se liší pouze v tom, že ta první umístí kurzor na danou pozici, kdežto ta druhá ho posune relativně vůči aktuální pozici.
Stisk tlačítka myši se provede funkcí XTestFakeButtonEvent. Je potřeba znát číslo tlačítka, číslování je následující: 1 – levé tlačítko, 2 – prostřední tlačítko (kolečko), 3 – pravé tlačítko, 4 – točení kolečkem nahoru a 5 – točení kolečkem dolu.
Kód pro pohyb myši na pozici [10;10], následné přesunutí směrem [5;3] a na konec kliknutí pravým tlačítkem bude tedy tento:
1 2 3 4 5 6 7 | Display* display = XOpenDisplay(0); XTestFakeMotionEvent(display, -1, 10, 10, CurrentTime); XTestFakeRelativeMotionEvent(display, 5, 3, CurrentTime); XTestFakeButtonEvent(display, 3, true, CurrentTime); XTestFakeButtonEvent(display, 3, false, CurrentTime); |
Zdrojový kód ukázkové aplikace je zde.
A nakonec jak vykonat příkaz pro shell:
Vykonání příkazu sice není přímo událost, ale zařadím to mezi ně. Nyní už není potřeba knihovna Xlib, stačí už pouze systémový hlavičkový soubor stdlib.h a funkce system. Této funkci se jednoduše předá jako argument řetězec obsahující příkaz pro shell a ona ho jednoduše vykoná, toť vše. Toto je si moc pěkné, ale je potřeba si dát na něco pozor. Pokud příkaz spouští program, který vyžaduje vstup z konzole a vaše aplikace vyvolávající onen příkaz nebyla puštěna z konzole, může dojít k zamrznutí X serveru.
Zde ještě na ukázku kód spouštějící webový prohlížeč firefox:
1 | system("firefox"); |
Zdrojový kód ukázkové aplikace je zde.
Pokud byste si chtěli zde zmiňované vyzkoušet naživo, pak po zkompilování projektu budou ve složce bin/test/manual_tests/ testovací mini-aplikace.