Zadání Navrhněte systém, který zaznamená interakci člověka (stisky kláves, pohyb kurzoru myši, klikání myši, dragování objektů, atd.) s flash animací. Tento systém poté umožní zpětné přehrání těchto interakcí. Vámi navržený systém by měl obsahovat tlačítka na pozastavení, zastavení a převinutí zaznamenaných akcí.
Návrh řešení Celý systém lze rozdělit na dvě oddělitelné části – část určená pro záznam (recorder) a část určená pro pozdější přehrání zaznamenaných akcí (player).
Recorder Recoder lze realizovat dvěma způsoby, buď jako flash animaci, která do sebe vloží zaznamenávanou flash animaci nebo jako samostatný soubor *.as obsahující pouze zdrojový text ActionScriptu, který se přilinkuje k testované flash animaci. Událostní model funguje tak, že existují odesílatelé událostí (dispatcher), ke kterým se mohou zaregistrovat posluchači (listener) obsahující funkce (metody) obsluhující danou událost. Odesílatele i posluchače událostí lze v ActionScriptu 2.0 vytvořit, nám však k záznamu událostí stačí vytvořit jen posluchače obsluhujícího události myši a klávesnice a zaregistrovat ho u globálního odesílatele událostí “Mouse”, v případě myši, a “Key”, v případě klávesnice. Tito odesílatelé přímo odrážejí reakce uživatele. V rozumných programovacích jazycích získá metoda posluchače jako parametr objekt reprezentující událost nesoucí veškeré informace o dané události. Potom stačí tento objekt serializovat a uložit pro pozdější načtení playerem. Bohužel v ActionScriptu 2.0 se tento parametr nepředává a je třeba informace o události získávat z globálních proměnných (např. _xmouse, _ymouse) nebo z globálního odesílatele událostí (např. Key.getAscii(), Key.getCode()), avšak po posbírání informací již nic nebrání uložení události.
Player Úkolem playeru je načíst a deserializovat nebo jinak zrekonstruovat recorderem uložený objekt události a ve správný čas ho pomocí odesílatele, u kterého jsou zaregistrováni všichni posluchači přehrávané flash animace, předat těmto posluchačům. Na to flash animace zareaguje stejně jako by byla akce právě vyvolána uživatelem. Toto je jediné správné řešení problému. Bohužel v ActionScriptu 2.0 je znemožněno hned ze dvou důvodů. Prvním důvodem je výše zmíněné předávání objektu události posluchači jako parametru. Tím, že se informace o události musí číst z globálních proměnných je třeba je při vyslání naší události nastavit na příslušné hodnoty, avšak ne všechny lze změnit. Druhým vážnějším důvodem je nemožnost vyslání události pomocí globálních odesílatelů “Mouse” a “Key”, ke kterým jsou zaregistrováni všichni posluchači přehrávané flash animace. Věřím, že v některé z příštích verzí ActionScriptu již toto možné bude a že 1
Remote Flash Usability testing
Lukáš Skřivánek
samotné odeslání nastaví příslušné globální proměnné, čímž odpadne i prvně zmíněný problém, nebo dokonce začne používat předávání objektu události jako parametru posluchači. Paradoxem této situace je, že lze vytvořit jakýsi objekt události i vlastního odesílatele události, který již námi vytvořenou událost odeslat umí. Bohužel u našeho odesílatele nejsou zaregistrováni posluchači přehrávané flash animace. Ideální by tedy bylo, kdyby šlo přesměrovat registrace posluchačů z globálních odesílatelů “Key” a “Mouse” na našeho odesílatele a tím dokonce zastínit interakci uživatele v době přehrávání flash animace, což ovšem samožřejmě nejde. Další řešení již není zcela ideální, ale pokud by bylo možné získat z odesílatele veškeré posluchače, které jsou u něho zaregistrováni, bylo by možné volat obslužné funkce (metody) “ručně”. Ovšem ani toto odesílatelé událostí v ActionScriptu 2.0 neumožňují.
Implementace Recorder Při implementaci recorderu jsme sáhli po variantě samostatného souboru obsahujícího zdrojový text ActionScriptu *.as, který se bude linkovat s flash animací, ve které chceme odchytávat interakce uživatele. Pro ukládání dat jsme zvolili cestu přes PHP skript, přestože současná verze produktu Macromedia Flash 8.0 umí ukládat do souboru pomocí JavaScriptu, protože chceme ukládat interakce do databáze MySQL. Pro komunikaci s PHP skriptem používáme XML verze 1.0. Na začátku pomocí PHP skriptu získáme z databáze číslo nového uživatele a toto číslo v databázi rezervujeme s událostí start, dále vytvoříme dva posluchače obsluhující události onKeyDown, onKeyUp, onMouseDown, onMouseUp a onMouseMove. V obsluze těchto událostí se tvoří XML soubor, který obsahuje číslo uživatele, url flash animace, čas události, číslo snímku, na kterém došlo k události, druh události a další informace o události. Čas události se měří od první interakce uživatele (první událost je v čase 0). Události jsou odesílány v průběhu záznamu po předem daném množství událostí. Záznam končí zavřením flash animace, ale v tuto chvíli je potřeba odeslat poslední zaznamenané události. O nedokonalosti událostního modelu v ActionScriptu 2.0 již bylo v tomto dokumentu řečeno mnohé a proto čtenáře jistě nepřekvapí, že neobsahuje událost ukončení přehrávače flash animace. Tímto faktem vstupuje do hry JavaScript, mimochodem jazyk podobný ActionScriptu, a omezení zaznamenávání interakcí uživatele pouze s flash animací umístěné v HTML stránce. JavaScript totiž umožňuje nejen zachytit událost ukončení setrvání HTML stránky v prohlížeči, ale dokonce volat zpřístupněné funkce ActionScriptu v přehrávané flash animaci. Pro snazší pochopení provázání jednotlivých programovacích jazyků a toků dat slouží následující obrázek:
2
Remote Flash Usability testing
Lukáš Skřivánek
Ve chvíli uzavření prohlížeče, načtení jiné stránky či obnovení stránky je JavaScriptem odchycena událost onUnload a JavaScript volá funkci ActionScriptu onClose(). Tato funkce přidá poslední událost end s časovým razítkem a odešle poslední události skriptu PHP. PHP skript obsluhuje požadavky ActionScriptu tak, že buď načte z databáze číslo posledního uživate, to zvýší a předá zpět flash animaci, nebo přijme XML soubor, ten přečte a pomocí SQL uloží data v něm obsažená do databáze. Než začneme databázi jako uložiště událostí využívat je třeba v ní vytvořit tabulku. Naše tabulka obsahuje atributy: ID, UrlSwf, UserID, Frame, Time, Kind, MouseX, MouseY, Ascii, KeyCode.
Player Z důvodů uvedených v části o návrhu řešení není v současné době možné implementovat player podle prvotní vize v ActionScriptu 2.0. Možným řešením je buď vyčkat příchodu vyšších verzí ActionScriptu nebo jiných technologií spojených s Macromedia Flashem nebo sáhnout po jiných nastrojích jakými může být například Win32 API, jenž bude posílat události přímo přehrávači flash animace.
Instalace Recorder Pro správnou funkci recorderu je nutné mít: 1. zdrojový soubor recorderu (recorder.as - příloha č. 1) 2. zdrojový soubor testované flash animace (*.fla) 3. html stránku, která bude obsahovat flash animaci (recorder.html - příloha č. 3) 4. PHP skript pro ukládání událostí (save.php - příloha č. 2) 5. schéma tabulky (sql.txt - příloha č. 4) 6. funkční webový server s podporou PHP skriptů 7. databázový server MySQL 3
Remote Flash Usability testing
Lukáš Skřivánek
1. Ve zdrojovém souboru recorderu (recorder.as) je třeba modifikovat cestu k PHP skriptu určenému k ukládání událostí: _global.php_name = "http://www.server.cz/save.php"; a volitelně je možné změnit po kolika událostech má docházet k odesílání: _global.send_count = 50; 2. Zdrojový soubor testované flash animace je třeba modifikovat tak, že na první snímek animace vložíme akci: #include "recorder.as" Na konci toho řádku nesmí být středník. Tato akce způsobí přilinkování souboru recorder.as k flash animaci. Pokud se soubor recorder.as nachází v jiném adresáři nebo je přejmenován, je třeba změnit cestu a název vkládaného souboru. Pak již stačí jen spuštěním animaci znovu přeložit. 3. V html stránce je třeba modifikovat cestu k flash animaci a to hned na dvou místech: <param name="movie" value="animace.swf"> a <embed src="animace.swf" .... Pokud budete vytvářet stránku svoji, upozorňuji, že je nezbytně nutné, aby obsahovala <param name="allowScriptAccess" value="always" /> v tagu objekt flash animace a AllowScriptAccess="always" v tagu embeded. Bez tohoto by nefungovala komunikace mezi JavaScriptem a ActionScriptem. V mnohých zdrojích se dočtete, že hodnota always je u atributu AllowScriptAccess automatická bez uvedení, ale není to pravda. 4. V PHP skriptu je třeba správně nastavit adresu k MySQL serveru: $SQL_Server="mysql.server.cz"; uživatelské jméno v MySQL: $SQL_Login="user name"; heslo: $SQL_Password="password"; databázi: $SQL_Databaze="databaze";
4
Remote Flash Usability testing
Lukáš Skřivánek
a název tabulky, kterou vytvoříme za chvíli: $SQL_Table="recorder"; 5. Podle tohoto schématu je třeba vytvořit tabulku v databázi. Pokud chcete zvolit jiný název tabulky nezapomeňte správně nastavit v PHP skriptu proměnnou $SQL_Table (část 4.). Jiné zásahy do schématu se provádět nemusí. Body 6 a 7 přesahují rámec tohoto textu a nejsou ani cílem, stačí mít funkční webový server s podporou PHP skriptů. Do jeho adresáře s publikovanými html a php stránkami přikopírovat soubory: •
nově přeloženou flash animaci (*.swf)
•
html stránku, která bude obsahovat flash animaci (recorder.html)
•
PHP skript pro ukládání událostí (save.php)
Zároveň Vám musí fungovat MySQL server a musíte mít správně nastavené veškeré výše zmíněné proměnné (cesty, jména, hesla ...) a vytvořenou tabulku (bod 5.). Pak již stačí zadat do prohlížeče adresu: http://adresaVasehoWebovehoServeru/cesta/recorder.html. Měla by se Vám zobrazit html stránka obsahující vaši flash animaci. Při první interakci s touto animací se začnou veškeré interakce zaznamenávat (včetně té první) a záznam skončí až při uzavření okna prohlížeče, načtení jiné stránky nebo obnovení stránky(v tom případě může začít záznam znovu pod novým uživatelem).
Závěr Ač celý dokument vyznívá proti produktu Macromedia Flash a ActionScriptu, je třeba říci, že se jedná o velmi kvalitní kreslící a prezentační nástroj, ve kterém lze dokonce tvořit aplikace a hry, je uživatelsky přívětivý, intuitivní a velmi dobře se v něm pracuje. ActionScript samotný je jazyk, který prochází vývojem a tím se stává stále mocnějším nástrojem. Podle mého názoru jeho událostní model není zatím zcela vyzrálý, avšak je třeba si uvědomit, že na podobné účely není určený ani navržený a pro běžné aplikace je plně dostačující. Celá práce byla realizována v Macromedia Flashi 8.0 Trial version a je pravděpodobné, že v nižších verzích nebude korektně fungovat zvláště zpřístupnění funkcí z ActionScriptu pro JavaScript. (ExternalInterface.addCallback("onClose", null, onClose);)
Zdroje http://www.macromedia.com http://www.adobe.com/cfusion/tdrc/index.cfm?product=flashpro&loc=en_us – Trial version 5
Příloha č. 2 – save.php document_element(); $url="unknown"; $user=0; // zero is ban $frame=0; $time=0; //parse XML function parse_node($node) { global $SQL_Table, $url, $user, $frame, $time; if ($node->has_child_nodes()) { foreach($node->child_nodes() as $n) { if ($n->node_name()=='url'){ foreach($n->child_nodes() as $text) { $url=$text->node_value(); } } if ($n->node_name()=='user'){ foreach($n->child_nodes() as $text) { $user=$text->node_value(); } } if ($n->node_name()=='end'){ foreach($n->child_nodes() as $text) { $endtime=$text->node_value(); } if($user!=0){ $UP = mysql_query("INSERT INTO $SQL_Table (UrlSwf,UserID,Frame,Time,Kind) VALUES('$url',$user, 0, $endtime, 'end')"); } } if ($n->node_name()=='event'){ foreach($n->child_nodes() as $text) { if ($text->node_name()=='time'){ foreach($text->child_nodes() as $value) { $time=$value->node_value(); } } if ($text->node_name()=='frame'){ foreach($text->child_nodes() as $value) { $frame=$value->node_value(); } } if ($text->node_name()=='kind'){ foreach($text->child_nodes() as $value) { $kind=$value->node_value(); } } if ($text->node_name()=='mouse_x'){ foreach($text->child_nodes() as $value) { $mouse_x=$value->node_value(); }
10
Remote Flash Usability testing
Lukáš Skřivánek
} if ($text->node_name()=='mouse_y'){ foreach($text->child_nodes() as $value) { $mouse_y=$value->node_value(); } } if ($text->node_name()=='ascii'){ foreach($text->child_nodes() as $value) { $ascii=$value->node_value(); } } if ($text->node_name()=='code'){ foreach($text->child_nodes() as $value) { $code=$value->node_value(); } } } if (($kind=="onKeyUp")||($kind=="onKeyDown")){ if($user!=0){ $UP = mysql_query("INSERT INTO $SQL_Table (UrlSwf,UserID,Frame,Time,Kind,Ascii,KeyCode) VALUES('$url',$user, $frame, $time, '$kind', $ascii, $code)"); $kind=""; $ascii=0; $code=0; } }else{ if($user!=0){ $UP = mysql_query("INSERT INTO $SQL_Table (UrlSwf,UserID,Frame,Time,Kind,MouseX,MouseY) VALUES('$url',$user, $frame, $time, '$kind', $mouse_x, $mouse_y)"); $kind=""; $mouse_x=0; $mouse_y=0; } } } } } } parse_node($root); $dom->free(); }else{ //read and send user ID $result = mysql_query("SELECT COALESCE( MAX( UserID ) , 0 ) AS MAXUSER FROM $SQL_Table"); $row = mysql_fetch_array($result); $maxid = $row['MAXUSER']; $maxid++; $UP = mysql_query("INSERT INTO $SQL_Table (UrlSwf,UserID,Frame,Time,Kind) VALUES('unknown',$maxid, 0, 0, 'start')"); header("Content-type: text/xml"); echo "\n"; echo "<user>"; echo $maxid; echo "";
}
} } @mysql_close ($Spojeni);
?>
11
Remote Flash Usability testing
Lukáš Skřivánek
Příloha č. 3 – recorder.html NUR - FLASH - Recorder <script type="text/javascript"> /* */
12
Remote Flash Usability testing
Lukáš Skřivánek
Příloha č. 4 – sql.txt CREATE TABLE `recorder` ( `ID` INT NOT NULL AUTO_INCREMENT, `UrlSwf` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL , `UserID` INT NOT NULL, `Frame` INT NOT NULL, `Time` INT UNSIGNED NOT NULL, `Kind` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL, `MouseX` MEDIUMINT, `MouseY` MEDIUMINT, `Ascii` TINYINT UNSIGNED, `KeyCode` SMALLINT, PRIMARY KEY ( `ID` ) );