KMac
aneb jak přimět vašeho PSIONa dělat věci, které jste dosud považovali za nemožné
Předpokládám, že mnoho uživatelů špičkových palmtopů PSION si - stejně jako já - občas postesklo nad tím, že PSION nedokáže nahrávat a přehrávat "klávesnicová makra". Předpokládám, že mnoho uživatelů PSIONu - stejně jako já donedávna - neví o existenci aplikace KMac, která to umožňuje. To, a ještě mnohem více.
KMac sice není aplikace oficiálně podporovaná firmou PSION; vytvořil ji ale s hlubokou znalostí operačního systému EPOC jeden z nejlepších PSIONovských programátorů David Wood. Díky tomu se nejedná o žádný prasecký hack (jako tomu je např. u mojí podpory češtiny), ale o zcela korektní a slušný systémový program. V tomto článku si ukážeme co dokáže - a co s ním dokáže zkušený uživatel.
1. Základy
Samozřejmě, základní službou aplikace pro práci s makry je možnost nahrát a přehrát "makro" - tj. sekvenci stisků kláves. Nic není jednoduššího; máme-li v PSIONu instalovanou aplikaci KMac, stiskneme prostě kdykoli a kdekoli kombinaci Control-Shift-Space; KMac zobrazí dialog ve kterém zadáme jméno makra, a pak prostě píšeme (nebo provádíme jakékoli jiné akce). Nakonec stiskneme znovu kombinaci Control-Shift-Space, a KMac všechny stisknuté klávesy uloží. Chceme-li makro přehrát, stiskneme kombinaci Control-Shift-Enter...
Konkrétní příklad: nemáme-li právě S3c s jeho správcem souborů, víme všichni jak je nepohodlné dělat úpravy více souborů najednou - správce souborů S3a ukončí práci po každé akci, a musíme jej znovu otevírat. Proč ale nepoužít KMac? Dejme tomu, že máme nějakou práci v adresáři B:\APP; stiskneme tedy v systémové obrazovce postupně klávesy Control-Shift-Space (aktivace KMacu), Enter (nahráváme nepojmenované makro), Control-Tab (správce souborů), šipku dolů (adresář), "B:\APP\" a Enter (jsme v požadovaném adresáři), Control-Shift-Space (ukončíme nahrávání)... a je to! Kdykoli se nyní chceme opět dostat do správce souborů a aktivovat adresář B:\APP, stiskneme prostě kombinaci Control-Shift-Enter.
KMac umí zpracovávat i další kombinace s přepínači Control-Shift: Control-Shift-
(diamond) zobrazí seznam všech maker, ze kterého si můžeme podle jména vybrat makro k přehrání, Control-Shift-Esc přeruší přehrávání makra a Control-Shift-Help zobrazí nápovědu, obsahující všechny tyto kombinace... Navíc můžeme kterémukoli makru přiřadit kombinaci Control-Shift-písmeno (na minulém obrázku vidíme, že např. makro Vyhledat v adresáři má kombinaci Control-Shift-A); stiskneme-li tedy Control-Shift-A, okamžitě se přehraje odpovídající makro...
Mimochodem, vidíme, že makro beze jména má přiřazenou kombinaci Control-Shift-M; to ale není nic jiného, než stará známá kombinace Control-Shift-Enter (protože Enter je totéž, jako Control-M). KMac prostě kombinaci Control-Shift-M přiřadí každému nově nahranému makru; proto jej můžeme ihned kombinací Control-Shift-Enter přehrát.
2. Přímé programování
Pozorného čtenáře už možná napadlo, že naše makro pro nastavení adresáře by bylo ještě mnohem šikovnější, kdyby na začátku nějak ověřilo není-li náhodou otevřený dialog, a v kladném případě nejprve přehrálo klávesu Enter. Tak bychom prostě dialog pro práci se zvoleným souborem ukončili kombinací Control-Shift-Enter namísto klávesy Enter, a systém by se po provedení akce sám vrátil zpět do správce souborů a do požadovaného adresáře.
KMac takové věci samozřejmě dokáže; musíme je již ale naprogramovat "ručně". Použijeme prostě textový editor a otevřeme soubor KMA\Kmac.kma, do kterého aplikace standardně ukládá všechna makra. Pro větší pohodlí takové editace si můžeme vytvořit nový seznam souborů s aplikací Word v textovém režimu a adresářem a příponou kma:
Aplikace KMac makra ukládá do naprosto standardního textového souboru, takže jej můžeme zpracovávat editorem Word bez jakýchkoli problémů. Na prvním řádku souboru je vždy text KMAC 1.00, podle kterého aplikace KMac ověří jedná-li se skutečně o soubor maker; za ním následuje klíčové slovo AUTO se specifikací kombinace kláves pro nově nahrávaná makra (standardně M, jak již víme), a pak jsou v něm již uloženy definice maker.
Definice makra je jednoduchá - uvádí ji klíčové slovo MACRO se jménem makra, za ním může být uvedeno několik přepínačů (např. KEY se specifikací klávesy která je makru přiřazena, nebo QUIET, aby makro nevypisovalo na obrazovku "Playback successful") a za klíčovým slovem CONTENTS následují příkazy, formující tělo makra. Příkazy odpovídající klávesám, nahraným "živě" pomocí kombinace Control-Shift-Space jsou triviální - jedná se prostě o kódy patřičných kláves (a případných přepínačů). V editoru tedy uvidíme něco jako
Nemůžeme samozřejmě v tomto článku podrobně popisovat všechny příkazy, kterým KMac rozumí; součástí KMacu je však podrobný uživatelský manuál a databáze, obsahující specifikace všech jeho příkazů:
V ní si například najdeme, že pro odeslání znaku nebo znakového řetězce slouží příkaz S (i když v tomto jednoduchém případě, kdy chceme odeslat pouze Enter, bychom stejně snadno mohli do makra prostě přidat kód 13) a pro ověření je-li otevřen dialog slouží příkaz J. Doplníme tedy do makra vše co je třeba, a pojmenujeme jej třeba "Adresář B:\APP":
V této podobě makro nejdříve ověří je-li otevřen dialog; jnení-li tomu tak, přeskočí jeden následující řádek - odeslání Enteru (S^C). Pak zůstává původní živě nahrané makro, které otevírá požadovaný adresář.
Hned makro vyzkoušíme... a zjistíme, že nefunguje správně. Není-li otevřen dialog, funguje vše stejně ajko předtím - to jsme ostatně chtěli. Je-li však otevřen dialog (např. pro přejmenování souboru), makro jej správně ukončí klávesou Enter (odeslanou příkazem S^C), ale neotevře znovu správce souborů. Proč tomu tak je? Důvod je jednoduchý - správce souborů po potvrzení dialogu pro přejmenování souboru otevře informační okno ("Renaming A to B"); dokud není toto okno uzavřeno, můžeme mačkat kterékoli klávesy, a správce souborů je prostě ignoruje. KMac to ale samozřejmě nemůže vědět, takže klávesy potřebné pro otevření našeho adresáře přehraje právě "do" tohoto informačního okna.
Řešení je snadné - stačí po potvrzení dialogu klávesou Enter požádat KMac aby nejprve nechal PSION dodělat vše co má na práci; k tomu slouží příkaz y (yield). Cílová podoba makra - tentokrát plně funkční - tedy vypadá takto:
Paleta příkazů kterým KMac rozumí je velmi rozsáhlá - můžeme otevírat a zavírat soubory, přímo volit příkazy z menu, zjišťovat (a modifikovat) jméno aktuální aplikace a souboru, který právě zpracovává. Můžeme dokonce programově přepínat aplikace, které mají dostávat "přehrávané" klávesy a rozhodovat, která aplikace se má přepnout na popředí ("na obrazovku") a která má běžet v pozadí.
Ukažme si jednoduchý příklad makra, které se připojí k aplikaci System a zapne hlasité 'cvakání' při stisknutí klávesy:
Makro - s přiřazenou kombinací Control-Shift-L - se nejprve připojí k aplikaci System (gSystem) a pak nastaví 'hlasité cvakání' - příkaz S, jak již víme, odesílá 'klávesy' připojenému programu, @s odpovídá kombinaci PSION-S, ^D je šipka dolů ("Down"), 'l' zvolí hlasité ('loud' - makro je psáno pro anglickou verzi) cvakání a ^C odešle 'klávesu' Enter. Konečně příkaz f připojí KMac k aplikaci, která je právě aktivní - ať již to je kterákoli - a příkaz I vypíše zadaný text do levého horního rohu obrazovky.
3. Chceme-li doopravdy programovat...
Sada příkazů makrojazyka KMac je dost silná, a jak jsme viděli v prvním příkladu, obsahuje i příkazy pro testování jednoduchých podmínek a základní větvení programu. Pokud bychom však chtěli v rámci makra naprogramovat komplikovanější činnost, jeho vlastní příkazy by nestačily. To není opomenutí Davida Wooda; naopak - jedná se o naprosto rozumné rozhodnutí: na počítači, který je standardně vybaven interpreterem jednoduchého a přitom poměrně silného programovacího jazyka, by byl naprostý nesmysl zavádět jazyk další. Namísto toho obsahuje KMac prostředky, jak využívat jazyka OPL - který jsme měli samozřejmě v minulém odstavci na mysli.
Především, v makrech můžeme kdekoli použít příkaz o<jméno>, který zavolá a provede OPL program zadaného jména. V programech OPL - ať již jsou volány z maker KMacu nebo 'normálním' způsobem - zase můžeme využívat služby KMacu. Jinými slovy, KMac rozšiřuje jazyk OPL o možnost připojit se k jakékoli aplikaci a řídit ji odesíláním "stisků kláves".
Ukážeme si dva příklady. První z nich je jednoduchoučký, ale přitom velmi šikovný: připravíme makro, které při stisknutí patřičné kombinace kláves - řekněme Control-Shift-D - vloží na místo kurzoru aktuální datum. Do souboru Kmac.kma zapíšeme jen 'slupku' makra, zajišťující zavolání odpovídajícího OPL programu při stisknutí požadované kombinace kláves:
OPL program Datum.opl nebude o mnoho složitější - obsahuje jen šest řádků; první tři jen zavedou do OPL služby KMacu a poslední KMac opět odpojí, zbývající dva (příkazy lpWrite) mu odešlou příkazy f a S<datum>:
|
Je zřejmé, že bychom program mohli snadno modifikovat tak, aby datum bylo v libovolném formátu. Je však vidět základní princip spolupráce OPL a KMAcu - v OPL máme k dispozici příkaz lpWrite, který KMacu odešle příkaz, daný svým parametrem. Provedeme-li tedy např. v OPL příkaz lpWrite:(%S,"ahoj"), je to totéž, jako kdybychom přímo v makru zapsali příkaz Sahoj. Některé další příkazy, určené speciálně pro OPL, jsou navíc k dispozici pod svými čísly prostřednictvím příkazu lpSend (pro ty, kdo mají nějaké zkušenosti s objektovým programováním PSIONů můžeme říci, že příkaz lpSend nedělá nic jiného, než že objektu KMac pošle zadanou zprávu).
Druhý příklad který si ukážeme bude trochu komplikovanější - ukáže ale, jak silné služby může KMac ve spolupráci s OPL nabízet. Vytvoříme makro, které 'vezme' právě označený text v libovolné aplikaci a vyhledá jej v databázi adres. Část makra uvedené v Kmac.kma je stejně jednoduchá jako u makra pro zápis data; ukážeme si proto jen program v OPL:
| lpWrite:(%f,"") | :rem Připojení k aktivní aplikaci |
| q$="%s"+chr$(0) | :rem KMac očekává 'C stringy' s 0 na konci |
|
| if len(b$)=0 | :rem Nebyl označen žádný text | |
| lpWrite:(%F,"") | :rem Vrátíme aplikaci do popředí | |
| goto Quit | :rem (na obrazovku) a konec |
| if x$<>ADR | :rem Není-li aktivní právě databáze adres... |
| lpWrite:(%F,"") | :rem Přesuneme databázi do popředí... |
Program by se opět dal zdokonalit - v případě že nebyl označen žádný text, mohli bychom pro vyhledávání vzít slovo nad kterým je právě kurzor; mohli bychom volit databázi pro vyhledávání podle textu ve kterém právě jsme (tj. píšeme-li program v OPL, hledalo by makro zadaný text v databázi příkazů OPL; píšeme-li běžný text, hledalo by v databázi adres)...
4. Ani OPL není poslední krok
KMac zkušeným programátorům nabízí ještě další možnost: nemusíme zůstat u OPL, ale makra můžeme psát přímo v jazyce C. Zde však nejsme omezeni pouze na odesílání příkazů a "kláves" aplikacím prostřednictvím KMacu; objektová podstata EPOCu (operačního systému počítačů PSION) nabízí daleko elegantnější řešení.
Než si jej popíšeme podrobně, musíme na chviličku odbočit a napsat několik slov o objektech pro čtenáře, kteří o nich buď nevědí nic, nebo o nich mají jen mlhavé představy z pseudoobjektových prostředí typu C++ nebo Object PASCALu. Aplikace v objektovém prostředí není lineárním kódem, reprezentovaným hlavním programem, který volá jednotlivé procedury. Namísto toho je aplikace sítí objektů - samostatných jednotek, které spolu navzájem komunikují. Komunikace probíhá prostřednictvím zpráv; zpráva je "balíček", obsahující identifikaci zprávy (v EPOCu je to prostě číslo) a její případně parametry. Chce-li pak jeden objekt poslat zprávu druhému, zavolá určitou službu operačního systému a předá jí (a) adresu cílového objektu, (b) číslo zprávy, (c) parametry zprávy. Operační systém se již sám postará o vyhledání cílového objektu, předání zprávy a případné předání výsledku zpět původnímu objektu. Důležité je, že objekty navzájem neznají svou vnitřní strukturu; znají pouze zprávy, které je spolupracující objekt schopen zpracovat.
Dalším podstatným faktorem v tomto kontextu je to, že operační systém vždy nabízí řadu objektů, které zajišťují všechny základní služby potřebné v aplikacích. Chceme-li např. psát aplikaci, jejíž součástí je textový editor - ať již se jedná o plnohodnotný editor "přes celou obrazovku", nebo jen o jeden řádek, určený pro zápis několika znaků textu - použijeme prostě standardní systémový objekt. I v případě, že jeho služby nejsou dostatečně flexibilní pro potřeby které právě máme, nebudeme vytvářet nový editor; namísto toho využijeme dědičnosti, a vytvoříme objekt, který nabídne nové služby jako nadstavbu nad standardními službami systémového objektu. Díky tomu - a to je právě důležité - zůstanou standardní služby textového objektu zachovány i v rámci našeho rozšíření.
Vraťme se ke KMacu. Jestliže aplikace není "řetězcem bytů" jako v zastaralých neobjektových systémech, ale jen volně vázanou sítí objektů, nebrání nám nic vzít vlastní nový objekt a připojit jej (dočasně nebo stále, podle potřeby) ke kterékoli - třeba i běžící - aplikaci. Jestliže spolu objekty nekomunikují nešikovným statickým způsobem, ale posílají si skutečné objektové zprávy, není pro nový objekt žádný problém komunikovat s kterýmkoli z objektů, které v aplikaci jsou (zná-li jeho adresu). Konečně, je-li aplikace (samozřejmě ne výhradně, ale do značné míry) sestavena ze standardních systémových objektů nebo jejich dědiců, zná nový objekt i zprávy, které objekty aplikace dokáží zpracovávat, a jejich význam.
To je právě služba, kterou KMac nabízí: programátor může v jazyce C vytvořit vlastní objekt. KMac pak na požádání tento objekt připojí ke kterékoli běžící aplikaci a na chvíli mu předá řízení aplikace. Nový objekt přitom může komunikovat s již existujícími objekty - řadu jich "zná" díky tomu, že se jedná o standardní objektu EPOCu nebo jejich dědice. Poznamenejme, že sám KMac je implementován právě takto - "odeslání klávesy" není nic jiného, než připojení k aktivní aplikaci a odeslání zprávy "byla stisknuta klávesa ta a ta" jejímu objektu, který se stará o čtení klávesnice.
Ukažme si konkrétní příklad: naprogramujeme makro, které zjistí a vypíše počet slov v právě editovaném textu. Makro zapsané do souboru Kmac.kma je opět velmi jednoduché:
Kompletní kód makra je uložen v programu, konkrétně v dynamické knihovně CWORD.DYL. Ta obsahuje jediný objekt (pro ty, kdo objektový systém znají - přesně řečeno, jedinou třídu, na základě které se objekt vytvoří); KMac na základě příkazu H tento objekt načte a dynamicky jej připojí k právě aktivní aplikaci. Pak mu odešle první zprávu, kterou tento objekt dokáže zpracovávat - v našem příkladu se jedná zároveň o jedinou zprávu CWORD_COUNT. V rámci implementace této zprávy může objekt provést všechny potřebné akce. Zdrojový kód v jazyce C vypadá takto:
|
Jádrem celého programu je samozřejmě metoda cword_cword_count (která se automaticky provede při přijetí zprávy CWORD_COUNT). Metoda využívá několika standardních faktů, které platí pro standardní systémové objekty EPOCu (a samozřejmě i pro jejich příkadné dědice): globální proměnná DatApp1 obsahuje odkaz na objekt právě aktivního editoru; jeho jednotlivé (a opět standardní) podobjekty scrimg a doc rozumějí zprávám O_SI_GET_SELECT - zjištění odkud kam sahá označený text, a O_EP_SCAN_WORD - vyhledání dalšího slova... Na základě těchto znalostí (které není problém zjistit z programátorské dokumentace EPOCu) je posčítání slov už poměrně jednoduché - uvnitř označeného bloku postupně vyhledáme všechna slova a za každé přičteme jedničku. Systémová služba p_itob pak jen výsledek převede na textový řetězec, a služba wInfoMsg jej vypíše na obrazovku.
5 Omezení a problémy
Jak jsme si ukázali v předcházejícím textu, KMac dokáže téměř cokoli - na co nestačí sám, na to můžeme využít OPL nebo, v případě největších nároků, objektové programování v jazyce C. Přesto však má určitá omezení; na některá z nich se podíváme blíže.
Jistý problém je dán tím, že KMac není oficiálně podporovaná aplikace. Jak už jsme se zmínili, nepřináší to sice žádná omezení vzhledem k jeho vlastní implementaci; firma PSION však na něj nemusí brát ohled při rozšiřování svých produktů. Konkrétním příkladem může být třeba nejnovější PSION S3c, u kterého jsou kvůli ovládání podsvíceného displeje změněny kódy generované klávesou Space. Díky tomu však na něm nefunguje kombinace Control-Shift-Space (tento problém lze snadno obejít změnou tabulky kódů generovaných klávesnicí, takže např. na mém S3c funguje KMac zcela hladce; to však samozřejmě není úloha pro běžného uživatele).
Určitým omezením také je velikost operační paměti počítačů PSION a maximální počet procesů, které mohou pracovat najednou. KMac samozřejmě sám určitou paměť zabírá, a zabere také jedno místo v tabulce procesů. Vyšší míra integrace mezi jednotlivými aplikacemi kterou KMac nabízí (viz např. makro umožňující vyhledat označený text v databázi) celkem přirozeně vede ke snaze mít najednou spuštěných co nejvíce aplikací; díky tomu všemu můžeme na oba limity poměrně snadno narazit.
Trochu nepříjemné je to, že ve většině případů nemáme možnost z aplikace, ke které je KMac připojen, číst (pokud nevyužijeme "nejtěžší kalibr" připojení vlastního objektu). Pokud bychom např. chtěli makro pro zapnutí hlasitého cvakání přeprogramovat tak, aby přepínalo mezi hlasitým a tichým cvakáním, narazili bychom na problém - v rámci KMacu nemáme možnost zkistit je-li právě zapnuto cvakání tiché nebo hlasité; nevěděli bychom tedy na co přepnout. Připojením vlastního objektu samozřejmě tento problém můžeme vyřešit, to nás však nutí využít poměrně komplikovaný aparát objektového C pro vyřešení triviálního problému. Zde by zřejmě stálo za to služby KMacu trochu rozšířit (to není nemožné - David Wood dal k dispozici kompletní zdrojový text).
Asi nejvýznamnější problém je dán principem, na kterém KMac pracuje - jedná se o připojení nového objektu k objektové síti aktivní aplikace, podrobněji jsme tento mechanismus popsali v minulém odstavci. EPOC však umožňuje i běh neobjektových programů (typu "řetězec bytů"), a některé firmy vytvářející 3rd party aplikace toho bohužel využívají. KMac se pak k takové aplikaci nedokáže připojit a nemůže ji řídit. Ze stejného důvodu není možné ovládat aplikace, napsané v jazyce OPL (ten sice umožňuje odesílat zprávy jiným objektům, sám ale objektový není).
Poznamenejme, že KMac samozřejmě nabízí prostředky k ověření je-li ta která aplikace objektová (a je-li tedy možné se k ní připojit) nebo ne. Ukažme si poslední příklad - makro Hlasité cvakání, které jsme si ukázali, mělo jednu nevýhodu: na samém konci zobrazovalo informaci o tom, že byla hlasitost přepnuta, příkazem I v rámci aktivní aplikace. Pokud by aktivní aplikace byla neobjektová, nebylo by to možné, a makro by sice hlasitost přepnulo korektně, ale pak by skončilo chybou.
Můžeme namísto toho použít příkazy q a x - první z nich zjistí je-li možné se připojit k aktivní aplikaci, a druhý ukončí makro jestliže to možné není:
A nakonec, abych nezapomněl - chcete si KMac vyzkoušet na svém vlastním PSIONu? Naleznete jej např. na ftp://src.doc.ic.ac.uk (v některém adresáři jehož jméno si nepamatuji - možná 'misc'); kromě vlastního KMacu (kmac091.zip) je tam i makro pro počítání slov z minulého odstavce (cword.zip) a pro zvídavé programátory dokonce i kompletní zdrojové texty KMacu (kmac091s.zip a lpc091s.zip).