* Erweiterungscode "JOBKEY_byt"                 * .hpr * 6.4.96

Copyright (C) 1996 h.-peter recktenwald, berlin

Sofern nicht anderslautende gegenseitig schriftlich besttigte Verein-
barungen getroffen wurden, auf die in diesem Text rsp bei Installation
der Erweiterung hingewiesen wird, ist Weitergabe der Assemblerquellen
"jobkey_asm" und "insjobkey_asm", des Codeteils "JOBKEY_byt" und des
Textes "JOBKEY_txt" nur gemeinsam, nur kostenlos und ggf. nur zusammen
mit kostenlosen Programmen gestattet.
Die Beschreibung stellt den augenblicklichen Zustand bei Betrieb im
Gert des Autors dar und gibt keine wie auch immer geartete Zusage.
Als grundlegende Ergnzung zur GF6-Samlung unterliegt die Erweiterung
den dort genannten Bedingungen der GNU-Lizensierung.

Die jeweils jngste Version ist in autorisierter Form nur ber den
SQLUC e.V. gegen einen Frderbeitrag von DM 10,- (einschlielich der
Versandkosten) erhltlich. Kontakt ggf. durch den Autor.

"SBasic" steht abgekrzt fr das "Super-Basic" des QL.

Im Text verwandte Namen und Bezeichnungen mgen rechtlich geschtzt
sein. Es steht den Inhabern solcher Rechte frei, entsprechende Hin-
weise an das Ende dieses Textes anzufgen.


Diese Systemerweiterung dient folgenden Zielen, die in der gngigen
Systemsoftware mit dort verfgbaren Mitteln nicht darstellbar sind:

1. Herkunftsermittlung einer Hotkey-Auslsung:
Bestimmbarkeit des zum Zeitpunkt der HOTKEY- oder ALTKEY-Bettigung
die Tastatur "besitzenden" Jobs. Das ist z.B. der Job, der zu diesem
Zeitpunkt eine Tastatureingabe empfangen hat, ber dessen Fenster
der Bildschirmpointer des Pointer-I.F. steht, oder der zuletzt mit
CTR/C aktiviert wurde.

2. Zuteilung einer Auslsetaste an ausgewhlte Programme:
Die Tastenauswertung kann gezielt einzelnen Jobs erlaubt oder fr
solche gesperrt werden. Bei geeigneter Programmierung in den Anwen-
dungsprogrammen lassen sich derselben Taste fr verschiedene Jobs
rsp. i/o-Consolen unterschiedliche Funktionen zuteilen.

3. Zusammen mit einem auswertenden Job ist hiermit eine von TK2 oder
HOTKEY-Erweiterung unabhngige Form der Tastaturauslsung programmier-
barer Funktionen mglich. Beispiele sind etwa der Programmabbruch im
F6-Forth-System desselben Autors, oder Ausslsung rsp. Abbruch eines
Druckauftrages in LDUMP, einem Programm zur magenauen Wiedergabe des
Bildschirminhalts mit beliebigen Matrixdruckern.


Anmerkung:
Dies ist eine berarbeitete Probeversion, sie ist nicht umfassend ge-
prft. Falls es Unregelmigkeiten damit gibt, oder eine andere Funk-
tionsweise wnschenswert erscheint, wird um Nachricht gebeten an

        h.-peter recktenwald, 12159 berlin, albestr. 21
        t. 030 8520413


Installation:

Die Erweiterung berlagert die HOTKEY/ALTKEY-Definitionen. Damit
kann die Auslsung fr jeden Tastencode gesondert vor einem aus-
gewhlten Teil im System vorhandener Jobs verborgen werden. Dies
geschieht dadurch, da nach Untersuchung der festgelegten Konstel-
lation die ggf. nicht zugelassenen Codes verworfen werden und aus
der Tastatur nicht mehr in das System gelangen.

Einzige systemabhngige Voraussetzung ist, da die Tastaturabfrage im
ltesten Poll-Interrupt-Aufruf durchgefhrt wird. Da dies in allen QL-
Varianten seit JM (ltere nicht untersucht) bis hin zum SMSQ/E 2.75
der Fall ist, wird auch knftig mit grter Sicherheit vom Vorliegen
dieser Voraussetzung auszugehen sein.

Aufgrund der Wirkungsweise ist JOBKEY unabhngig vom umgebenden
Betriebssystem, kann also ohne Rcksicht auf Version und ggf.
zustzliche Ausstattung in allen QL- und SMSQ-Varianten eingesetzt
werden. Es ist lediglich zu beachten, da danach keine andere hn-
liche Funktion in das System aufgenommen wird. Sie sollte also nur
NACH Programmen geladen werden, die in irgendeiner Form die TASTA-
TUR-Bedienung beeinflussen. Etwa ldt man bei MINERVA die landes-
bezogenen Tastatur-Programme zuerst.

Stets sicher ist es, wenn "JOBKEY_byt" als letzte Erweiterung
eingefgt wird. Dies geschieht ohne weitere Vorkehrungen in
der gewohnten Weise mit LRESPR oder entsprechenden Aufrufen.
Eine Ausnahme bildet LDUMP, das selbst eine verkrzte Form des
JOBKEY-Programms installiert, wenn jenes nicht gefunden wurde.
Danach bleiben Versuche, JOBKEY zu installieren, wirkungslos.
JOBKEY wird also ggf. VOR LDUMP geladen.

Ist vorher nicht wenigstens der Codeblock "DVS" der IO2-Sammlung
geladen worden, wird bei MGG-Systemen die Basic-Procedur (s.u.)
meist erst nach dem nchsten LOAD oder NEW aufrufbar sein.


Verwendung:

Mit der Statusangabe durch JOB_KEY oder Assembler-Routine:

Codierung einzelner Tasten:
        Job-bezogene Sperrung,
                dann Freigabe global, sofern dieselbe Taste
                keinem anderen Job mehr zugewiesen ist.
        Job-bezogene Freigabe,
                zugleich Sperrung der globalen Wirkung.

Wirksam nur fr einen ausgewhlten Job:
        Sperrung aller Tasten fr einen Job,
                dabei globale Freigabe der Tasten, die
                keinem weiteren Job mehr zugewiesen sind.
        Freigabe aller Tasten fr einen Job
                dabei zugleich Sperrung der globalen Wirkung.

Globale Wirkung bei Erhalt ggf. abweichender Job-bezogener Einstellungen
        Freigabe aller Tasten global, Sperrung nur jobweise wirksam
        Sperrung aller Tasten global, Freigabe nur jobweise wirksam

Auswertung durch das Betriebssystem:

Wenn eine Job-bezogene Tabelle existiert, hat diese Vorrang gegenber
den globalen Angaben. Eine entsprechende Tabelle wird automatisch mit
der ersten Tasten-Freigabe oder -Sperrung fr einen Job eingerichtet.
Sie verschwindet ebenso automatisch, wenn der zugehrige Job aufgegeben
wird. Kann im Verlaufe der Auswertung der aktuelle Job oder seine Code-
Auswahltabelle nicht eindeutig bestimmt werden, gilt globale Codierung.


Programmierung von HOTKEY-Definitionen:

Die Einstellungen knnen aus Assemblerprogrammen vorgenommen werden,
wo dann weitere Daten lesbar sind, die in den betr. Programmen gezielt
Job-bezogene Aktionen ermglichen. In einer Hotkey-Aktionsroutine ist
es damit mglich, den auslsenden Job zu ermitteln (dessen ID wird in
einem Datenblock bereitgestellt), und festzustellen, ob es sich um eine
gewhnliche Eingabe handelte, oder ob zu diesem Zeitpunkt das Pointer-
I.F. die Kontrolle bernommen hatte. Ein besonderes Signal weist ggf.
darauf hin, da die Herkunft nicht eindeutig zu bestimmen war.

Mehr hierzu am Schlu und im Beispielassembly "insjobkey_asm".


SBasic:

Es ist eine SBasic-Procedur angegeben, mit der Sperrung und Freigabe
gesteuert werden knnen:
        JOB_KEY [ zeichencode [, schaltflag [, jobnummer ]]]

Tastenzuweisung:
        zeichencode     (Vorgabe -1)
        -1 alle Tasten, mit Codeangabe einer einzelnen Taste
Schaltzustand:
        schaltflag      (Vorgabe 0)
        0 fr die Freigabe, -1 fr die Sperrung.
Jobreferenz:
        jobnummer       (Vorgabe -1)
        -1 global, positive Zahl entweder einfache Jobnummer
        oder ganze Job-ID.

Fehlen smtliche Parameter, bewirken o.a. Vorgabewerte die globale
Freigabe aller Tastencodes. Dies ist zugleich der Zustand beim Ein-
richten der Ereiterung, nachden sie mit z.B. LRESPR geladen wurde.


Beispiele:

Jobspezifische Codierung bleibt unberhrt:
        KEY_JOB  -1, 0,-1
                alle global gltig
        KEY_JOB  -1,-1,-1
                alle global ungltig
        KEY_JOB "A", 0,-1
                ALT/"A"  global gltig
        KEY_JOB "A",-1,-1
                ALT/"A"  global ungltig

Globale Freigabe nur, wenn der Code keinem weiteren Job zugewiesen ist:
        KEY_JOB  -1, 0,job
                alle nur fr {job} gltig,      global gesperrt
        KEY_JOB  -1,-1,job
                alle nur fr {job} ungltig,    global s.o.
        KEY_JOB "A", 0,job
                ALT/"A" nur fr {job} gltig,   global gesperrt
        KEY_JOB "A",-1,job
                ALT/"A" nur fr {job} ungltig, global s.o.

        JOB_KEY
entsprechend
        JOB_KEY -1,0,-1
stellt den Einschaltzustand her, wo alle Tasten global freigegeben
sind. Abweichend davon bleibt die evtl. zuvor vorgenommene Sperrung
einzelner oder auch aller Tasten fr ausgewhlte Jobs erhalten.

Alle Tasten werden global gesperrt, d.h. nur fr ausgewhlte Jobs
freigegeben, durch
        JOB_KEY -1,-1,-1

        JOB_KEY -1,-1,0
Alle Tasten fr Job 0 sperren.

        JOB_KEY CODE("A"),0,0
Im Job Null die Taste ALT/"A" freigeben.

        JOB_KEY CODE("."),0,HEX("10001")
Taste ALT/"." fr den Job mit der Identifikationszahl 65537 frei-
geben. Dasselbe mit Angabe der einfachen Jobnummer:
        JOB_KEY CODE("."),0,1

Weil es in einer Multitasking-Umgebung grundstzlich keine Totzeit
gibt, whrend der etwa die Ausfhrungsdauer eines Teilprogramms be-
langlos wre, empfiehlt es sich, nur dort, wo es wirklich sinnvoll
ist, eine Job-bezogen Codierung einzurichten, da die Ausfhrungszeit
mit jeder weiteren Tabelle zunimmt. Weil die Auswertung im 20ms-Takt
durch einen Poll-Interrupt geschieht und mit der systemeigenen Tasta-
turauswertung synchron geht, wird damit whrend der Tastatureingabe
die Leistung des gesamten Systems beeinflut.
Andererseits kann aber auch durch die Einrichtung einer aktiven JOB-
KEY-Tabelle eine wesentliche Programmbeschleunigung eintreten, wenn
damit erfolglose Suchdurchgnge der HOTKEY-Erweiterung einzusparen
sind, da jene dort uerst zeitraubend ausgefhrt werden.


* Progammierungshinweise

In Assemblerprogrammen stehen fr die erweiterte Hotkey-Funktionalitt
einige Hilfsaufrufe zur Verfgung. Um diese zu erreichen, mu zunchst
die Codebasis ermittelt werden. Diese ist mit einer Interruptroutine
verknpft und ber die Systemliste fr 'polled' Interrupts auffindbar.
Das beigefgte Assembler-Beispiel "insjobkey_asm" enthlt die zur autar-
ken Verwendung in beliebigen anderen Programmen erforderlichen Routinen.

Grundlage zur Adressierung sind folgende Variable rsp. Pointer im Code
der vollstndig zum Ram copierten Interrupt-Routine (die Erweiterung
ist damit Rom-tauglich):

polblk  dc.w *-polnk    ptr in erste verkettungsposition
psrce   dc.b 0          herkunftsflag bei gltigem tastencode
pchar   dc.b 0          gelesenes zeichen
pkeyq   dc.l 0          i/o-queue oder job-id des tastaturbesitzers
pasci   dc.w -1,-1      reserviert fr ein besonderes programm
klkys   dc.b '%LKY'
poll    equ *           einsprung in die interruptroutine

Bezogen auf den Ort <POLNK> als zentralem Verkettungspointer stehen
im Codeblock ein paar Hilfsdaten, die den Arbeitsablauf beschleunigen:
whnd  dc.l 0            handleradresse fr SCR- und CON-kanle
pifd  dc.w -4           0 bei vorhandenem Pointer-I.F.
      dc.w 0            abstand der im PIF erweiterten parametertabelle
;                       gegenber der standarddefinition

Im Anschlu daran finden sich jeweils auf ihre eigene Adresse bezogene
Pointer in folgende Hilfsroutinen:
       dc.w *-newky     (neuen) code einreihen/ (alten) code freigeben
       dc.w *-jobfind   jobid prfem, tabelle suchen/einrichten
       dc.w *-jobnew    jobtabelle einrichten
       dc.w *-joblink   jobbezogene tabelle suchen
       dc.w *-jobtid    jobnummer/-id prfen
       dc.w *-kyfind    anzapfinterrupt suchen
       dc.w *-baslink   gesamte codeverwaltung
pkylnk dc.w *-keylink   vollstndige tastendefinition
backl  dc.l -1          backlink basis, anfangs -1,
;                       sonst ptr auf <polnk> der vorgngertabelle.
polnd ; ende des fixierten codeblocks

Die weiteren Posten einschlielich der o.g. <backl>-Position werden
jedem Job-bezogenen und dem globalen Datenblock gesondert zugeteilt.
Die globale Tabelle schliet sich unmittelbar an den zum Ram copierten
Codeteil mit der Interrupt-Routine an und liefert so auch die Grundlage
zur Adressierung obiger Pointer:
POLNK  dc.l -1          -1 vor der initiierung,
;                       spter adresse der jeweils nchsten tabelle
poljb equ *+0           -1 global, sonst
;                       job-id des jobs, dem die tabelle zugeordnet ist
poltb equ *+4           256 bytes tastenflags
;                       je -1 gesperrt oder 0 fr gltigen ALT/char
tabnd equ *+260         tabellenende,
;                       ende des job-bezogenen oder globalen datenblocks

Verkettung der Datenblcke:

Struktur eines Blocks
        [ bk(n) | ls(n) ] [ job ] [ 256 flags ]
bk(n) zeigt auf Position ls(n-1) und ist -1 beim 'ltesten' Rckwrts-
pointer (im Codeblock), ls(n) zeigt auf Position ls(n+1) rsp ist -1 im
'jngsten' Datenblock.

Damit ist die Anordnung im Speicher:
        ROM-tauglicher Codeblock, dessen Position bk(-1) mit -1 markiert
        RAM: Basisblock enthlt die Interruptroutine zur Bearbeitung der
             ankommenden Tastencodes. An dessen Ende folgt der globale
             Datenblock mit der Verkettungsbasis.
        RAM: Job-bezogene Datenblcke mit Rckwrtspointer bk(nn), Vor-
             wrtspointer ls(nn), Besitzerjob-ID und den Freigabeflags.

Die gesamte Verkettung:

Ein Eintrag der verketteten Liste SV_PLIST zeigt zur Interruptroutine
  [ qdos-link ] [ AUFRUFadresse ]
Vor der gesuchten Aufrufadresse findet sich eine Markierung
  [ daten ] [ marke ] [ AUFRUF ... ][ daten ]
Wurde bei "marke" die JOBKEY-Marke "%LKY" gefunden, so gelten die o.g.
Positionen
  [ ABSTAND.w ][flag.b][taste.b][tastaturjob.l][xx.l][marke][ AUFRUF.. ]...
Von der Adresse der Position [abstand] zieht man deren Inhalt.w ab
und erhlt die "lastlink"-Adresse der globalen Tabelle. Dort stehen
  [backlink][ LASTLINK ][tabellenbesitzer = -1][256 global geltende codes]
Auf der in "backlink" verzeichneten Adresse findet sich das virtuelle
"lastlink" des Basis-Codeblocks. Dort ist als letzter Posten BACKLINK
besetzt, das mit -1 den Hinweis auf seine Lage im Basisblock enthlt.
Von dort an nach niedrigen Adressen findet sich die Liste negativer
Abstnde zu ihrer jeweils eigenen Position, die auf die verschiedenen
Hilfsroutinen zeigen.


Die Speicherblcke werden beim Einrichten dem zugehrigen Job zugeteilt
und verschwinden dadurch automatisch zugleich mit dessen Aufgabe. Davor
nimmt ein im Verlauf der Speicherfreigabe vom Betriebssystem aufgerufe-
nes Teilprogramm die Justage der Verkettung wie folgt vor:

Freigabe des ersten (nicht-globalen) Posten:
        [bk0 | ls0 ][ bk1 | ls1 ][ bk2 | ls2 ] .. [ bk(n) | -1 ]
        [bk0 | ls1 ]             [ bk1 | ls2 ] .. [ bk(n) | -1 ]
des letzten Posten:
        [bk0 | ls0] [bk1 | ls1] .. [bk(n-1) |ls(n-1)] [bk(n) | -1 ]
        [bk0 | ls0] [bk1 | ls1] .. [bk(n-1) | -1 ]
allgemein:
        .. [bk(m-2) | ls(m-2)] [bk(m-1)|ls(m-1)] [bk(m)  | ls(m)] ..
        .. [bk(m-2) | ls(m-1)]                   [bk(m-1)| ls(m)] ..
bk0|ls0 bezeichnen den globalen Block, der nicht aufgegeben werden kann.


Mit dem Wissen um obengenannte Datenstruktur lassen sich nun alle Daten
und Hilfsaufrufe erreichen. Dafr mu zunchst mit einer vom Anwender
bereitzustellenden Routine die Basisadresse ermittelt werden:

Das hier vorgeschlagene <kyfind> ist in jeder Situation aufrufbar und
weitgehend sicher gegen mgliche Fehler auch bei verdorbenem Speicher.
    D0 > 0 liefert die Adresse <pkeyq> der Codebasis
    D0 < 0 oder = 0 signalisiert, da die "JOBKEY"-Erweiterung
           nicht installiert ist oder ihre Adresse verdorben wurde.
    Bei Rckkehr entsprechen die Processorflags dem Wert in D0.
* REIN: nix
* RAUS: d0 -7:link fehlt  sonst negativ: adresse verdorben  >0:queueptr
* NDERT: d0 sonstnix
m setstr d1/d2/a0/a2
kyfind  movem.l [m],-(sp)
        moveq   #0,d0           mt.inf
        trap    #1              sysvari holen
        move.l  $3c(a0),a0      sv.plist
        moveq   #-7,d0          err.nf vorbereiten
fkypol  move.l  (a0),d1         erster poll-int.
        beq.s   keypol          ? gefunden
        bmi.s   tkyret          ? adresse verdorben
        move.l  d1,a0           sichern
        ror.b   #1,d1           geradzahligkeit prfen
        bcc.s   fkypol          ? weitersuchen
        bra.s   tkyret          - adressenfehler
keypol  addq.l  #4,a0
        move.l  (a0),d1         ptr zum aufruf
        move.l  d1,a2           sichern
        asr.l   #1,d1           prfen
        bls.s   fkyret          ? 0 oder ungerade ist faul
        bmi.s   tkyret          ? negativ auch
        cmp.l   #'%LKY',-(a2)   marke
        bne.s   fkyret          ? fehlt
        moveq   #-(poll-pkeyq),d0 auf <pkeyq> einstellen
        add.l   (a0),d0         ptr ermitteln
        ble.s   fkyret          ? 0 oder negativ ist mll
        ror.l   #1,d0           bei ungeradem wert
        bmi.s   tkyret          ? ret 'mi' und d0 negativ
        rol.l   #1,d0           gltige adresse wiederherstellen
fkyret  tst.l   d0
tkyret  movem.l (sp)+,[m]
        rts

Ausgehend von D0 knnen nun Programme mit den bereits bewerteten Codes
aus der Tastatur arbeiten, die ber die oben notierten Abstnde zu D0
erreichbar sind:
<pchar> hlt den Code der zuletzt bettigten (ALT-)Taste bereit
<psrce> gibt den Quellentyp an:
         0      ungltig, dann Bit #31 der Job-ID gesetzt (s.u.).
                Der ankommende Tastencode wird verworfen, ist aber
                in <pchar> durch z.B. einen anderen Job noch lesbar.
        -1      globale Freigabe hatte Vorrang
        -2      Job-Bezug eindeutig
        -3      eindeutig, aber bernahme des Bildschirms durch das PIF
        -4      Zuordnung unklar
<pkeyq> -1      globale Codierung gilt,
        job     Job-bezogene Codierung,
        job     ID mit gesetztem Bit #31 bei ungltigem ALT-Key.
In den hier relevanten Fllen steht in <pkeyq> die Job-ID des Tastaten-
auslsers rsp -1, wenn dieser nicht eindeutig bestimmbar war oder die
globale Tabelle gilt. Andere negative Werte signalisieren ungltige
Tastencodes. Fr ein spezielles Programm wird die i/o-Queue eingetragen,
daher der Label-Name. Die Queue-Adresse steht dort stets auch bei ungl-
tigem Tastencode, der nicht mit ALT zusammen gelesen wurde.

Zur Adressierung der Hilfsaufrufe ermittelt man die Basisadresse der
Tabellenverkettung an der Position <polnk> rsp <backl>:
* REIN: d0 adresse <pkeyq>
* RAUS: d0 0 oder fehler   a0 Adresse <backl> im Codeblock
        move.w  #polblk-pkeyq,a0
        add.l   d0,a0
        sub.w   (a0),a0
        move.l  -(a0),a0 erster backptr zeigt in den code
        moveq   #-1,d0
        sub.l   -(a0),d0

Von der Position <polnk> des Codeblocks ausgehend lassen sich nun die
Adressen der verschiedenen Hilfsaufrufe ermitteln, wie sie oben ver-
zeichnet sind. Ein exemplarischer Verlauf ist dann etwa folgender:

1. D0:=<pkeyq> in selbstdefinierter Routine <kyfind> ermitteln.
2. Daten bereitstellen
        d0.l <pkeyq>
        d1.l Tastencode
        d2.w Zustandsflag 0:Freigabe -1:Sperrung
        d4.l Jobnummer oder vollstndige QDOS-Job-ID
2. <keylink> aufrufen - die Adresse holt man z.B. mit Hilfe der nach
   o.a. Muster bestimmten Position <backl> nach A0 mit
        sub.w   -(a0),a0
        jmp     (a0)
Der Aufruf <keylink> verndert die Register d0-d6 und a0-a5.

Diese Routine erledigt smtliche erforderlichen Aktionen, auch die
Einrichtung eines evtl. noch nicht vorhandenen Job-bezogenen Daten-
blocks. Sie darf darum nur dann bei gesperrten Interrupts oder aus
einer Routine im Supervisor-Modus des Processors durchlaufen werden,
wenn der betr. Datenblock bereits existiert. Widrigenfalls bricht
der Aufruf sicherheitshalber mit Fehlercode -19 (err.ni) ab, sonst
entspricht die Fehlerrckgabe in D0 den QDOS-Konventionen.

<keylink> erfat definierenden Aktionen. Die o.a. weiteren Pointer
zeigen in Teilaufrufe dazu und erlauben Einstellungen, die nur in
besonderen Fllen von Nutzen sind. Nheres ist dem kommentierten
Asssemblertext zu entnehmen.


Anfragen und Korrespondenz zum Programm bitte an
        h.-peter recktenwald, 12159 berlin, albestr. 21
        t. 030 8520413 (Q)
        (uhrzeit egal, notfalls nachricht hinterlassen,
        (wenn's fiept evtl. fax in betrieb - versuchen;
        (kann auch QTERM3 sein, dann einfach schreiben.


 eof 
