Gli script di Jaws 11. Le serie di Script e il nuovo Aiuto in Linea.

Programmiamoli da Soli!

Facciamo lavorare Jaws per noi.

Lo scopo del nostro lavoro con gli script di Jaws è, come detto più volte, semplificarci le PERSONALI attività quotidiane al computer. In questo capitolo, ed in quelli che seguiranno, faremo in modo che sia Jaws a lavorare per noi, o meglio, che faccia per noi la parte più ripetitiva del nostro lavoro.

In particolare, ora esamineremo come far sì che Jaws inserisca, da dentro all’Editor di Script, delle serie di copie dello stesso script base, da noi realizzato, modificandoci di volta in volta solo il suffisso numerico. Questi gruppi di script, i cui nomi saranno dunque diversi solo per l’ultima cifra che li contraddistingue, in questo capitolo andranno solo dall’uno al nove, ma più avanti avranno suffissi di numero anche maggiore.

La nascita di script in serie, che useremo pressoché in ogni occasione da qui alla fine del nostro viaggio negli script di Jaws, ci porterà poi a modificare il sistema che avevamo approntato per creare un aiuto in linea. Esso, per non appesantire troppo le informazioni inviate al Visualizzatore Virtuale, dovrà essere in grado di riconoscere se uno script appartiene ad una serie e, in tal caso, dovrà indicarne solo i dati riassuntivi.

Coglieremo poi l’occasione per inserire in questa versione le funzionalità definitive del nostro aiuto in linea, che ci consentirà di avere informazioni di contesto anche in altre procedure da realizzare. Per fare ciò, dovremo per forza anticipare sia alcuni aspetti di carattere generale, sia alcuni dettagli, che riguarderanno il resto del lavoro da svolgere.

Prima, però, ci dedichiamo al consueto aggiornamento dei nostri file esterni.

Esercizio 11.1.1. Aggiornare il file Personale delle Costanti.


A9 = "\T", ; carattere Tab, Ascii 9
CONTROL_R = "Control+R", ; combinazione tasti omologa
CHIAVE_SCRIPT = "Script ", ; parola per identificare l’intestazione di uno script
APERTA_TONDA = "(", ; carattere omonimo
SEZIONI = "Sezioni", ; termine omonimo
TASTI = "Tasti", ; termine omonimo
MAX_VOCI = 99, ; numero predefinito per le voci in una finestra di elaborazione
TASTIERA = 1, ; indica l’input tramite la tastiera del pc
JSS = ".JSS", ; estensione omonima
SEGNO_PIU = "+", ; carattere omonimo
BACKSPACE = "BackSpace", ; tasto omonimo
CONTROL_E = "Control+E", ; combinazione omologa
TAB = "Tab", ; tasto omonimo
BARRA_SPAZIO = "Space", ; l’equivalente inglese del tasto omonimo
ALT_D = "Alt+D", ; combinazione omologa
INVIO = "Enter", ; tasto inglese omonimo
DELETE = "Delete", ; tasto omonimo
RITARDA = 4, ; decimi di secondo per i quali sospendere il flusso del codice
CONTROL_S ="Control+S", ; combinazione tasti omologa
AMPERSAND = "&", ; termine inglese per il carattere
ALT = "Alt", ; termine omonimo
ALT_O = "Alt+O", ; combinazione tasti omologa
EDITOR_ITA = "editor di script", ; nome italiano dell’applicazione omonima
EDITOR_ENU = "script editor", ; nome inglese dell’applicazione omonima
PERSONALI = "ScriptsPersonali", ; sezione dei dati sugli script a gestione personale

Esercizio 11.1.2. Aggiornare il file Personale delle Variabili Globali.


string gsTitolo, ; titolo della finestra di dialogo
String gsEtichette, ; elenco di etichette
String gsTermine, ; termine usato per formattare il titolo delle schermate
int gnCampo, ; fase attiva della procedura

Esercizio 11.1.3. Aggiornare il file Personale dei Messaggi.


; nessuno script rilevato sul cursore
@hlpNoScript
Nessuno script alla posizione del cursore
@@
; nessuno script rilevato sul cursore - versione corta
@hlpNoScript_corto
Nessuno script.
@@
; quattro termini affiancati
@msg4
%1%2%3%4
@@
; conferma generica
@msgConferma
Confermate?
@@
; Nessun nome di file individuato
@hlpNoNomeFile
Nessun NomeFile Rilevato dal documento corrente.
@@
; Nessun nome di file individuato - versione corta
@hlpNoNomeFile_corto
Nessun NomeFile.
@@
; nessun suffisso numerico nel nome
@hlpNoSuffisso
Nessun suffisso numerico in %1.
@@
; nessun suffisso numerico nel nome - versione corta
@hlpNoSuffisso_corto
Nessun suffisso.
@@
; Titolo per sezione o tasti di attivazione mancanti in uno script
@ttlNoTasti
Sezione o tasti mancanti per lo script %1
@@
; messaggio su sezione o tasti di attivazione mancanti in uno script
@msgNoTasti
Continuare senza aggiungerli?
@@
; scelta ultimo suffisso numerico per la serie di script
@msgUltimoScript
Scegliere il suffisso per l’ultimo script della serie
@@
; titolo per conferma creazione script
@ttlCreaScript
Lo script %1 sarà copiato fino al suffisso %2.
@@
; conferma di scelta generica
@msgConfermaScelta
Confermate la scelta?
@@
; comando per simulare la pressione di un tasto
@lstPremiTasto
TypeKey ("%1")
@@
; titolo delle informazioni sulle finestre di dialogo
@ttlInfoDialogo
Informazioni sulla finestra di dialogo:
%1.
Pulsanti disponibili:
@@
; due termini separati da un segno Più
@msg2Piu
%1+%2
@@
; due termini separati da uno spazio
@msg2Spazi
%1 %2
@@
; riga del buffer utente per il comando Annulla
@lstEscape
Annulla. Esc, oppure Alt+A.
@@
; nome reale degli script a gestione personale
@msgPersonalScript
EseguePersonali%1
@@
; base per informazioni sulle serie di tasti personali
@hlpInfoSerie
%1 da %3 a %4. %2%3-%4.
@@
; assenza di un aiuto in linea per la finestra corrente
@hlpNoInLinea
Nessun aiuto in linea per la finestra corrente.
@@
; assenza di un aiuto in linea per la finestra corrente - versione corta
@hlpNoInLinea_corto
Nessun aiuto.
@@

***

Le serie di script.

L’obiettivo della prima serie di script, di cui inizieremo tra poco a costruire gli elementi, sarà completare una funzionalità che avevamo già predisposto nel capitolo scorso, quella dei contrassegni numerati. Nel dettaglio, realizzeremo dapprima nove script, che registrano ciascuno una diversa posizione identificata tramite un numero, ed altri nove, i quali si occupano di tornarci in seguito.

In questa occasione, avendo noi ben diciotto script da realizzare, ci basterà crearne in realtà soltanto due, uno per quelli che registrano la posizione, ed uno per quelli che vi tornano. Una volta realizzati i due prototipi, basterà posizionarci sopra ad uno di questi e, attivando il nostro apposito script di duplicazione, sarà poi sufficiente indicare solo il numero di copie che vogliamo Jaws realizzi per noi.

Non si tratta, in ogni caso, di un semplice copia ed incolla, magari un po’ evoluto, bensì di una vera e propria simulazione di quanto faremmo noi se dovessimo impostare gli script a mano. In particolare, saranno replicate, per ciascuno script, l’apertura e la compilazione dell’apposita schermata con la procedura guidata. Verrà riservato alle istruzioni nel codice soltanto il salvataggio dei tasti di attivazione, con il loro abbinamento ai singoli script, tramite la compilazione del file tasti predefinito

Default.JKM.

Come al solito, le informazioni più di dettaglio su script e funzioni, sia quelle che andremo a realizzare, sia quelle integrate di Jaws, saranno inserite nella documentazione proposta assieme a ciascun elemento di codice. Eventuali argomenti particolari, invece, saranno trattati con delle note a sé stanti, che introdurranno i blocchi di codice che li riguardano.

Inizieremo, appunto, da una presentazione dei prossimi tre elementi, che costituiscono il primo gruppo di funzioni correlate.

Rilevare il codice dai file script.

Lo scopo di questo primo blocco di quattro funzioni è quello espresso nel titolo: da dentro all’Editor di Script, con il cursore in un punto qualsiasi all’interno dello script da duplicare, rilevare il codice dello script, controllando che, appunto, si sia effettivamente posizionati dentro ad un elemento di codice valido, e di che tipo si tratti.

In realtà, la quasi totalità di questo compito è svolta dall’ultima funzione di questo blocco, mentre le altre tre sono funzioni accessorie a quella principale. Vale tuttavia la pena di citare la terza di queste, che serve ad estrarre la parte iniziale o finale di una stringa, a partire da, oppure fino a, un carattere o una stringa da utilizzare come separatore.

Si tratta di uno strumento molto utile, che gioca su valori predefiniti e parametri opzionali, i quali consentono di modificare una stringa in un modo ben preciso indicando come parametro anche il solo testo da elaborare. Proprio per la sua versatilità, questa funzione sarà spesso chiamata dalle funzioni e dagli script che incontreremo da qui in avanti.

Esercizio 11.2.2. La funzione ToglieTab.

FileScript.

Default.JSS

Nome.

ToglieTab

Descrizione.

Rimuove gli eventuali caratteri di Tabulazione, Ascii 9, dalla stringa passata come parametro.

Ritorni.

Di tipo String. Il testo ripulito da eventuali caratteri di tabulazione.

Parametri.
  1. sTesto. La stringa da elaborare. Di tipo String.
Novità.
  1. La costante
    A9
    , che corrisponde al carattere Tabulazione, Ascii 9.
Note.
  1. Questa funzione, come altre più avanti, nasce per semplificare la sostituzione di caratteri ricorrenti, così come quello di Tabulazione, che si deve effettuare con una funzione in cui il nome è piuttosto lungo già da solo.

Codice.


String Function ToglieTab (string sTesto)
Return StringReplaceSubstrings (sTesto, A9, NULLO); restituisce il testo senza caratteri di tabulazione
EndFunction

Collaudo.

  1. Come spesso capita nel caso di funzioni, il collaudo dell’elemento di codice va rinviato al primo script utile. Per questo blocco, e per i prossimi, sarà chiesto soltanto di porre come opzionali i parametri che eventualmente lo prevedessero.

Esercizio 11.2.3. La funzione ImpostaPipe.

FileScript.

Default.JSS

Nome.

ImpostaPipe

Descrizione.

Qualora non sia specificato alcun carattere o stringa come separatore, viene impostato a tale scopo il carattere Pipe, Ascii 124.

Ritorni.

Di tipo Void. Nessuno.

Parametri.
  1. sSeparatore. Per Riferimento. L’eventuale carattere o stringa impostati come separatore. Di tipo String.
Note.
  1. Tale funzione serve a ridurre il codice che gestisce l’impostazione di un separatore predefinito, operazione che si ripeterà più volte nelle funzioni da qui in avanti.

Codice.


Void Function ImpostaPipe (string ByRef sSeparatore)
If !sSeparatore Then; se non si è indicato alcun carattere o stringa di separazione,
Let sSeparatore = PIPE; imposta il carattere Ascii 124
EndIf; fine controllo caratteri
EndFunction

Esercizio 11.2.4. La funzione TroncaTesto.

FileScript.

Default.JSS

Nome.

TroncaTesto

Descrizione.

Mantiene, o elimina, la parte iniziale, oppure quella finale, del testo specificato, fino alla prima, o al numero indicato, di occorrenze di un carattere di separazione. Questo separatore sarà il carattere o la stringa specificata, oppure il carattere Pipe, qualora non si specifichi nulla.

Ritorni.

Di tipo String. La stringa, da mantenere oppure rimuovere, fino , oppure a partire da, agli eventuali caratteri di separazione specificati.

Parametri.
  1. sTesto. Il testo da elaborare. Di tipo String.
  2. sSeparatore. Eventuale Carattere o stringa di separazione delle parti del testo; se non specificata, sarà utilizzato il carattere Pipe, Ascii 124. Di tipo String. Parametro Opzionale.
  3. iValore. Eventuale numero delle occorrenze da mantenere o rimuovere; se non specificato, sarà elaborata la prima parte iniziale del testo, altrimenti, un valore positivo indica di contare le occorrenze dall’inizio, mentre un numero negativo indica di farlo dalla fine del testo. Di tipo Int. Parametro Opzionale.
  4. iRimuovi. Se valorizzato con TRUE, indica di rimuovere le porzioni di testo indicate; se non specificato, o con valore FALSE, le mantiene. Di tipo Int. Parametro Opzionale.
Novità.
  1. La nostra funzione
    ImpostaPipe ().
  2. La funzione integrata
    Abs
    , (Assoluto); Restituisce il valore assoluto di un numero, senza un eventuale segno negativo. Nel suo unico parametro va indicato il valore numerico da controllare.
  3. La funzione nativa
    StringReverse
    , (DatoTestualeInvertito); Restituisce una stringa invertendone l’ordine dei caratteri, da destra a sinistra, indicata come suo unico parametro.
  4. Le funzioni integrate
    StringChopLeft
    , (TagliaDatoTestualeASinistra) , e
    StringChopRight
    , (TagliaDatoTestualeADestra), che rimuovono una parte del testo passato come parametro, nell’ordine a sinistra e a destra; hanno entrambe due parametri:
    • Il dato testuale da modificare;
    • Il numero di caratteri da rimuovere a partire, nel primo caso, dall’inizio della stringa, e nel secondo, dalla sua fine.
Fasi.
  1. La prima struttura di controllo interrompe subito il flusso, qualora non sia stato specificato alcun testo come primo parametro.
  2. Se invece un testo c’è, dapprima la nostra funzione
    ImpostaPipe ()
    controlla l’impostazione di un separatore, poi sono raccolti gli eventuali dati relativi al numero di ripetizioni del separatore da trovare, e la direzione della ricerca, utilizzando anche le funzioni native
    Abs ()
    e
    StringReverse ().
  3. Dopo altre impostazioni preliminari, si entra nel ciclo di ricerca della stringa di separazione; qui, quando il separatore viene trovato, ma non ancora nel numero di occorrenze richieste, viene aggiornato il punto d’inizio della ricerca nel testo; se e quando si trova il numero di occorrenze desiderato, viene interrotto il ciclo e restituita la parte di testo fino al punto individuato, oppure a partire da quel punto sino alla fine del testo, a seconda che si sia indicato di conservare o di tagliare la stringa così ottenuta; per eliminare una parte del testo, saranno utilizzate le funzioni native
    StringChopLeft ()
    e
    StringChopRight ().
  4. Se si esce dal ciclo, senza quindi aver trovato il carattere separatore, o non averlo fatto nel numero di occorrenze desiderato, viene restituito il testo nella forma originale.
Note.
  1. In pratica, come accennato nella premessa, se si indica un testo nel primo parametro, il solo obbligatorio, il testo inserito sarà restituito a partire dall’inizio sino all’eventuale primo carattere Pipe.
  2. Se, oltre ad indicare un testo come primo parametro, si indica un carattere o una stringa come separatore, il testo sarà troncato a partire da tale separatore.
  3. Se, oltre ai primi due, nel terzo parametro si indica un valore positivo, il testo immesso sarà mantenuto fino all’occorrenza del separatore con il numero indicato, partendo dall’inizio del testo; se invece il valore indicato è preceduto da un segno Meno, il conteggio delle occorrenze a cui interrompere il testo partirà dalla fine.
  4. Ancora, se si pone un qualsiasi valore positivo come quarto parametro, il testo indicato nel primo sarà tagliato, anziché mantenuto; se come terzo parametro si indica un qualsiasi valore, sarà rimosso fino al numero indicato di occorrenze del separatore attivo, o dall’inizio o dalla fine sulla base del fatto che tale valore sia positivo o negativo; Se invece non lo si indica, sarà troncata solo la prima parte del testo, fino al separatore indicato.

Codice.


String Function TroncaTesto (string sTesto, string sSeparatore, int iValore, int iRimuovi)
Var
Int i, ; contatore del ciclo
String sOrigine, ; copia del testo da cercare
Int iCerca, ; numero di occorrenze da trovare
Int iPartenza, ; punto della stringa da cui iniziare a cercare
Int iLungo, ; lunghezza della stringa di origine
Int iRipeti, ; contatore delle ripetizioni
Int iPosiz, ; punto d’interruzione della stringa
String sDato; stringa temporanea
ImpostaPipe (sSeparatore); se non lo si è specificato, imposta come separatore il carattere Pipe
If iValore >= FALSE Then; se la ricerca va fatta a partire dall’inizio,
If iValore < 1 Then; se non si sono specificati parametri, o il valore Zero,
Let iCerca = PRIMA; imposta di cercare la prima occorrenza
Else; altrimenti, se un valore positivo è specificato,
Let iCerca = iValore; lo imposta come numero di occorrenze da trovare
EndIf; fine controllo occorrenze
Let sOrigine = sTesto; duplica la stringa per la ricerca
Else; Altrimenti, se la ricerca va fatta dalla fine,
Let iCerca = Abs (iValore); porta il parametro negativo al valore assoluto
Let sOrigine = StringReverse (sTesto); inverte la stringa dove cercare
Let sSeparatore = StringReverse (sSeparatore); inverte anche la stringa cercata
EndIf; fine controllo direzione ricerca
Let iPartenza = 1; inizializza la colonna da cui partire
Let iLungo = StringLength (sOrigine); lunghezza della stringa in cui cercare
While !iPosiz && iRipeti < iCerca; continua finché i caratteri non siano stati trovati, o quando si raggiunge il numero necessario di ripetizioni
Let iRipeti = iRipeti + 1; aggiorna il contatore delle ripetizioni
Let sDato = SubString (sOrigine, iPartenza, iLungo - (iPartenza -1)); crea il segmento in cui cercare
Let iPosiz = StringContains (sDato, sSeparatore); cerca la stringa indicata
If iPosiz ; se è la stringa è stata trovata,
&& iRipeti < iCerca Then; ma ancora non si è giunti al numero di occorrenze richiesto,
Let iPartenza = iPartenza + iPosiz; sposta di un’unità in avanti il punto d’inizio del successivo segmento da controllare,
Let iPosiz = FALSE; ed azzera il valore
EndIf; fine controllo ritrovamento
EndWhile; fine ciclo ricerca
If iPosiz Then; se il ritrovamento è avvenuto,
If !iRimuovi Then; se la parte è da mantenere,
; Calcola la lunghezza della stringa da ottenere, sommando i valori rilevati
Let iPosiz = (iPosiz + iPartenza) - 2
If iValore >= FALSE Then; se la ricerca era dall’inizio,
Return StringLeft (sTesto, iPosiz); preleva la stringa da sinistra
Else; altrimenti, se era dalla fine,
Return StringRight (sTesto, iPosiz); la preleva da destra
EndIf; fine controllo porzione mantenuta
Else; altrimenti, se la parte è da eliminare,
; calcola la lunghezza della stringa da rimuovere, aggiungendo anche i caratteri del separatore
Let iPosiz = ((iPosiz + iPartenza) - 2) + StringLength (sSeparatore)
If iValore >= FALSE Then; se la ricerca era dall’inizio,
Return StringChopLeft (sTesto, iPosiz); rimuove la stringa a sinistra
Else; altrimenti, se era dalla fine,
Return StringChopRight (sTesto, iPosiz); rimuove la stringa da destra
EndIf; fine controllo porzione eliminata
EndIf; fine controllo modifica
Else; altrimenti, se il separatore non è stato trovato,
Return sTesto; restituisce la stringa originale invariata
EndIf; fine controllo esito
EndFunction

Collaudo.

  1. Poiché come detto la funzione ha solo il primo come parametro obbligatorio, si invita ad aprire subito il file documentazione,
    Default.JSD
    , per porre la riga con la dicitura
    :Optional
    , appena prima del secondo parametro dei quattro presenti nella scheda della funzione.

Esercizio 11.2.5. La funzione CaricaScript.

FileScript.

Default.JSS

Nome.

CaricaScript

Descrizione.

Raccoglie il codice di uno script, memorizzandone tutte le istruzioni, come opzione predefinita, oppure prelevando soltanto il contenuto senza la riga d’intestazione ed il comando di chiusura.

Ritorni.

Di tipo Int. TRUE per un corretto caricamento dei dati, FALSE per un risultato nullo.

Parametri.
  1. sNome. Per Riferimento. Il nome dello script. Di tipo String.
  2. sCodice. Per Riferimento. Il codice dell’elemento, completo o limitato al solo contenuto tra l’intestazione ed il comando di chiusura. Di tipo String.
  3. iCompleto. Se con valore positivo, indica di memorizzare tutto il contenuto del codice; se senza valore, o non specificato, rileva solo il contenuto tra l’intestazione ed il comando di chiusura. Di tipo Int. Parametro Opzionale.
Novità.
  1. Le nostre funzioni
    ToglieTab ()
    e
    TroncaTesto ().
  2. Le funzioni integrate
    PriorCharacter
    , (CaratterePrecedente), e
    NextCharacter
    , (CarattereSuccessivo), le quali spostano il cursore di un carattere, rispettivamente, a sinistra o a destra; entrambe sono senza parametri.
  3. Le costanti
    CONTROL_R
    e
    APERTA_TONDA
    , che corrispondono alle rispettive combinazioni tasti e carattere.
  4. La costante
    CHIAVE_SCRIPT
    , la quale corrisponde alla singola parola chiave che identifica questi elementi di codice, e che quindi non può essere usata come termine a sé stante in quanto già utilizzata da Jaws.
Fasi.
  1. La prima struttura di controllo verifica di essere nell’Editor di Script, altrimenti il flusso viene interrotto.
  2. Dopo aver spento la sintesi, si utilizza il comando
    "Seleziona script"
    del menu modifica, tramite il comando rapido della costante
    "CONTROL_R"
    , per selezionare tutto il codice, intestazione e comando di chiusura compresi, ripulendo tale testo selezionato grazie alla nostra funzione
    ToglieTab ()
    , servendosi anche di
    PriorCharacter ()
    e
    NextCharacter ()
    , ed infine salvandolo in una variabile.
  3. Una seconda struttura di controllo, qualora il testo rilevato non sia uno script valido, interrompe il flusso restituendo un risultato nullo. Altrimenti, il nome ed il codice dello script sono trasmessi alla funzione chiamante per riferimento, eventualmente servendosi della nostra
    TroncaTesto ()
    , e comunque restituendo un esito positivo. In entrambi i casi, prima di uscire dalla funzione, viene riattivata la sintesi.
Note.
  1. Questa è la funzione principale del blocco, di cui si accennava nella premessa. Il codice dello script viene qui raccolto usando la funzione
    TroncaTesto ()
    per rimuovere l’intestazione e il comando di chiusura dal codice, poiché sarà la procedura guidata di creazione, attivata dal nostro script, a predisporre l’inizio e la fine di ciascun elemento di codice inserito.

Codice.


Int Function CaricaScript (string ByRef sNome, string ByRef sCodice, int iCompleto)
If !SiamoNellaFinestra (MANAGER) Then; se non ci si trova nell’Editor di Script,
PronunciaEsegue (); ripete i tasti premuti, leggendo il nome dello script,
Return FALSE; e restituisce un risultato nullo, interrompendo il flusso
EndIf; fine controllo finestra
Var
String sTesto, ; eventuale contenuto dello script
Int iLungo, ; lunghezza della parola iniziale degli script
Int iPosiz, ; posizione di fine nome dello script
Int i; contatore del ciclo
SpeechOff (); spegne la sintesi
TypeKey (CONTROL_R); attiva la selezione di un eventuale script sul cursore
Pause ()
; salva l’eventuale contenuto selezionato, cui sono rimossi spazi in eccesso e tabulazioni
Let sTesto = TagliaSpazi (ToglieTab (GetSelectedText ()))
PriorCharacter (); si sposta di un carattere indietro, casomai per togliere la selezione
NextCharacter (); ritorna alla posizione iniziale
Let iLungo = StringLength (CHIAVE_SCRIPT); salva la lunghezza della parola d’inizio script
If !sTesto ; se nessun contenuto è stato rilevato,
|| StringLeft (sTesto, iLungo) != CHIAVE_SCRIPT Then; oppure, se non si tratta di uno script,
SpeechOn (); riattiva la sintesi
SayMessage (OT_ERROR, hlpNoScript, hlpNoScript_corto); legge l’avviso,
Return FALSE; e restituisce un risultato nullo, interrompendo il flusso
EndIf; fine controllo script
Let iPosiz = StringContains (sTesto, APERTA_TONDA); trova la fine del nome dello script
Let iLungo = iLungo + 1; aggiorna il dato di partenza
Let sNome = TagliaSpazi (SubString (sTesto, iLungo, iPosiz - iLungo)); estrae la stringa
If !iCompleto Then; se il contenuto deve escludere la prima e l’ultima riga di codice,
; rimuove le estremità individuate con il carattere di Nuova Linea, Ascii 10
Let sCodice = TroncaTesto (TroncaTesto (sTesto, LF, 1, TRUE), LF, -1, TRUE)
Else; altrimenti,
Let sCodice = sTesto; lascia la forma rilevata
EndIf; fine controllo estrazione codice
SpeechOn (); riattiva la sintesi
Return TRUE; restituisce l’esito positivo
EndFunction

Collaudo.

  1. Anche qui, l’ultimo parametro opzionale consiglia di andare subito nel file di documentazione del file Predefinito, cercare la scheda della funzione
    "CaricaScript"
    , e porre la speciale dicitura tra il secondo ed il terzo parametro.

Trovare la sezione dove sono registrati i tasti di attivazione.

Quando si crea uno script, come detto fin dai primi capitoli, i tasti di attivazione sono registrati nel file tasti relativo al file script corrente. Il suo nome è lo stesso del file script, solo con estensione
.JKM
, ma la sezione di questo file, dove saranno presenti tali combinazioni una volta trascritte, può essere diversa da caso a caso.

Nella normale gestione degli script, quella realizzata da dentro l’Editor di Jaws, non è necessario conoscere in quale delle sezioni siano stati salvati i suoi tasti di attivazione. Se quello che noi stiamo creando è uno script di base per le duplicazioni, invece, la procedura di copia ha di norma la necessità di conoscere il nome di tale sezione, per potervi aggiungere direttamente tramite il codice anche i tasti di attivazione degli ulteriori script creati da Jaws al nostro posto. Questa, infatti, se da un lato è l’unica fase della procedura guidata di creazione script che non siamo riusciti a replicare, dall’altro è anche la più semplice da simulare, in quanto basterà servirsi delle normali funzioni di scrittura dati sui file
INI
utilizzate sinora.

Per conoscere il nome della sezione dove Jaws ha trascritto la combinazione da noi immessa nel prototipo, dovremo compiere un cammino al contrario, partendo dalle due informazioni in nostro possesso. Così, saremo costretti a rilevare dapprima tutte le sezioni presenti nel file tasti abbinato all’applicativo corrente, e cercare in quale di esse Jaws ha registrato la combinazione tasti da noi scelta, servendoci delle prossime quattro funzioni.

Tra queste, vanno evidenziate quelle che rilevano le sezioni e le chiavi dai file in formato
INI
. Così come avevamo fatto nell’ottavo capitolo con l’Aiuto in linea, esse hanno la particolarità di avere il suffisso
Ex
, (Ulteriore), con quindi un parametro in più per indicare la cartella dove prelevare i dati.

In questo caso, useremo il contenuto della costante numerica
"UTENTE"
, di valore 6, che serve appunto ad essere certi di elaborare dati solo dalla cartella con le Impostazioni per l’Utente.

Esercizio 11.2.7. La funzione ImpostaConfigurazione.

FileScript.

Default.JSS

Nome.

ImpostaConfigurazione

Descrizione.

Qualora il nome di archivio indicato non abbia un’estensione, vi aggiunge quella predefinita dei file configurazione.

Ritorni.

Di tipo String. Il nome di archivio eventualmente completato dall’estensione predefinita.

Parametri.
  1. sArchivio. Per Riferimento. Il nome dell’archivio da controllare. Di tipo String.
Note.
  1. La funzione nasce solo per semplificare il codice, in questo e nei successivi casi in cui la struttura di controllo che la compone sarà utilizzata dalle funzioni chiamanti.

Codice.


String Function ImpostaConfigurazione (string ByRef sArchivio)
If PathRemoveExtension (sArchivio) == sArchivio Then; se il nome indicato è privo d’estensione,
Let sArchivio = sArchivio + JCF; aggiunge l’estensione predefinita dei file di configurazione
EndIf; fine controllo estensione
EndFunction

Esercizio 11.2.8. La funzione SezioniUtente.

FileScript.

Default.JSS

Nome.

SezioniUtente

Descrizione.

Rileva le sezioni presenti nel file di configurazione indicato, all’interno della cartella con le Impostazioni per l’Utente.

Ritorni.

Di tipo String. L’elenco delle sezioni rilevate nel file di configurazione specificato.

Parametri.
  1. sArchivio. Il nome del file di configurazione da elaborare; qualora in tale nome non sia specificata un’estensione, viene aggiunta quella predefinita JCF. Di tipo String.
Novità.
  1. La funzione integrata
    IniReadSectionNamesEx
    , (LeggiNomiSezioniFileIniUlteriore); Rileva le sezioni del file di configurazione specificato, limitandone la ricerca ad un determinato percorso. Ha due parametri:
    • Un codice numerico che indica in quale cartella cercare il file da cui leggere i dati;
    • Il nome dell’archivio da elaborare.

Codice.


String Function SezioniUtente (string sArchivio)
ImpostaConfigurazione (sArchivio); se non presente, aggiunge l’estensione dei file configurazione
; Dalle impostazioni per l’Utente, restituisce le sezioni dell’archivio indicato
Return IniReadSectionNamesEx (UTENTE, sArchivio)
EndFunction

Esercizio 11.2.9. La funzione ChiaviUtente.

FileScript.

Default.JSS

Nome.

ChiaviUtente

Descrizione.

Rileva le chiavi nella sezione e archivio specificati, all’interno della cartella delle Impostazioni per l’Utente.

Ritorni.

Di tipo String. L’elenco delle chiavi lette nel file di configurazione specificato.

Parametri.
  1. sArchivio. Il nome del file di configurazione da elaborare; qualora in tale nome non sia specificata un’estensione, viene aggiunta quella predefinita JCF. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.

Codice.


String Function ChiaviUtente (string sArchivio, string sSezione)
ImpostaConfigurazione (sArchivio); se non presente, aggiunge l’estensione dei file configurazione
; Dalle impostazioni per l’Utente, restituisce le chiavi di archivio e sezione indicati
Return IniReadSectionKeysEx (sSezione, UTENTE, sArchivio)
EndFunction

Esercizio 11.2.10. La funzione LeggeUtente.

FileScript.

Default.JSS

Nome.

LeggeUtente

Descrizione.

Rileva il dato della chiave indicata, nella sezione e archivio specificati all’interno della cartella delle Impostazioni per l’Utente.

Ritorni.

Di tipo String. Il dato letto dall’archivio specificato.

Parametri.
  1. sArchivio. Il nome del file di configurazione da elaborare; qualora in tale nome non sia specificata un’estensione, viene aggiunta l’estensione predefinita JCF. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del dato da leggere. Di tipo String.

Codice.


String Function LeggeUtente (string sArchivio, string sSezione, string sChiave)
ImpostaConfigurazione (sArchivio); se non presente, aggiunge l’estensione dei file configurazione
; Dalle impostazioni per l’Utente, restituisce il dato di archivio, e sezione e chiave indicati
Return IniReadStringEx (sSezione, sChiave, NULLO, UTENTE, sArchivio)
EndFunction

Esercizio 11.2.11. La funzione TrovaSezione.

FileScript.

Default.JSS

Nome.

TrovaSezione

Descrizione.

Verifica nell’archivio tasti specificato la presenza di uno script, trasmettendo per riferimento sia la sezione dove è stata eventualmente trovata l’assegnazione, sia i tasti di attivazione ad esso abbinati.

Ritorni.

Di tipo Int. TRUE per i dati trovati, FALSE per il mancato rilevamento.

Parametri.
  1. sFile. L’archivio in cui cercare lo script. Di tipo String.
  2. sNome. Il nome dello script da cercare. Di tipo String.
  3. sSezione. Per Riferimento. La sezione dove è stato rilevato lo script. Di tipo String.
  4. sTasti. Per Riferimento. La combinazione tasti che attiva lo script indicato. Di tipo String.
Novità.
  1. Le nostre funzioni
    SezioniUtente ()
    e
    ChiaviUtente ().
Fasi.
  1. Tramite la nostra funzione
    SezioniUtente ()
    , sono raccolti i dati per far partire un ciclo che scorra le sezioni del file tasti specificato.
  2. Grazie all’altra funzione,
    ChiaviUtente ()
    , si può avviare un secondo ciclo che invece scorra i tasti, o le loro combinazioni, che fungono da chiavi nelle singole sezioni.
  3. Una volta trovati i tasti che sono abbinati al nome di script da cercare, i cicli s’interrompono e viene restituito il nome della sezione.
  4. Se i cicli si concludono senza aver trovato lo script cercato, viene restituita una stringa vuota.

Codice.


Int Function TrovaSezione (string sFile, string sNome, ; intestazione con i primi due parametri
string ByRef sSezione, string ByRef sTasti); seconda riga con gli altri due
Var
string sSezioni, ; elenco delle sezioni
Int j, ; contatore del ciclo primario
Int k, ; contatore del secondo ciclo
String sChiavi, ; elenco delle chiavi della sezione
String sDato; dato testuale
Let sSezioni = SezioniUtente (sFile); raccoglie le sezioni dall’archivio
For j = 1 To StringSegmentCount (sSezioni, PIPE); scorre le sezioni rilevate
Let sSezione = StringSegment (sSezioni, PIPE, j); estrae la singola sezione da elaborare
Let sChiavi = ChiaviUtente (sFile, sSezione); legge i dati per l’Utente
For k = 1 To StringSegmentCount (sChiavi, PIPE); scorre le chiavi rilevate
Let sTasti = StringSegment (sChiavi, PIPE, k); estrae la combinazione tasti che funge da chiave
Let sDato = LeggeUtente (sFile, sSezione, sTasti); legge il dato
If sDato == sNome Then; se il dato estratto ed il nome di script coincidono,
Return TRUE; restituisce l’esito positivo
EndIf; fine controllo confronto
EndFor; fine ciclo chiavi
EndFor; fine ciclo sezioni
Return FALSE; se il flusso non si è interrotto prima, restituisce un risultato nullo
EndFunction

L’uso dei record.

Prima di affrontare il prossimo blocco di funzioni, è necessario introdurre un argomento molto importante, che caratterizzerà gran parte del nostro lavoro da qui in avanti: la gestione di informazioni diverse in una stessa riga di dati.

Per farne subito un esempio concreto, riproponiamo di seguito un elenco di saluti, separati tra loro dal carattere Pipe, che avevamo incontrato nel quinto e nell’ottavo capitolo:


Buongiorno|Buon pomeriggio|Buonasera|Buonanotte

Questo breve elenco, composto da quattro parti coincidenti con gli altrettanti diversi saluti, lo avevamo analizzato sinora come tale, prima estraendo un termine da leggere, poi cercandone uno per averne restituita la posizione nell’elenco stesso. Se questo stesso elenco lo scrivessimo in un file in formato
INI
, dovremmo utilizzare il seguente schema:


[Sezione]
Chiave=Buongiorno|Buon pomeriggio|Buonasera|Buonanotte

In questa forma, il nostro elenco diventerebbe quello che sinora abbiamo chiamato
"dato"
, in quanto contenuto letto tramite le apposite funzioni. Abbiamo però già analizzato che in esso le informazioni inserite non sono soltanto una, bensì quattro, ciascuna utilizzabile in modo a sé stante.

Nell’attesa di poter affrontare questa distinzione sotto altri aspetti, per il momento basterà dire che l’intera riga, composta dalle due parti separate dal segno Uguale, la potremmo rinominare in questo modo:


Record=Campo1|Campo2|Campo3|Campo4

Quindi, tutta la riga la possiamo chiamare
record
, e ad ogni singolo dato, potremo dare il nome convenzionale di
campo
, che in questo esempio abbiamo diversificato aggiungendo a ciascuno un suffisso numerico progressivo.

Da qui in avanti, quando avremo bisogno di scrivere o leggere il contenuto dei vari dati, eventualmente inseriti in un’unica stringa composta da più segmenti, cercheremo di usare questa terminologia,
"record"
e
"campo"
, anche per poi capire meglio cosa si sta facendo.

In modo estensivo, con
"record"
potremo intendere anche solo una stringa costituita da più
"campi"
divisi da un carattere, o una stringa, di separazione, a prescindere che essa provenga da un file in formato
INI
. In qualche caso tali speciali stringhe, continueremo a chiamarle
"elenchi"
, specialmente quando si tratterà di voci da proporre nelle finestre di dialogo.

Il prossimo blocco di elementi di codice sarà composto da cinque funzioni, seguite dallo script di creazione e dai due prototipi che realizzeremo per duplicarli. Di queste funzioni, la prima costituisce un altro strumento molto efficace, tramite il quale potremo creare o aggiornare dei
"record"
, sostituendo o aggiungendo dei campi al loro interno. Anche in questo caso, così come è stato per la funzione
TroncaTesto ()
, sfrutteremo i parametri opzionali per poter indicare il tipo di lavoro da svolgere.

L’altra funzione da citare è quella che si occupa soltanto di spostare il cursore da un controllo all’altro, e da un un campo d’inserimento all’altro, dentro alla procedura guidata di creazione script. La sua esistenza è dovuta, oltre al risparmio di codice, anche al tentativo di contribuire ad una maggiore visibilità dello stesso, sulla base del notevole numero di chiamate della funzione necessarie allo script.

Esercizio 11.2.13. La funzione CambiaCampo.

FileScript.

Default.JSS

Nome.

CambiaCampo

Descrizione.

Sovrascrive, Aggiunge o rimuove un campo di un record, sulla base dei parametri specificati.

Ritorni.

Di tipo String. Il record con i campi eventualmente rimasti dopo le modifiche.

Parametri.
  1. sRecord. Il record cui sottoporre l’azione di modifica. Di tipo String.
  2. sTermine. L’eventuale contenuto del campo da rimuovere, qualora non si specifichino altri parametri, oppure da aggiungere o integrare al record indicato nel primo parametro, sulla base del valore numerico specificato nel parametro successivo; se si desidera eliminare dal record iniziale il campo di cui si indica un numero progressivo, in questo secondo parametro deve essere posto un testo vuoto. Di tipo String.
  3. iPosiz. Nel caso in cui il secondo parametro contenga un qualche dato testuale, il valore qui inserito indica il campo del record che va aggiornato con tale termine; sempre nel caso precedente, se si immette un valore -1, oppure la costante ULTIMA, il termine indicato sarà comunque aggiunto in coda al record; nel caso in cui il termine sia vuoto, ed il valore sia a -1, sarà aggiunto il separatore impostato ; ancora, se il secondo parametro è vuoto, un valore positivo indica il campo che deve essere eliminato; infine, se non lo si specifica, il termine presente nel secondo parametro sarà cercato per rimuovere il campo che lo contiene nel record. Di tipo Int. Parametro Opzionale.
  4. sSeparatore. L’eventuale carattere, o stringa, che serve da separatore dei campi nel record; se non viene specificato, sarà usato il carattere Pipe, Ascii 124. Di tipo String. Parametro Opzionale.
Fasi.
  1. In una prima ed articolata struttura di controllo, con vari livelli annidati al suo interno, si elaborano i parametri specificati; durante questi controlli, qualora i parametri non siano stati immessi in numero sufficiente, il flusso viene interrotto.
  2. Nell’altra struttura di controllo della funzione, si restituisce il record eventualmente modificato, sulla base di quanto rilevato in precedenza.
  3. Se la seconda struttura non intercetta il flusso, il record viene restituito nella forma originale oppure con il solo termine indicato come secondo parametro a costituire un record.
Note.
  1. Se si indica il numero minimo di parametri, dal record posto come primo parametro sarà rimosso il campo il cui contenuto corrisponde al testo specificato come secondo parametro.
  2. Se invece si specificano il primo parametro, con il record, ed il terzo, quello con il valore numerico, sarà rimosso dal record il campo corrispondente al numero progressivo indicato; in questa soluzione, è possibile indicare solo valori positivi, poiché numeri preceduti dal segno Meno sarebbero ignorati, lasciando così invariato il record.
  3. Se invece sono specificati tutti e tre i primi parametri, il contenuto del secondo andrà a sostituire il campo nel record con il numero progressivo indicato nel terzo parametro; qualora il valore sia negativo, ad esempio -1, oppure sia superiore al numero di campi presenti nel record, il contenuto del secondo parametro sarà aggiunto alla fine del record.
  4. A prescindere dal fatto che si specifichino solo due, o tutti tre, i primi parametri, il carattere o la stringa posta come quarto parametro sarà utilizzata come separatore dei campi nel record, in alternativa al carattere Pipe, Ascii 124, che viene usato quando tale parametro non viene specificato.

Codice.


String Function CambiaCampo (string sRecord, string sTermine, int iPosiz, string sSeparatore)
Var
Int iLungo, ; lunghezza del separatore
Int iCampi, ; numero dei campi rilevati nel record
String sDato; dato temporaneo
ImpostaPipe (sSeparatore); se non lo si è specificato, imposta come separatore il carattere Pipe
Let iLungo = StringLength (sSeparatore); conta i caratteri del separatore
Let iCampi = StringSegmentCount (sRecord, sSeparatore); conta i campi presenti nel record
If !iPosiz Then; se il numero dell’campo da elaborare non è specificato,
If !sTermine Then; se non lo è nemmeno la stringa da cercare,
Return sRecord; restituisce la forma originale
Else; altrimenti, se la stringa è indicata,
Let iPosiz = StringSegmentIndex (sRecord, sSeparatore, sTermine, TRUE); cerca la stringa nei campi
If !iPosiz Then; se l’campo non è stato individuato,
Return sRecord; restituisce la forma originale
EndIf; fine controllo campo da rimuovere
EndIf; fine controllo valore numerico
ElIf sTermine Then; se è presente anche il dato da integrare nei campi,
If iPosiz < FALSE Then; se si è specificato di aggiungere il termine in coda,
Let iPosiz = StringSegmentCount (sRecord, sSeparatore) + 1; aggiunge un’unità al numero di campi esistenti
EndIf; fine controllo valore negativo
If iPosiz == PRIMA Then; se il campo da sostituire è il primo,
If iCampi <= PRIMA Then; se anche i campi non sono superiori ad uno,
Let sDato = sTermine; duplica solo la stringa specificata
Else; altrimenti, se ve ne sono più d’uno,
Let sDato = sTermine + sSeparatore; aggiunge il separatore in coda alla stringa specificata
EndIf; fine controllo numero campi
Else; altrimenti, se il dato è da inserire o aggiungere in coda,
Let sDato = sSeparatore + sTermine; aggiunge il separatore all’inizio
EndIf; fine controllo aggiunta separatore
EndIf; fine controllo posizione campo
If !sTermine ; se nessun termine è stato specificato,
&& iPosiz == ULTIMA Then; ed è stato indicato di aggiungere un campo alla fine,
Return FormatString (msg2, sRecord, sSeparatore); aggiunge il solo separatore senza dato
ElIf iCampi > PRIMA ; se i dati sono più d’uno,
|| iPosiz > PRIMA Then; oppure, se il campo da elaborare è maggiore di uno,
If iPosiz == PRIMA Then; se quello da aggiornare o rimuovere è il primo campo,
; compone il dato, casomai aggiungendovi il resto del record dal secondo campo in poi
Return FormatString (msg2, sDato, TroncaTesto (sRecord, sSeparatore, PRIMA, TRUE))
ElIf iCampi == iPosiz Then; se il numero di dati e quello dell’campo da elaborare sono uguali,
; compone il dato tagliando dal record l’ultimo campo, e casomai accodandovi il dato
Return FormatString (msg2, TroncaTesto (sRecord, sSeparatore, ULTIMA, TRUE), sDato);
ElIf iPosiz > iCampi Then; se il nuovo dato va posto dopo quelli esistenti,
; compone il dato, casomai accodandolo all’elenco attuale
Return FormatString (msg2, sRecord, sDato);
Else; altrimenti, se l’campo da sostituire si trova in mezzo ad altri campi,
; inserisce il dato tra i campi fino a quello precedente al numero da sostituire e la restante parte del record
Return FormatString (msg4, TroncaTesto (sRecord, sSeparatore, iPosiz - 1), sDato, sSeparatore, TroncaTesto (sRecord, sSeparatore, iPosiz - iCampi))
EndIf; fine controlli composizione dato
EndIf; fine aggiornamento dato
Return sDato; restituisce il termine aggiunto, o una stringa vuota
EndFunction

Collaudo.

  1. Essendoci due parametri opzionali, si invita ad aggiornarne l’impostazione dentro al file di documentazione predefinito, ponendo la speciale stringa tra il secondo e terzo parametro della scheda.

Esercizio 11.2.14. La funzione ElencoSezioni.

FileScript.

Default.JSS

Nome.

ElencoSezioni

Descrizione.

Restituisce l’elenco aggiornato delle sezioni in cui elaborare i tasti di attivazione degli script.

Ritorni.

Di tipo String. L’elenco delle sezioni da elaborare.

Parametri.
  1. sSezione. La sezione corrente del file tasti. Di tipo String. Parametro Opzionale.
Novità.
  1. La nostra funzione
    CambiaCampo ().
  2. Le costanti
    SEZIONI
    e
    TASTI
    , corrispondenti ciascuna all’omonimo termine, che servono a comporre il nome della sezione dell’archivio personale dove salvare le eventuali nuove sezioni da elaborare nei file tasti.
Fasi.
  1. Dopo aver rilevato i dati necessari, una prima struttura di controllo verifica la presenza delle sezioni registrate nel file archivio personale; se così è, queste sono aggiunte all’elenco delle sezioni predefinite, memorizzate nell’apposito messaggio.
  2. Una seconda struttura controlla che l’eventuale sezione specificata non sia già presente nell’elenco appena rilevato; se così non è, questa nuova sezione viene registrata nel file archivio personale, e si restituisce l’elenco con questa ulteriore aggiunta; se invece la sezione indicata è già presente, viene restituito l’elenco nella forma originaria.
Note.
  1. L’elenco delle sezioni predefinite in cui elaborare le assegnazioni dei file tasti è memorizzato nel messaggio
    "lstSezioniTasti"
    . Pur restando sempre la possibilità di aggiornare manualmente tale elenco, così come spiegato nell’ottavo capitolo, questa funzione serve ad integrarlo in modo automatico, aggiungendo eventuali nuove sezioni utilizzate da Jaws per salvare le nostre serie di script.

Codice.


String Function ElencoSezioni (string sSezione)
Var
String sElenco = lstSezioniTasti, ; imposta le sezioni predefinite
String sNuove = ChiaviUtente (PS_FILE, SEZIONI + TASTI); rileva le eventuali sezioni aggiornate
If sNuove Then; se sono presenti delle sezioni personalizzate,
Let sElenco = CambiaCampo (sElenco, sNuove, ULTIMA); le aggiunge all’elenco
EndIf; fine controllo elenco sezioni
If !StringSegmentIndex (sElenco, PIPE, sSezione, TRUE) Then; se la sezione non è presente,
ScriveValore (PERSONALE, SEZIONI + TASTI, sSezione, TRUE); aggiorna il dato nell’archivio,
Return CambiaCampo (sElenco, sSezione, ULTIMA); e restituisce l’elenco aggiornato
Else; altrimenti, se non vi sono variazioni,
Return sElenco; restituisce la forma registrata
EndIf; fine controllo sezione
EndFunction

Collaudo.

  1. Dopo aver correttamente compilato, segnaliamo di rendere opzionale l’unico parametro della funzione .

Esercizio 11.2.15. La funzione ElencoNumeri.

FileScript.

Default.JSS

Nome.

ElencoNumeri

Descrizione.

Crea un elenco di scelte numeriche, in forma testuale, che parte dal valore indicato e termina con quello predefinito nella variabile MAX_VOCI.

Ritorni.

Di tipo String. Un elenco di cifre in forma testuale, a partire dal valore impostato sino a quello massimo consentito.

Parametri.
  1. iPartenza. Valore da cui far partire l’elenco. Di tipo Int.
Novità.
  1. La costante
    MAX_VOCI
    , che equivale al numero 99.
Note.
  1. All’interno del ciclo, che costituisce in pratica il codice della funzione, l’utilizzo della nostra funzione
    CambiaCampo ()
    consente di costruire da zero l’elenco delle voci da visualizzare.

Codice.


String Function ElencoNumeri (int iPartenza)
Var
Int i, ; contatore del ciclo
String sElenco; stringa da restituire
For i = iPartenza + 1 To MAX_VOCI; crea un elenco di valori in forma testuale
Let sElenco = CambiaCampo (sElenco, IntToString (i), ULTIMA); aggiunge il valore del ciclo
EndFor; fine ciclo creazione elenco
Return sElenco; restituisce l’elenco di voci testuali creato
EndFunction

Collaudo.

Esercizio 11.2.16. La funzione SceltaValore.

FileScript.

Default.JSS

Nome.

SceltaValore

Descrizione.

Consente di scegliere il valore corrispondente ad una delle voci proposte nell’elenco della finestra di dialogo.

Ritorni.

Di tipo Int. Il valore scelto.

Parametri.
  1. sElenco. L’elenco delle voci di scelta. Di tipo String.
  2. sTitolo. Il titolo della finestra di dialogo. Di tipo String.
  3. iPartenza. Il numero della voce su cui ci si posiziona all’ingresso. Di tipo Int. Parametro Opzionale.
Fasi.
  1. Dopo aver comunque impostato il valore di controllo, si entra in un ciclo dove viene proposto di scegliere un valore tra quelli proposti.
  2. Se si opera una scelta, viene annullato il valore di controllo per l’uscita dal ciclo, e quindi viene restituito il valore scelto.
  3. Se invece si abbandona la scelta, viene proposta una conferma all’uscita: se la si conferma, si esce dal ciclo e viene restituito un risultato nullo, altrimenti si ritorna alla precedente finestra di scelta.
Note.
  1. Per quanto riguarda la funzione speciale di Jaws
    DlgSelectItemInList ()
    , più volte utilizzata sinora con soli tre parametri, in questa occasione ne useremo un quarto, che serve a stabilire la voce selezionata all’ingresso nella finestra di dialogo; più avanti concluderemo l’esame delle sue possibilità, illustrando anche gli ultimi due parametri facoltativi.

Codice.


Int Function SceltaValore (string sElenco, string sTitolo, int iPartenza)
Var Int iScelta; valore della scelta effettuata
If !iPartenza Then; se il valore d’ingresso non è stato indicato,
Let iPartenza = PRIMA; imposta la voce di scelta iniziale
EndIf; fine controllo voce all’ingresso
While iPartenza; ripropone la richiesta finché un valore è impostato
Let iScelta = DlgSelectItemInList (sElenco, sTitolo, FALSE, iPartenza); consente la scelta
If iScelta Then; se è stata effettuata una scelta,
Let iPartenza = FALSE; annulla il valore per l’uscita dal ciclo
Else; altrimenti, viene chiesta l’uscita dalla fase
If ChiedeConferma (ttlConfermaUscita, msgConferma) Then; se tale uscita è stata confermata,
Let iPartenza = FALSE; annulla il valore per l’uscita dal ciclo
EndIf; fine controllo conferma
EndIf; fine controllo scelta effettuata
EndWhile; fine del ciclo di scelta
Return iScelta; restituisce la scelta operata
EndFunction

Collaudo.

  1. Segnaliamo l’ultimo parametro come opzionale, invitando quindi a renderlo subito tale, modificando manualmente la scheda della funzione
    "SceltaValore"
    , nel file di documentazione predefinito.

Esercizio 11.2.17. La funzione RigaCorrente.

FileScript.

Default.JSS

Nome.

RigaCorrente

Descrizione.

Rileva il contenuto della riga in cui è posizionato il cursore, o intero, oppure dal cursore a fine riga o dall’inizio al cursore, sulla base dei valori indicati come parametro.

Ritorni.

Di tipo String. Testo della riga corrente, senza ritorni a capo o caratteri di Nuova Linea, e spazi dopo questi.

Parametri.
  1. iTipo. L’eventuale tipo di testo da prelevare: 0, per tutta la riga; 1, per la porzione dal cursore sino a fine riga; 2, per quella dal cursore fino all’inizio. Di tipo Int. Parametro Opzionale.
Novità.
  1. La funzione integrata
    GetToEndOfLine
    , (OttieniVersoFineRiga); Rileva il testo dalla posizione del cursore sino a fine riga corrente. Senza parametri.
  2. La funzione integrata
    GetFromStartOfLine
    , (OttieniDaInizioRiga); Rileva il testo dalla posizione del cursore fino all’inizio della riga corrente. Senza parametri.
Fasi.
  1. La struttura di controllo determina quale parte della riga sarà restituita, sulla base del valore eventualmente specificato come parametro, servendosi anche delle funzioni native
    GetToEndOfLine ()
    e
    GetFromStartOfLine ().
  2. Il testo viene poi restituito, dopo averne eliminato spazi inutili, caratteri di ritorno e nuova linea.

Codice.


String Function RigaCorrente (int iTipo)
Var String s; variabile temporanea
If !iTipo Then; se non si è indicato nulla, o il valore 0,
Let s = GetLine (); rileva l’intera riga
ElIf iTipo == 1 Then; se invece si è indicato il valore 1,
Let s = GetToEndOfLine (); rileva il testo dal cursore a fine riga
Else; altrimenti, se si è indicato il valore 2,
Let s = GetFromStartOfLine (); rileva il testo dal cursore sino ad inizio riga
EndIf; fine controllo tipo di testo
; restituisce il testo rilevato, senza caratteri di ritorno o nuova linea, e spazi inutili
Return TagliaSpazi (StringReplaceSubstrings (StringReplaceSubstrings (s, CR, NULLO), LF, NULLO))
EndFunction

Collaudo.

  1. Invitiamo subito a rendere opzionale l’unico parametro, andando ad aggiornare il file documentazione predefinito.

Esercizio 11.2.18. La funzione CambiaControllo.

FileScript.

Default.JSS

Nome.

CambiaControllo

Descrizione.

Consente di interagire con una finestra dotata di controlli tra i quali spostarsi, dovendo indicare un comando da premere per muoversi tra i campi, e casomai specificare anche un testo da inserire in quello attivo.

Ritorni.

Di tipo Void. Nessuno.

Parametri.
  1. sComando. Nome esteso del tasto o della combinazione di cui simulare la pressione. Di tipo String.
  2. sTesto. L’eventuale stringa da inserire nel campo in cui ci si è portati. Di tipo String. Parametro Opzionale.
Novità.
  1. La funzione integrata
    SetLastScriptKey
    , (ImpostaUltimiTastiScript); Simula la pressione dei tasti indicati, come se fossero stati gli ultimi premuti dall’utente. Come unico parametro, vanno inseriti i tasti da impostare.
  2. Le costanti numeriche
    TASTIERA
    e
    EDITABILE
    , corrispondenti ai valori 1 e 3, i quali rappresentano, nell’ordine, un numero identificativo della tastiera e il codice di tipo per i campi di editazione nelle finestre secondarie.
Fasi.
  1. Una prima struttura di controllo verifica se sia stato indicato il parametro iniziale; se così è, usa la stringa immessa per simulare la pressione dei relativi tasti, registrandoli inoltre come se fossero stati gli ultimi, in ordine di tempo , premuti sulla tastiera, tramite la funzione nativa
    SetLastScriptKey ().
  2. Nella seconda struttura di controllo, il testo eventualmente immesso come secondo parametro viene inserito alla posizione del cursore, qualora il tipo di oggetto del controllo confermi che si tratta di un campo editabile.
Note.
  1. Come si potrà notare più avanti, tale funzione può essere usata anche solo per spostarsi da un campo all’altro con il tasto Tab, così come si farebbe utilizzando i relativi comandi di Jaws; anche nel caso di un utilizzo così minimale, tuttavia, servirsi della funzione consente di utilizzare una sola riga di codice per svolgere almeno due funzioni, come detto uno spostamento al campo successivo o precedente, e l’attesa tramite l’istruzione
    Pause ()
    , che in questo tipo di procedura con molti comandi in sequenza è assolutamente indispensabile.
  2. Formalmente sarebbe solo il secondo parametro ad essere opzionale, in quanto l’utilizzo più logico prevede comunque il comando per spostarsi al controllo desiderato, e poi casomai inserirvi un testo nel caso in cui ne esistano le condizioni; le due strutture di controllo indipendenti tra loro consentono, tuttavia, di poter anche non specificare un comando di spostamento, usando la funzione anche solo per poter immettere del testo sfruttando il controllo del campo editabile.

Codice.


Void Function CambiaControllo (string sComando, string sTesto)
If sComando Then; se un comando è stato specificato,
TypeKey (sComando, TASTIERA); simula l’esecuzione di una combinazione dalla tastiera del pc
Pause ()
SetLastScriptKey (sComando); imposta il comando specificato come l’ultimo digitato
EndIf; fine controllo comando
If sTesto Then; se un testo è stato specificato,
TypeString (sTesto); simula l’immissione di una stringa testuale
Pause ()
EndIf; fine controllo testo
EndFunction

Collaudo.

  1. Anche in questo caso, dopo aver compilato, si consiglia di indicare subito il secondo come parametro opzionale , andando alla scheda della funzione ed inserendo la dicitura apposita tra i due parametri nel file
    Default.JSD.

Esercizio 11.2.19. Lo script CreaSerie.

FileScript.

Default.JSS

Nome.

CreaSerie

Sommario.

Crea una serie di script da quello corrente.

Descrizione.

Carica nome e contenuto dello script su cui è posizionato il cursore, per crearne le copie indicate, aggiornandone il suffisso numerico, ed aggiungendo i relativi tasti nell’apposito file.

TastiAttivazione.

Shift+Control+Windows+P

Novità.
  1. Le nostre funzioni
    CaricaScript (),
    TrovaSezione (),
    ElencoSezioni (),
    ElencoNumeri (),
    SceltaValore (),
    RigaCorrente ()
    e
    CambiaControllo ().
  2. La funzione integrata
    GetScriptDescription
    , (OttieniDescrizioneScript); Rileva la descrizione dello script indicato, immessa nell’omonimo campo durante la procedura di creazione.
  3. La funzione integrata
    IniWriteStringEx
    , (ScriviDatoTestualeFileIniUlteriore); Scrive un dato testuale in un archivio in formato
    "INI"
    , collocandolo nella cartella indicata dal valore identificativo specificato. Ha cinque parametri obbligatori:
    • La sezione del file INI da trattare.
    • La chiave del dato.
    • Il dato testuale da scrivere.
    • Un codice numerico che indica in quale cartella cercare il file.
    • L’archivio da elaborare.
  4. La funzione integrata
    StopSpeech
    , (FermaSintesi), che zittisce la sintesi vocale, così come si farebbe premendo ripetutamente il tasto
    Control
    . Senza parametri.
  5. Le costanti
    SEGNO_PIU,
    BACKSPACE,
    CONTROL_E,
    TAB,
    BARRA_SPAZIO,
    ALT_D,
    INVIO,
    DELETE
    e
    CONTROL_S
    , che equivalgono alle rispettive combinazioni di tasti o caratteri.
  6. La costante
    JSS
    , che rappresenta l’omonima estensione, incluso il carattere Punto iniziale.
  7. La costante numerica
    Ritarda
    , equivalente al valore 4, che indica i decimi di secondo per i quali ritardare il flusso del codice.
Fasi.
  1. Si effettuano in sequenza tre controlli dove il flusso prosegue solo in caso positivo, nell’ordine controllando se: sia stato rilevato il nome del file script corrente; si siano raccolti il nome ed il codice dello script, tramite la nostra funzione
    CaricaScript ()
    ; il nome dello script abbia un suffisso numerico.
  2. Nel quarto controllo si verifica se sia stato rilevato il nome della sezione in cui trascrivere le combinazioni che attivano gli script, grazie alla nostra
    TrovaSezione ()
    ;poiché questo dato non è sempre indispensabile, anche se tale nome non sia stato rilevato, viene comunque fornita la possibilità di continuare ugualmente la procedura. Se invece i tasti sono stati rilevati, si crea l’elenco delle sezioni da elaborare, grazie alla nostra funzione
    ElencoSezioni ().
  3. Se il flusso continua, viene quindi proposta la scelta del numero di copie da fare dello script interessato, utilizzando le nostre funzioni
    ElencoNumeri ()
    e
    SceltaValore ()
    . Se si interrompe la scelta, viene proposta una conferma dell’abbandono; altrimenti, si propone la conferma del numero di copie impostate, la quale è a sua volta da confermare o annullare.
  4. Se si conferma la scelta effettuata, la procedura copia lo script sul cursore, si porta a fine file ed inizia ad eseguire la duplicazione degli script, copiando il codice ed aggiornando solo il suffisso numerico; in questa fase, tra le altre, sono chiamate anche le nostre funzioni
    RigaCorrente ()
    e
    CambiaControllo ()
    , nonché quelle integrate
    GetScriptDescription ()
    e
    IniWriteStringEx ().
Note.
  1. Se l’apposita sezione del file tasti è stata rilevata, durante la trascrizione del codice saranno riportati anche i tasti di attivazione degli script.

Codice.


Script CreaSerie ()
Var
String sNomeFile, ; nome del file script
String sFileTasti, ; nome del file tasti
String sNome, ; nome dello script da duplicare
String sCodice, ; contenuto dello script
String sCifra, ; suffisso numerico al nome
String sNomeBase, ; nome script senza suffisso
String sSezione, ; sezione del file tasti dove è registrata la combinazione abbinata allo script
String sTasti, ; stringa base per le combinazioni da formattare
Int iNoTasti, ; indicatore della scrittura dei tasti di attivazione
Int iPartenza, ; valore iniziale
String sElenco, ; lista di valori testuali
String sTitolo, ; titolo nelle finestre di dialogo
Int iScelta, ; valore della scelta effettuata
Int iValore, ; variabile temporanea
String sNuovo, ; nome aggiornato dello script
String sNuoviTasti, ; nuova combinazione tasti
String sSommario, ; stringa base per il Sommario
String sDescrizione, ; stringa base per la Descrizione
Int i; contatore del ciclo
If !DocumentoCorrente (sNomeFile) Then; se non si è rilevato il nome del file script,
SayMessage (OT_ERROR, hlpNoNomeFile, hlpNoNomeFile_corto); avvisa dell’errore,
Return; e interrompe il flusso
EndIf; fine controllo nome file
Let sFileTasti = StringReplaceSubstrings (sNomeFile, JSS, JKM); compone il nome del file tasti
If !CaricaScript (sNome, sCodice) Then; se non si è rilevato alcuno script sul cursore,
Return; interrompe il flusso
EndIf; fine controllo presenza script
Let sCifra = EstraeNumero (sNomeBase, sNome); individua e toglie dal nome dello script l’eventuale suffisso numerico
If !sCifra Then; se nel nome non è presente alcun suffisso,
SayFormattedMessage (OT_ERROR, hlpNoSuffisso, hlpNoSuffisso_corto, sNome); formatta l’avviso,
Return; e interrompe il flusso
EndIf; fine controllo suffisso
If !TrovaSezione (sFileTasti, sNome, sSezione, sTasti) Then; se i dati non sono stati rilevati,
If !ChiedeConferma (FormatString (ttlNoTasti, sNome), msgNoTasti) Then; se non si vuole continuare,
Return; interrompe il flusso
EndIf; fine conferma prosecuzione
EndIf; fine controllo rilevamento dati
If sTasti Then; se i tasti di attivazione sono stati trovati,
EstraeNumero (sTasti); rimuove dalla combinazione tasti il suffisso numerico
If StringRight (sTasti, 1) != SEGNO_PIU Then; se la base dei tasti non finisce con un Più,
Let sTasti = sTasti + SEGNO_PIU; lo aggiunge
EndIf; fine controllo tasti
Let sTasti = sTasti + msg1; aggiunge il carattere segnaposto alla base per i tasti
Else; altrimenti, se non si vogliono trascrivere i tasti di attivazione,
Let iNoTasti = TRUE; annota il valore
EndIf; fine controllo presenza tasti
Let iPartenza = StringToInt (sCifra); converte la cifra testuale come valore iniziale
Let sElenco = ElencoNumeri (iPartenza); genera un elenco di valori in forma testuale
Let sTitolo = FormatString (ttlSelezione, msgUltimoScript); compone il titolo della finestra
; imposta la voce selezionata all’ingresso nella finestra di dialogo
Let iValore = StringSegmentIndex (sElenco, PIPE, IntToString (MAX_SEGNI), TRUE)
Let iScelta = SceltaValore (sElenco, sTitolo, iValore); imposta il suffisso dell’ultimo script
If !iScelta Then; se nessun valore è stato impostato,
Return; interrompe il flusso
EndIf; fine controllo scelta
Let iValore = iScelta + iPartenza; aggiunge al valore scelto quello iniziale
If !ChiedeConferma (FormatString (ttlCreaScript, sNome, iValore), msgConfermaScelta) Then; se non si è confermata la prosecuzione,
Return; interrompe il flusso
EndIf; fine controllo conferma
; compone dei messaggi base da formattare per Sommario e Descrizione degli script
Let sSommario = StringReplaceSubstrings (GetScriptSynopsis (sNome), sCifra, msg1);
Let sDescrizione = StringReplaceSubstrings (GetScriptDescription (sNome), sCifra, msg1);
For i = iPartenza + 1 To iValore; scorre gli script da duplicare
SayFormattedMessage (OT_ERROR, msg1, NULLO, i); pronuncia il numero del suffisso elaborato
SpeechOff (); spegne la sintesi
JAWSBottomOfFile (); si porta alla fine del documento
If TagliaSpazi (ToglieTab (RigaCorrente ())) Then; se la riga non è vuota,
EnterKey (); crea una nuova riga
Else; altrimenti,
CambiaControllo (BACKSPACE); cancella il carattere precedente
If TagliaSpazi (RigaCorrente ()) Then; se nemmeno ora la riga è vuota,
EnterKey (); crea una nuova riga
EndIf; fine controllo riga precedente
EndIf; fine controllo ultima riga
Let sNuovo = FormatString (msg2, sNomeBase, i); compone il nuovo nome dello script
If !iNoTasti Then; se la scrittura dei tasti di attivazione non è stata disattivata,
Let sNuoviTasti = FormatString (sTasti, i); formatta la nuova combinazione
IniWriteStringEx (sSezione, sNuoviTasti, sNuovo, UTENTE, sFileTasti); trascrive i tasti
EndIf; fine controllo scrittura tasti
Pause ()
; avvia la procedura di creazione script, e ne immette il nome aggiornato
CambiaControllo (CONTROL_E, sNuovo)
CambiaControllo (TAB); preme il tasto Tab
CambiaControllo (BARRA_SPAZIO); imposta di creare uno script
; si porta nel campo sommario, e ne immette il contenuto aggiornato
CambiaControllo (ALT_S, FormatString (sSommario, i))
; si porta al campo Descrizione, e ne aggiorna il contenuto
CambiaControllo (ALT_D, FormatString (sDescrizione, i))
; avanza di tre controlli, passando per:
CambiaControllo (TAB); il campo Categoria
CambiaControllo (TAB); il campo Assegna A
CambiaControllo (TAB); il pulsante Ok
CambiaControllo (INVIO); chiude la procedura guidata
PriorLine (); si sposta alla riga sopra
CambiaControllo (DELETE); cancella la riga vuota sul cursore
CambiaControllo (DELETE); ne cancella un’altra
Delay (RITARDA); sospende temporaneamente il flusso
MetteTesto (sCodice, FALSE); trascrive il contenuto dello script
SpeechOn (); riattiva la sintesi,
StopSpeech (); e ne resetta il buffer
EndFor; fine scorrimento script
SayMessage (OT_ERROR, msgAttesa); pronuncia un avviso
Refresh ()
TypeKey (CONTROL_S); salva e compila gli script creati
EndScript

Collaudo.

  1. Se la compilazione dello script riesce, si potrà completare il collaudo solo dopo aver realizzato gli script prototipo, quelli da duplicare. Per il momento, provate lo stesso a posizionarvi all’interno dello script appena salvato,
    CreaSerie ()
    , e premete i tasti di attivazione scelti, oppure quelli consigliati
    Shift+Control+Windows+P.
  2. Se tutto va bene, sarete avvisati che lo script sul quale siete posizionati non ha un suffisso numerico, e per questo il flusso si concluderà senza avviare la procedura di copia.

Esercizio 11.2.20. Lo script SalvaContrassegno1.

FileScript.

Default.JSS

Nome.

SalvaContrassegno1

Sommario.

Registra il contrassegno denominato 1.

Descrizione.

Chiama la funzione di gestione dati per salvare la posizione del cursore nel documento corrente, registrandola come contrassegno numero 1.

TastiAttivazione.

Control+Windows+1

Note.
  1. Uno script base, per poter essere duplicato, deve avere lo stesso suffisso numerico sia nel nome, sia nella combinazione tasti che lo attiva, il quale in questo caso è il numero 1.
  2. Come si può notare, i tasti di attivazione corrispondono, ad eccezione del suffisso numerico, alla combinazione usata per lo script
    SalvaContrassegno ()
    ,la quale se vi ricordate era
    Control+Windows+K
    . Questo per facilitare la possibilità di ricordarsi, ed associare la combinazione base,
    Control+Windows
    , proprio al salvataggio dei contrassegni.
  3. Il contenuto dello script, per questo e per quello che lo segue, è quello che abbiamo già esaminato più volte, con il solo richiamo della nostra funzione di gestione dati.

Codice.


Script SalvaContrassegno1 ()
GestisceDato (); richiama la funzione generica
EndScript

Il collaudo della creazione delle serie di script.

Se il salvataggio va a buon fine, siamo finalmente in grado di collaudare la duplicazione in serie degli script, e grazie ad essa realizzare la prima parte degli script per gestire i contrassegni numerati.

  1. posizionatevi in un punto qualsiasi del codice all’interno dello script appena salvato,
    SalvaContrassegno1 ()
    , e premete i tasti di attivazione dello script
    CreaSerie (),
    Shift+Control+Windows+P.
  2. Se tutto riesce, dovrebbe proporsi una finestra di dialogo in cui si chiede di confermare fino a che numero di suffisso lo script attuale vada duplicato. Per questo, la serie di voci numeriche partirà dal numero successivo a quello del suffisso dello script base, in questo caso il numero 2.
  3. All’ingresso il cursore sarà posizionato sulla voce col numero 9, anche se si potrebbe andare sino al limite impostato , che è 99. In ogni caso, cogliete l’occasione della voce selezionata per confermarla premendo Invio.
  4. Sarà allora proposta un’ulteriore schermata dove confermare fino a che numero sarà duplicato lo script base, partendo dal numero 1, quello dello script base, al numero 9, quello della scelta operata . Anche in questo caso, limitatevi a confermare la scelta effettuata.
  5. Se per qualche motivo voleste interrompere la procedura, sia nella prima schermata di scelta, sia nella successiva richiesta di conferma, sarà sufficiente premere il tasto Escape, o cliccare su Annulla.
  6. Nel caso in cui confermiate di andare avanti, sarà avviata la procedura di copia, con il cursore che all’inizio si sposterà al termine del file script aperto, e da lì comincerà a trascrivere il codice.
  7. L’avanzamento del lavoro sarà confermato dal numero progressivo degli script duplicati, che sarà pronunciato ad ogni inizio copia. dati i molti passaggi da compiere, ciascuno con le necessarie pause per non creare malfunzionamenti, la scrittura di ciascuna copia potrebbe impiegare anche circa un paio di secondi a script.
  8. Al termine, sarà pronunciato un messaggio di attesa, dopo del quale sarà avviato il salvataggio e la compilazione del file script. Se tutto va bene, dovreste sentire almeno il segnale acustico di riuscita, se non il messaggio di conferma.
  9. Ora, per collaudare il salvataggio dei contrassegni numerati, usate la combinazione
    Windows+FrecciaSu
    per tornare all’inizio dell’ultimo script creato,
    SalvaContrassegno9 ()
    . Qui, premete la combinazione
    Control+Windows+9
    , e dovrete essere avvisati del fatto che un contrassegno identificato con il numero 9 sia stato salvato.
  10. Se volete, per completare appieno il collaudo, muovetevi all’indietro per tornare all’inizio di ciascuno script della serie appena creata, premendo di volta in volta la combinazione
    Control+Windows
    seguita dal numero che è presente nel suffisso numerico dello script su cui vi trovate. In ciascun caso, Jaws dovrebbe confermarvi con un messaggio il salvataggio del contrassegno numerato.

Esercizio 11.2.22. Lo script TornaContrassegno1.

FileScript.

Default.JSS

Nome.

TornaContrassegno1

Sommario.

Torna al contrassegno denominato 1.

Descrizione.

Chiama la funzione di gestione dati, per tornare al contrassegno numero 1.

TastiAttivazione.

Alt+Windows+1

Note.
  1. Questo script ci fornirà la base per creare l’altra serie di script, quella per tornare ai contrassegni numerati, la quale ci consentirà quindi di completare la gestione di tale tipo di contrassegni.
  2. In modo analogo allo script precedente, i tasti di attivazione corrispondono, ad eccezione del suffisso numerico, alla combinazione usata per lo script
    TornaContrassegno ()
    ,la quale se vi ricordate era
    Alt+Windows+K
    . Questo per facilitare la possibilità di ricordarsi, ed associare la combinazione base,
    Alt+Windows
    , proprio al ritorno ai contrassegni salvati.

Codice.


Script TornaContrassegno1 ()
GestisceDato (); richiama la funzione generica
EndScript

Collaudo.

  1. Se il salvataggio va a buon fine, attiviamo nuovamente la procedura per le serie di script. posizionatevi in un punto qualsiasi del codice all’interno dello script appena salvato,
    TornaContrassegno1 ()
    , e premete i tasti di attivazione dello script
    CreaSerie (),
    Shift+Control+Windows+P.
  2. Confermate dapprima il 9 come suffisso finale per gli script, quindi premete Invio quando sarà proposta la conferma della scelta effettuata, ed Attendete infine il concludersi della procedura di copia degli script.
  3. Se questa va a buon fine, premete i comandi di ritorno ai contrassegni di cui prima avete salvato le posizioni, premendo
    Alt+Windows+9
    , e tutti gli altri eventuali numeri di contrassegno che sono disponibili. Se tutto riesce, dovreste tornare di volta in volta alla posizione del relativo contrassegno numerato.
  4. Ora, questa gestione dei contrassegni numerati è disponibile non solo nell’Editor di Script, dove avete fatto le prove sinora, bensì in ogni altro applicativo dove abbiate collaudato il salvataggio dei contrassegni, che dovrebbero essere almeno Microsoft word e Wordpad, nonché il Blocco Note.

***

Il nuovo Aiuto in linea.

Un Aiuto in linea è tanto più efficace quanto riesce ad adattarsi in modo automatico al contesto in cui viene chiamato. Per questo , dopo averne realizzato una versione base nell’ottavo capitolo, ora cogliamo l’occasione di questo aggiornamento, resosi necessario dalle serie di script, per produrne la versione definitiva.

In particolare, dopo aver effettuato quest’ultima revisione, il nostro aiuto si potrà usare in tre diversi ambiti:

  1. le normali applicazioni, dove produrrà informazioni sugli script da noi creati.
  2. Le nostre procedure guidate, dove fornirà informazioni su funzioni, e tasti disponibili, delle singole schermate.
  3. Altre schermate di conferma o inserimento, dove avrà comportamenti diversi da caso a caso.

Nel dettaglio, per quel che riguarda il suo funzionamento da dentro le normali applicazioni, come potrebbero essere l’Editor di Script, il Blocco Note o Microsoft Word e Wordpad, la nuova versione dell’Aiuto in linea ci fornirà informazioni su:

  • gli script da noi creati nel modo tradizionale, con una riga ed un link ciascuno per poterli eseguire da dentro l’Aiuto stesso.
  • Le serie di script, con una sola riga per ciascuna serie, nella quale sono presenti il nome base ed i numeri iniziale e finale, sia degli script, sia delle combinazioni tasti abbinate.
  • Gli script a gestione personale, di cui parleremo più avanti, e che avranno l’aspetto e le funzioni di quelli creati con metodo tradizionale.

Parlando invece del secondo dei tre ambiti citati prima, quello che riguarda le procedure guidate, ne sapremo di più man mano che acquisiremo le informazioni necessarie nel corso di questo e dei prossimi due capitoli. Appare tuttavia necessario anticipare almeno un tema, che poi introdurrà il primo blocco di funzioni della sezione.

I pulsanti opzionali nella funzione DlgSelectItemInList ().

Nel sesto capitolo avevamo incontrato per la prima volta la funzione
DlgSelectItemInList ()
,anticipando fin da allora che essa aveva sei parametri. Dopo aver utilizzato anche il quarto di questi nella nostra recente funzione
SceltaValore ()
, come anticipato in quell’occasione, è giunto ora il momento di completare la conoscenza anche degli ultimi due possibili parametri opzionali.

Per evitare errori, riportiamo in sintesi le note riguardanti i primi quattro parametri di questa speciale funzione, seguite più in dettaglio da quelle che riguardano l’ultima coppia di parametri inediti:

  1. L’elenco delle voci testuali da selezionare.
  2. Il titolo della finestra di dialogo.
  3. Il valore che indica l’ordine alfabetico.
  4. Il numero della voce selezionata, sulla quale sarà posizionato il cursore, all’ingresso nella finestra di dialogo.
  5. Un elenco testuale, composto da un massimo di cinque voci separate tra loro da il carattere Pipe, che rappresentano le etichette visualizzate di altrettanti pulsanti opzionali, da proporre a video assieme a quelli predefiniti,
    Ok
    e
    Annulla.
  6. Una variabile di tipo Integer, che trasmette per riferimento un valore che indica l’eventuale pulsante opzionale premuto; in questo caso, il valore assegnato alla variabile sarà positivo, e restituirà il numero del pulsante nell’ordine della sua etichetta nell’elenco; nel caso siano premuti i tasti predefiniti, tale variabile restituirà 0 per
    "Annulla"
    , -1 per
    "Ok".

Evitando di parlare ancora del quarto parametro, che abbiamo peraltro già utilizzato, sui restanti due possiamo subito dire che sono complementari tra loro. Se il quinto parametro fornisce un elenco di pulsanti da premere, infatti, il sesto consente di capire quali di questi si sia casomai premuto, e quindi il loro utilizzo deve essere per forza contemporaneo.

Una interessante peculiarità di questi pulsanti è il modo in cui si possono attivare, il quale dipende da come ne specifichiamo il nome. Per capire meglio, facciamo subito un esempio, mettendo di seguito un elenco con le etichette di quattro pulsanti opzionali che, per maggiore chiarezza, poniamo ciascuno su una diversa riga:


modifica|
campo successivo|
campo precedente|
torna all’inizio

Se noi usassimo questo elenco, meglio se assegnato ad una variabile e comunque con i caratteri Pipe al posto dei ritorni a capo, avremmo nella nostra finestra di dialogo questi quattro pulsanti in più. Per poterli azionare, tuttavia, dovremo per forza spostarci con i tasti di movimento, Tab o Shift+Tab, ed una volta sopra al pulsante desiderato, premere Invio.

Se invece ai nomi dei pulsanti si aggiunge il carattere
"&"
, la E Commerciale, nota anche con il termine inglese di
Ampersand
, la lettera, o il carattere, che segue immediatamente questo segno speciale, diventa il tasto da premere assieme al tasto
Alt
per attivare il pulsante stesso. Creeremo così delle
"scelte rapide"
che, se riusciamo a non usare lettere uguali per la stessa finestra di dialogo, ci consentono con un solo gesto di simulare la pressione diretta del pulsante.

Riprendendo l’elenco precedente, poniamo di seguito le etichette da porre nell’elenco con il carattere E Commerciale, seguito da un segno di Uguale e dalla scelta rapida così creata:


&modifica = Alt+M
Campo s&uccessivo = Alt+U
Campo p&recedente Alt+R
&Torna all’inizio = Alt+T

Per finire, un’importante avvertenza: Proprio per evitare di creare più pulsanti con la stessa scelta rapida, bisogna sempre tener conto che i due pulsanti predefiniti,
"Ok"
e
"Annulla"
, si attivano rispettivamente con le scelte
"Alt+O"
e
"Alt+A".

Le variabili globali per le procedure.

Sinora ci siamo occupati di brevi procedure, dove il dialogo tra i vari elementi di codice era garantito dal passaggio di parametri, oppure di sistemi integrati, dove i dati comuni ai diversi elementi erano trascritti sui file in formato
INI
. Da qui in avanti, invece,pur continuando ad usare sia il primo sia il secondo dei sistemi citati, faremo sempre più largo uso delle variabili globali per trasmettere i dati da un elemento di codice all’altro.

Questo sistema ha il grande vantaggio di limitare al minimo l’uso dei parametri nelle funzioni, oltre a rendere sempre disponibili delle variabili senza doverle dichiarare a livello locale. Di contro, entrambi questi aspetti fanno sì che il flusso degli elementi di codice sia molto meno intuitivo, dovendo quindi conoscere l’assieme delle procedure su cui si sta lavorando per capire bene l’utilizzo di tali variabili globali.

Potrà perciò capitare, come già dalle prossime funzioni, d’imbattersi in una variabile globale di cui si controlla il contenuto, senza che in nessun altro elemento di codice si sia incontrata un’assegnazione di un valore a quella variabile. Quando ciò capiterà, cercheremo di dare qualche spiegazione in più tra le note delle schede, nella speranza di poter rendere più comprensibile il flusso del codice.

Creare il testo dell’aiuto nelle finestre di dialogo.

Il primo blocco di questa sezione riguarda tre funzioni, una principale e due secondarie, che si occupano di creare le informazioni d’aiuto sui tasti disponibili nelle finestre di dialogo. Tali informazioni sono prese direttamente dalle etichette dei pulsanti, quelle che abbiamo esaminato devono essere poste nel quinto parametro della funzione
DlgSelectItemInList ()
, e che sono nella circostanza registrate in una variabile globale. In particolare, la prima funzione è un’altra di quelle create solo per semplificare la sintassi delle sostituzioni di testo, mentre la seconda serve a sua volta solo per facilitare la formattazione di una stringa.

Esercizio 11.3.4. La funzione NoAmpersand.

FileScript.

Default.JSS

Nome.

NoAmpersand

Descrizione.

Rimuove i caratteri E Commerciale eventualmente presenti nella stringa passata come parametro.

Ritorni.

Di tipo String. La stringa eventualmente ripulita dai caratteri E Commerciale.

Parametri.
  1. sTesto. Il testo da ripulire. Di tipo String.
Novità.
  1. La costante
    AMPERSAND
    , che contiene l’omonimo carattere.

Codice.


String Function NoAmpersand (string sTesto)
Return StringReplaceSubstrings (sTesto, AMPERSAND, NULLO); rimuove il carattere
EndFunction

Esercizio 11.3.5. La funzione PremeTasto.

FileScript.

Default.JSS

Nome.

PremeTasto

Descrizione.

Formatta una stringa con il comando che simula la pressione del tasto specificato come parametro.

Ritorni.

Di tipo String. Il comando formattato.

Parametri.
  1. sNome. Il nome del tasto, o della combinazione, da formattare. Di tipo String.

Codice.


String Function PremeTasto (string sNome)
Return FormatString (lstPremiTasto, sNome); restituisce il testo formattato con il nome dei tasti
EndFunction

Esercizio 11.3.6. La funzione ComponeAiuto.

FileScript.

Default.JSS

Nome.

ComponeAiuto

Descrizione.

Raccoglie i dati in memoria per comporre le informazioni dell’Aiuto in linea.

Ritorni.

Di tipo Void. Nessuno.

Novità.
  1. Le nostre funzioni
    NoAmpersand ()
    e
    PremeTasto ().
  2. La funzione integrata
    StringUpper
    , (DatoTestualeMaiuscolo); Converte in caratteri maiuscoli il testo specificato nel suo unico parametro.
  3. La funzione integrata
    UserBufferAddLink
    , (AggiungiLinkBufferUtente); Aggiorna il contenuto dell’ambiente virtuale, ponendovi solo i primi tre dati per il collegamento che esegue il comando abbinato. A differenza dell’analoga funzione utilizzata nell’ottavo capitolo, mantiene soltanto i primi tre parametri, di cui anche in questo caso solamente il primo obbligatorio:
    • Il testo da inviare al Visualizzatore Virtuale.
    • Il comando che si vuole venga eseguito quando si clicca sul testo presente nel primo parametro.
    • La voce che si vuole appaia nell’elenco dei link, la quale attiverebbe il comando inserito nel secondo parametro.
  4. Le costanti
    ALT
    e
    ALT_O
    , che corrispondono alle omonime combinazioni tasti.
Fasi.
  1. Dopo aver inizializzato il Visualizzatore Virtuale, un ciclo scorre i pulsanti memorizzati nella variabile globale
    gsEtichette.
  2. il nome della scelta rapida che attiva ciascun pulsante sarà acquisita sommando il prefisso
    Alt
    alla lettera che segue il carattere E Commerciale, mentre la spiegazione del pulsante sarà la stessa etichetta, ripulita dall’E Commerciale, cui si aggiunge un termine predefinito registrato in un’altra variabile globale,
    gsTermine
    ; in questa fase, tra le altre, saranno utilizzate le nostre funzioni
    NoAmpersand ()
    e
    PremeTasto ()
    , oltre a quelle native
    StringUpper ()
    e
    UserBufferAddLink ().
  3. Dopo aver concluso la porzione variabile delle informazioni con la seconda parte del titolo, registrato nella corrispondente variabile globale, le informazioni saranno concluse con i messaggi predefiniti che contraddistinguono anche le informazioni espresse dall’Aiuto in linea tradizionale.

Codice.


Void Function ComponeAiuto ()
Var
String sInfo, ; il testo delle informazioni in linea
Int i, ; contatore dei cicli
String sNome, ; dati del singolo pulsante
String sCaldo, ; nome del tasto caldo che attiva il pulsante
String sTesto; descrizione della funzione svolta dal pulsante
EnsureNoUserBufferActive (); chiude eventuali schermate del Visualizzatore Virtuale
; Inizializza le informazioni, inviando al buffer la prima parte del titolo memorizzato
UserBufferAddText (FormatString (ttlInfoDialogo, StringSegment (gsTitolo, PIPE, PRIMA)))
For i = 1 To StringSegmentCount (gsEtichette, PIPE); scorre i pulsanti opzionali impostati
Let sNome = StringSegment (gsEtichette, PIPE, i); estrae l’etichetta sul pulsante
; rileva anche la lettera della scelta rapida, formattandola assieme al prefisso del tasto
Let sCaldo = FormatString (msg2Piu, ALT, StringUpper (SubString (sNome, StringContains (sNome, AMPERSAND) + 1, 1)))
Let sNome = NoAmpersand (sNome); rimuove il carattere E Commerciale dall’etichetta
If !StringContains (sNome, SPACE) Then; se l’etichetta del pulsante è di una sola parola,
Let sTesto = FormatString (msg2Spazi, sNome, gsTermine); vi formatta anche il soggetto
Else; altrimenti, se vi sono già due o più parole,
Let sTesto = sNome; utilizza la forma originale
EndIf; fine controllo parole etichetta
; aggiorna il contenuto del buffer, aggiungendo il comando ed il contenuto del link
UserBufferAddLink (FormatString (msg2Punto, sTesto, sCaldo), PremeTasto (sCaldo), sTesto)
EndFor; fine scansione tasti
Let sTesto = StringSegment (gsTitolo, PIPE, SECONDA); estrae anche la seconda parte del titolo,
UserBufferAddLink (sTesto, PremeTasto (ALT_O), TroncaTesto (sTesto, PUNTO)); e la aggiunge al buffer
; Chiude la serie di comandi nel buffer con il testo predefinito per il tasto Escape
UserBufferAddLink (lstEscape, PremeTasto (ALT_A), TroncaTesto (lstEscape, PUNTO))
UserBufferActivate (); visualizza il contenuto del visualizzatore virtuale
; formatta infine le righe conclusive, citando il comando d’ingresso e di uscita dalle informazioni,
Let sInfo = FormatString (hlpUltimaInfo, GetCurrentScriptKeyName (), hlpFineInfo);
; poi, le trasmette al Buffer, avviandone la lettura.
RedirectToUserBuffer (sInfo)
EndFunction

Collaudo.

  1. Malgrado l’elemento sia l’ultimo del gruppo, per un vero e proprio collaudo bisognerà attendere lo script a fine sezione.

Le nuove versioni di NomeArchivio () e ComprimeDati ().

Due su tre delle funzioni che compongono questo blocco saranno le versioni definitive degli elementi di codice già proposti negli scorsi capitoli. Il sistema da rinnovare è l’acquisizione dell’elenco degli script di cui visualizzare le informazioni, prelevandoli dalla cartella con le impostazioni per l’Utente.

L’aspetto da aggiornare, nei confronti in particolare della versione dell’Aiuto in linea dell’ottavo capitolo, è far comprendere a Jaws se ci si trovi nel file script predefinito. Tale esigenza viene soddisfatta dalla prima funzione delle tre, che è quindi l’unico elemento davvero inedito del blocco.

Esercizio 11.3.8. La funzione ApplicativoCorrente.

FileScript.

Default.JSS

Nome.

ApplicativoCorrente

Descrizione.

Determina il nome dell’applicativo corrente, convertendolo in quello predefinito di Jaws qualora ci si trovi nell’Editor di Script.

Ritorni.

Di tipo String. Il nome dell’applicativo corrente, eventualmente convertito.

Novità.
  1. Le costanti
    EDITOR_ITA
    e
    EDITOR_ENU
    , le quali corrispondono al nome reale dell’Editor di Script, così come lo rileva Jaws, dapprima nella versione italiana, poi in quelle per Jaws 18, Jaws 2021 ed in lingua inglese.

Codice.


String Function ApplicativoCorrente ()
Var String sNome = GetActiveConfiguration (); dichiara e rileva il nome dell’applicazione attiva
If sNome == EDITOR_ITA ; se il nome corrisponde alla versione italiana dell’Editor di Jaws,
|| sNome == EDITOR_ENU Then; oppure se corrisponde a quella standard inglese,
Return JAWS_FILE; restituisce il nome dei file standard di Jaws
Else; altrimenti,
Return sNome; restituisce il nome rilevato
EndIf; fine controllo nome
EndFunction

Esercizio 11.3.9. La versione aggiornata di NomeArchivio ().

FileScript.

Default.JSS

Nome.

NomeArchivio

Novità.
  1. La nostra funzione
    ApplicativoCorrente ().
Note.
  1. Le modifiche rispetto alla precedente versione consistono soltanto nel sostituire la funzione integrata
    GetActiveConfiguration ()
    , con quella appena realizzata
    ApplicativoCorrente ()
    , quando si chiede il nome del file tasti attivo.

In questo caso, se ci si trova nell’Editor di Script, viene restituito il nome del file tasti predefinito,
Default.JKM.

Codice.


String Function NomeArchivio (int iTipo)
If iTipo == CORRENTE Then; se l’archivio da elaborare è quello dell’applicazione attiva,
Return GetActiveConfiguration () + JCF; ne restituisce il nome aggiungendo l’estensione
ElIf iTipo == PERSONALE Then; se invece l’archivio da elaborare è quello personale,
Return PS_FILE + JCF; ne restituisce il nome aggiungendo l’estensione
ElIf iTipo == APP Then; per il file Tasti dell’applicazione attiva,
Return ApplicativoCorrente () + JKM; restituisce il file tasti dell’applicazione
ElIf iTipo == JAWS Then; per il file Tasti Predefinito,
Return JAWS_FILE + JKM; utilizza l’altra costante impostata
ElIf iTipo == SEGNI Then; se l’archivio da elaborare è quello per i contrassegni,
; rimuove i riferimenti ai suffissi inglesi dei nomi, ed aggiunge etichetta ed estensione
Return FormatString ( ; restituisce il nome formattato,
msg2, ; messaggio base,
StringReplaceSubstrings (GetActiveConfiguration (), CLASSIC, NULLO), ; rimuove un suffisso,
SUFFISSO_JSI); e ne aggiunge un altro, comprensivo d’estensione
ElIf iTipo == TEMPORANEO Then; se infine è richiesto un archivio solo per la sessione,
Return FormatString ( ; restituisce nome e percorso dell’archivio temporaneo
msg3Controbarra, ; messaggio base,
GetUserSettingsDirectory (), ; percorso completo delle Impostazioni personali,
CARTELLA_SESSIONE, ; nome della sottocartella dove salvare le annotazioni,
GetActiveConfiguration () + TMP); etichetta dell’applicativo corrente
EndIf; fine controllo tipo archivio
EndFunction

Esercizio 11.3.10. La versione aggiornata di ComprimeDati ().

FileScript.

Default.JSS

Nome.

ComprimeDati

Ritorni.

Di tipo Int. TRUE per il rilevamento di tasti, FALSE per nessun tasto.

Note.
  1. La modifica più importante alla versione precedente viene dalla definizione di un tipo di ritorno
    Integer
    , al posto di quello vuoto precedente, e quindi con la relativa descrizione che indica il restituirsi di un risultato
    "TRUE"
    o
    "FALSE"
    . Tale modifica comporta anche alla fine, dopo la conclusione del ciclo di scansione degli script, una struttura di controllo per restituire un valore positivo o nullo tramite l’istruzione
    "Return".
  2. L’altra modifica riguarda l’aggiunta di due assegnazioni che svuotano il contenuto di altrettanti parametri da trasmettere per riferimento ,
    "sChiavi"
    e
    "sDati"
    , che con più chiamate dalla stessa funzione finivano per rimanere in memoria anche quando gli script erano assenti.
  3. Le altre modifiche sono i vari richiami alle nostre funzioni,
    ChiaviUtente (),
    CambiaCampo ()
    e
    LeggeUtente ()
    , che abbiamo prodotto nel frattempo e che possiamo implementare ora per rendere più semplice il codice.

Codice.


Int Function ComprimeDati (string sFile, string sSezioni, ; intestazione con i primi due parametri,
string ByRef sChiavi, string ByRef sDati); seconda riga, con gli altri due
Var
Int j, ; contatore del ciclo primario
Int k, ; contatore del secondo ciclo
String sSezione, ; sezione del file da leggere
String sElenco, ; elenco temporaneo delle chiavi
String sChiave, ; chiave del dato
String sDato; singolo dato da leggere
Let sChiavi = NULLO; resetta l’elenco dei tasti,
Let sDati = NULLO; ed anche dei nomi di script
For j = 1 To StringSegmentCount (sSezioni, PIPE); scorre le sezioni da leggere
Let sSezione = StringSegment (sSezioni, PIPE, j); estrae una singola sezione
Let sElenco = ChiaviUtente (sFile, sSezione); rileva le chiavi dei dati dell’Utente
For k = 1 To StringSegmentCount (sElenco,PIPE); scorre l’eventuale elenco rilevato
Let sChiave = StringSegment (sElenco, PIPE, k); ne estrae la singola chiave
If !StringSegmentIndex (sChiavi, PIPE, sChiave, TRUE) Then; se la chiave non c’è,
Let sChiavi = CambiaCampo (sChiavi, sChiave, ULTIMA); la aggiunge all’elenco esistente
Let sDato = LeggeUtente (sFile, sSezione, sChiave); poi rileva il nome di script,
Let sDati = CambiaCampo (sDati, sDato, ULTIMA); e lo aggiunge al relativo elenco
EndIf; fine controllo chiavi registrate
EndFor; fine scorrimento chiavi
EndFor; fine scorrimento sezioni
If sChiavi Then; se, alla fine, dei tasti sono stati rilevati,
Return TRUE; restituisce l’esito positivo
Else; altrimenti,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo esito
EndFunction

Collaudo.

  1. Anche in questo caso, per il collaudo rinviamo al primo script utile, alla fine della sezione.

Un accenno sugli script a gestione personale.

Come promesso, la prossima funzione ci obbliga ad anticipare qualcosa sugli script a gestione personale, che tratteremo man mano nella predisposizione dei vari elementi di codice, ma che saranno diffusamente trattati solo al termine della nostra trattazione.

Per far capire meglio di cosa stiamo parlando, iniziamo con ricordare le caratteristiche degli script tradizionali, quelli che abbiamo trattato sinora, che possiamo così sintetizzare:

  1. Sono realizzati e compilati dentro all’Editor di Script, dove si assegna ad essi tutti i dati descrittivi ed i tasti di attivazione.
  2. Ad essi si assegna un nome che ricorda il più possibile il compito svolto.
  3. L’abbinamento tra i tasti che li attivano ed il loro nome si può verificare all’interno dei file tasti, quelli con estensione
    .JKM.

Diversamente, gli script a gestione personale, che andremo più avanti a costruire, hanno le seguenti caratteristiche:

  1. Sono realizzati solo all’inizio dentro all’Editor di Script, stabilendo un gran numero di script predefiniti che poi saranno usati nei diversi applicativi, con un nome che avrà sempre la stessa base,
    EseguePersonali
    , seguita da un suffisso numerico.
  2. Il nome virtuale, quello che ci servirà per riconoscerli, i dati descrittivi e le mansioni svolte saranno invece registrati nei nostri archivi di configurazione, ed inseriti tramite una nostra procedura guidata, la quale potrà essere avviata direttamente da dentro ciascun applicativo in cui gli script personali andranno ad agire.
  3. Per quanto detto al punto 1, i tasti che attivano gli script a gestione personale risulteranno abbinati ai nomi reali degli script, quelli che contengono la base predefinita ed il suffisso numerico.

Esaminandoli così in tre punti, si può far fatica anche a capire quale sia il vantaggio di questo sistema. Quello che si può anticipare è che, a pieno regime, esso consentirà una gestione molto più semplice e rapida dei file script per le varie applicazioni , permettendoci di non dover più entrare ed uscire dall’Editor di Jaws.

Inoltre, le copie di tutti gli script a gestione personale saranno memorizzate in un unico archivio. Questo permetterà di inserirne una versione nell’applicativo corrente grazie ad un solo comando, avendo poi l’opportunità anche di modificarne l’azione compiuta, o i tasti di attivazione, sempre agendo in una nostra procedura direttamente da dentro l’applicativo stesso.

A prescindere dai dettagli, per completare i prossimi elementi di codice è importante che voi sappiate che gli script a gestione personale hanno un nome reale, facilmente riconoscibile perché differisce solo tramite un suffisso numerico, ed uno virtuale, che nel codice chiameremo
"alias"
. Questo nome virtuale ci consente comunque di identificare gli script sulla base della funzione che svolgono, in modo del tutto analogo a quello che si fa con i normali script.

Esercizio 11.3.12. La funzione ScriptPersonale.

FileScript.

Default.JSS

Nome.

ScriptPersonale

Descrizione.

Controlla che il nome di script indicato sia uno di quelli a gestione personale.

Ritorni.

Di tipo Int. TRUE, per la conferma dello script personale; FALSE, se non lo è.

Parametri.
  1. sNome. Il nome dello script da controllare. Di tipo String.
  2. sSuffisso. Per Riferimento. L’eventuale suffisso rilevato, qualora sia una cifra in forma testuale. Di tipo String. Parametro Opzionale.
Novità.
  1. La funzione integrata
    StringDiff
    , (DifferenzeDatiTestuali); Restituisce la parte iniziale o finale della stringa principale, indicata come primo parametro, che non sia contenuta nella stringa posta come secondo parametro; ad esempio, se come prima stringa abbiamo i due termini
    "Ciao Pippo"
    , e nella seconda abbiamo invece solo
    "Ciao"
    , la funzione restituirà
    "Pippo"
    ; se le due stringhe indicate sono uguali, oppure non vi è alcuna uguaglianza nelle parti finali o iniziali, sarà restituita una stringa vuota.
Note.
  1. Sulla base di quanto anticipato nella breve premessa, il controllo sul fatto che siano o meno degli script a gestione personale avviene confrontando il nome indicato con quello predefinito come base degli script stessi, e verificando se nel nome vi sia il suffisso numerico.
  2. Se tale suffisso esiste, esso sarà usato come chiave del record dove acquisire gli altri dati relativi allo script, compreso il nome virtuale, l’
    "alias"
    , che sarà casomai trasmesso per riferimento dalla funzione.
  3. Nel codice, per estrapolare l’eventuale suffisso, non ci si limita solo a controllare che una stringa possa essere convertita in numero, ma viene controllato anche se il numero convertito abbia tante cifre quanti siano i caratteri che compongono la stringa. Questo perché la funzione
    StringToInt ()
    restituisce un numero anche se, nella stringa, dopo la cifra numerica vi si trovino anche degli altri caratteri, cosa che creerebbe dei malfunzionamenti nella procedura.

Codice.


Int Function ScriptPersonale (string sNome, string ByRef sSuffisso)
Var
Int iValore, ; valore temporaneo
Int iLungo; lunghezza dell’eventuale suffisso rilevato
; estrae le differenze del nome rispetto a quello base degli script personali
Let sSuffisso = StringDiff (sNome, FormatString (msgPersonalScript))
Let iValore = StringToInt (sSuffisso); verifica l’eventuale valore numerico della stringa,
Let iLungo = StringLength (sSuffisso); e ne misura comunque la lunghezza
If (iValore && iLungo == 1) ; se la differenza è una cifra con una lunghezza di un carattere,
|| (iValore > 9 && iLungo == 2) ; oppure, il valore è superiore a nove e una lunghezza di 2,
Return TRUE; restituisce l’esito positivo
Else; altrimenti,
Let sSuffisso = NULLO; resetta il dato,
Return FALSE; e restituisce un risultato nullo
EndIf; fine controllo suffisso
EndFunction

Collaudo.

  1. Anche in questo caso, segnaliamo il secondo come un parametro opzionale, per il quale s’invita a modificare la scheda della funzione
    "ScriptPersonale"
    , nel file documentazione predefinito.

Esercizio 11.3.13. La funzione CampoGlobale.

FileScript.

Default.JSS

Nome.

CampoGlobale

Descrizione.

Controlla la registrazione di un numero di campo, casomai impostandone il valore iniziale.

Ritorni.

Di tipo Int. Il numero del campo attivo.

Note.
  1. Questa funzione è un classico esempio di quello cui si accennava nel titolo riguardante l’uso delle variabili globali. In questo caso, infatti, possiamo creare una funzione senza parametri, poiché il valore controllato è la variabile globale
    "gnCampo"
    , che è impostata in altre funzioni della procedura e che, se non già settata in questa fase, fa restituire il valore 1.

Codice.


Int Function CampoGlobale ()
If gnCampo Then; se la variabile globale è già stata impostata,
Return gnCampo; ne restituisce il valore
Else; altrimenti, se è ancora nulla,
Return PRIMA; restituisce il valore Uno
EndIf; fine controllo campo
EndFunction

Scrivere e leggere i record.

All’interno di questo nutrito blocco di funzioni, ed in particolare per i prossimi quattro elementi di codice, troveremo l’ultima evoluzione della scrittura sui file in formato
INI
, quella dedicata in particolare ai file di configurazione.

Si tratta della classica doppia coppia, scrittura e lettura, dei due tipi di dato principale, testuale e numerico, di cui proponiamo l’elenco:

  1. WriteSettingString
    , (ScriviImpostazioniTestuali);
  2. ReadSettingString
    , (LeggiImpostazioniTestuali);
  3. WriteSettingInteger
    , (ScriviImpostazioniNumeriche);
  4. ReadSettingInteger
    , (LeggiImpostazioniNumeriche).

Tutte e quattro queste funzioni integrate elaborano un dato testuale, o un valore, da file configurazione in formato INI, restringendo la ricerca del tipo di archivio o della sua collocazione sulla base di particolari valori numerici da specificare.

Hanno tutte ben sei parametri, dei quali solo gli ultimi due opzionali, che qui elenchiamo di seguito:

  1. La sezione dell’archivio in cui operare.
  2. La chiave del dato da elaborare.
  3. Il dato o il valore da scrivere, nelle due funzioni di scrittura, oppure quello che si vuole sia restituito in caso di dato assente, nelle due funzioni di lettura.
  4. Un valore che corrisponde al tipo di file da trattare, sotto forma di costante registrata nel file
    "HJConst.JSH"
    , e che iniziano con il prefisso
    FT_
    , il quale sta per
    FileType
    , (TipoFile).
  5. Un valore, opzionale, che corrisponde alla destinazione di scrittura, nel caso delle omonime funzioni, e di origine lettura, per quelle dell’altro tipo; questi possono essere impostati tramite costanti, che si trovano sempre nel file
    "HJConst.JSH"
    , rispettivamente con i prefissi
    wd
    , che sta per
    WriteDestination
    , DestinazioneScrittura), ), e
    rs
    , che sta invece per
    ReadSource)
    , (SorgenteLettura).
  6. Il nome dell’archivio in cui scrivere; può anche non essere indicato, in quanto opzionale, poiché il nome dell’archivio potrebbe essere già impostato dal tipo di file del quarto parametro; in ogni caso, non è necessario specificare un’estensione al nome dell’archivio, poiché a ciascun tipo di file corrisponde un’estensione predefinita.

Come al solito, inserendo delle funzioni di Jaws nelle nostre, cerchiamo di ridurre il numero di parametri da impostare nelle chiamate. Così, grazie a questa riduzione, quelli da specificare diventeranno quattro per le funzioni di scrittura, e tre per quelle di lettura.

Nel dettaglio, ad essere preimpostati saranno sempre il quarto e quinto parametro delle funzioni native, che saranno rispettivamente:

  1. FT_CURRENT_JCF
    , (TipoDiFileConfigurazioneCorrente), che imposta come predefinito appunto il file di configurazione dell’applicativo corrente; ciò significa che, qualora nel sesto parametro si indichi un nome di archivio, ad esso sarà comunque posta l’estensione predefinita,
    .JCF
    ; altrimenti, se non si specifica nulla, sarà usato il file di configurazione relativo al programma attivo in quel momento.
  2. FALSE
    , per impostare i relativi valori predefiniti, che poniamo solo per consentire di specificare anche il successivo parametro con l’eventuale nome archivio.

Esercizio 11.3.15. La funzione ScriveRecord.

FileScript.

Default.JSS

Nome.

ScriveRecord

Descrizione.

Trascrive il record nel file di configurazione indicato, o in quello dell’applicazione corrente, nella sezione e con la chiave specificate, formattandolo in una stringa tra Virgolette.

Ritorni.

Di tipo Int. l’esito della scrittura, TRUE o FALSE.

Parametri.
  1. sArchivio. Il nome, senza estensione, dell’archivio da elaborare; se si imposta una stringa vuota, viene scritto sul file di configurazione dell’applicativo corrente. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del dato. Di tipo String.
  4. sDato. Il dato da scrivere. Di tipo String.
Novità.
  1. La funzione integrata
    WriteSettingString ()
    , già illustrata nella premessa.
  2. La costante nativa
    FT_CURRENT_JCF
    , anch’essa già presentata.
Note.
  1. In questa funzione il dato da scrivere lo poniamo tra virgolette, così da conservare eventuali spazi a fine stringa che, senza tale accorgimento, andrebbero perduti.
  2. Oltre a ciò, diversamente dalle altre funzioni di scrittura fin qui realizzate, subordiniamo il tentativo di scrittura del dato al fatto che sia specificata una chiave; se così non fosse, infatti, non solo il dato non si riuscirebbe a scriverlo ma, soprattutto, sarebbe rimossa l’intera sezione, causando la perdita irreversibile dei dati in essa contenuti.

Codice.


Int Function ScriveRecord (string sArchivio, string sSezione, string sChiave, string sDato)
Let sDato = FormatString (msgVirgolette, sDato); inserisce il dato in una stringa tra virgolette
If sChiave Then; se la chiave del dato è specificata, restituisce l’esito della scrittura
Return WriteSettingString (sSezione, sChiave, sDato, FT_CURRENT_JCF, FALSE, sArchivio)
Else; altrimenti, se una chiave non c’è,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo chiave
EndFunction

Collaudo.

Esercizio 11.3.16. La funzione LeggeRecord.

FileScript.

Default.JSS

Nome.

LeggeRecord

Descrizione.

Tenta di rilevare il record dall’archivio di configurazione specificato, o da quello dell’applicazione corrente, nella sezione e con la chiave indicate.

Ritorni.

Di tipo String. Il contenuto del record specificato.

Parametri.
  1. sArchivio. Il nome, senza estensione, dell’archivio da elaborare; se si imposta una stringa vuota, viene letto dal file di configurazione dell’applicativo corrente. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del record. Di tipo String.
Novità.
  1. La funzione integrata
    ReadSettingString ()
    , già presentata.

Codice.


String Function LeggeRecord (string sArchivio, string sSezione, string sChiave)
; restituisce il dato eventualmente letto , sulla base dei dati specificati, nel file di configurazione.
Return ReadSettingString (sSezione, sChiave, NULLO, FT_CURRENT_JCF, FALSE, sArchivio)
EndFunction

Collaudo.

Esercizio 11.3.17. La funzione ScriveNumerico.

FileScript.

Default.JSS

Nome.

ScriveNumerico

Descrizione.

Trascrive il valore nel file di configurazione indicato, o in quello dell’applicazione corrente, nella sezione e con la chiave specificate.

Ritorni.

Di tipo Int. l’esito della scrittura, TRUE o FALSE.

Parametri.
  1. sArchivio. Il nome, senza estensione, dell’archivio da elaborare; se si imposta una stringa vuota, viene scritto sul file di configurazione dell’applicativo corrente. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del valore. Di tipo String.
  4. iValore. Il valore numerico da scrivere. Di tipo Int.
Novità.
  1. La funzione integrata
    WriteSettingInteger ()
    , già presentata.
Note.
  1. Anche in questo caso, subordiniamo il tentativo di scrittura del dato alla presenza di una chiave, grazie ad una struttura di controllo, per evitare la perdita dei dati presenti nella sezione.

Codice.


Int Function ScriveNumerico (string sArchivio, string sSezione, string sChiave, int iValore)
If sChiave Then; se la chiave del dato è specificata, restituisce l’esito della scrittura
Return WriteSettingInteger (sSezione, sChiave, iValore, FT_CURRENT_JCF, FALSE, sArchivio);
Else; altrimenti, se una chiave non c’è,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo chiave
EndFunction

Esercizio 11.3.18. La funzione LeggeNumerico.

FileScript.

Default.JSS

Nome.

LeggeNumerico

Descrizione.

Tenta di rilevare il valore dall’archivio di configurazione specificato, o da quello dell’applicazione corrente, nella sezione e con la chiave indicate.

Ritorni.

Di tipo Int. L’eventuale valore registrato.

Parametri.
  1. sArchivio. Il nome, senza estensione, dell’archivio di configurazione da elaborare; se si imposta una stringa vuota, viene letto dal file di configurazione dell’applicativo corrente. Di tipo String.
  2. sSezione. Il nome della sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del valore da leggere. Di tipo String.
Novità.
  1. La funzione integrata
    ReadSettingInteger ()
    , già presentata.

Codice.


Int Function LeggeNumerico (string sArchivio, string sSezione, string sChiave)
; restituisce il valore eventualmente letto , sulla base dei dati specificati, nel file di configurazione.
Return ReadSettingInteger (sSezione, sChiave, FALSE, FT_CURRENT_JCF, FALSE, sArchivio);
EndFunction

Esercizio 11.3.19. La funzione LeggeCampo.

FileScript.

Default.JSS

Nome.

LeggeCampo

Descrizione.

Rileva il campo del record con il numero progressivo indicato, inserito nell’archivio di configurazione dell’applicativo corrente, o con il nome impostato nell’apposita variabile globale.

Ritorni.

Di tipo String. Il dato contenuto nel campo indicato del record.

Parametri.
  1. sArchivio. Il nome, senza estensione, dell’archivio da elaborare; se si imposta una stringa vuota, viene letto dal file di configurazione dell’applicativo corrente. Di tipo String.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del record. Di tipo String.
  4. iCampo. Eventuale numero del campo da estrarre; se non lo si indica, sarà usato quello memorizzato nell’apposita variabile globale. Di tipo Int. Parametro Opzionale.
Novità.
  1. Le nostre funzioni
    CampoGlobale ()
    e
    LeggeRecord ().
Fasi.
  1. Una struttura di controllo verifica se nessun parametro sia stato indicato come numero del campo da leggere; se così è, viene utilizzato il valore fornito dalla nostra funzione
    CampoGlobale ()
    , la quale assegna comunque un qualche valore alla variabile locale.
  2. Viene poi letto l’intero record di dati, sulla base di quanto specificato dai parametri, grazie all’altra nostra funzione
    LeggeRecord ().
  3. In ogni caso, si tenta di restituire il campo impostato del record; se il record è vuoto, o se il campo impostato non è presente nel record, viene restituita una stringa vuota.

Codice.


String Function LeggeCampo (string sArchivio, string sSezione, string sChiave, int iCampo)
Var String sRecord; il record di dati estratto
If! iCampo Then; se non è stato specificato alcun parametro,
Let iCampo = CampoGlobale (); imposta un valore, quello della variabile globale o il valore Uno
EndIf; fine controllo campo
; estrae il record di dati dall’archivio, dell’applicativo corrente o del nome impostato
Let sRecord = LeggeRecord (sArchivio, sSezione, sChiave)
Return StringSegment (sRecord, PIPE, iCampo); restituisce il solo campo richiesto
EndFunction

Collaudo.

  1. L’ultimo parametro opzionale della funzione invita ad aprire subito il file documentazione predefinito, cercare la scheda della funzione
    "LeggeCampo"
    , ed inserire il termine apposito tra il terzo ed il quarto parametro.

Esercizio 11.3.20. La funzione ImpostaNomi.

FileScript.

Default.JSS

Nome.

ImpostaNomi

Descrizione.

Restituisce il nome passato come parametro, e valuta se utilizzarlo come alias o se ricavarlo dagli script personali.

Ritorni.

Di tipo String. Il nome passato come primo parametro.

Parametri.
  1. sNome. Il nome reale dello script. Di tipo String.
  2. sAlias. Per Riferimento. L’eventuale alias da utilizzare nelle schermate d’informazioni. Di tipo String.
Novità.
  1. Le nostre funzioni
    ScriptPersonale ()
    e
    LeggeCampo ().
  2. La costante
    PERSONALI
    , che contiene il termine omonimo preceduto dal prefisso della categoria, formando così il nome della sezione dove elaborare gli script a gestione personale.
Fasi.
  1. Una struttura di controllo chiama la nostra funzione
    ScriptPersonale ()
    , per verificare se il nome passato come parametro appartiene ad uno script a gestione personale; se così è, procede a registrare in un’altra variabile, che sarà trasmessa per riferimento, il nome virtuale dello script, che è diverso da quello che viene eseguito da Jaws, e viene rilevato tramite la nostra funzione
    LeggeCampo ().
  2. Nel caso in cui il nome appartenga ad uno script tradizionale, alla seconda variabile sarà assegnato lo stesso nome di partenza.
  3. In ogni caso, il nome originario viene restituito come risultato della funzione.

Codice.


String Function ImpostaNomi (string sNome, string ByRef sAlias)
Var String sSuffisso; l’eventuale suffisso numerico del nome
If ScriptPersonale (sNome, sSuffisso) Then; se il nome è di uno script a gestione personale,
; estrae il nome virtuale dello script dal relativo record di dati
Let sAlias = LeggeCampo (NULLO, PERSONALI, sSuffisso, PRIMA)
Else; altrimenti, in tutti gli altri casi,
Let sAlias = sNome; copia il nome reale in quello virtuale
EndIf; fine controllo nome script
Return sNome; restituisce comunque il parametro nella forma originale
EndFunction

Creare versioni personali delle funzioni native.

Nell’ottavo capitolo, analizzando il file script
Default.JSS
, avevamo fatto notare l’iniziale inclusione di numerosi file già compilati, con estensione
JSB
. Se ricordate, si tratta di file esterni che aumentano le funzionalità di Jaws, senza tuttavia appesantire il codice sorgente del file script Predefinito.

Sul piano pratico, il fatto che tali funzioni siano assenti dal codice del file script principale, ci consente di poterne modificare il funzionamento. In particolare, è possibile creare dentro a
Default.JSS
una funzione che ha lo stesso nome di una nativa, la quale una volta chiamata esegua prima delle nostre istruzioni, o dei nostri controlli, prima di chiamare casomai la funzione originale.

Nel nostro caso, la funzione integrata si chiama
GetScriptSynopsis ()
, già esaminata nell’ottavo capitolo, e che serve a rilevare il sommario del nome di script passato come suo unico parametro. Nel dettaglio, la nostra funzione, che proporremo subito dopo questa premessa, consente di far leggere l’alias di uno script a gestione personale, anziché il nome reale, che come detto non ci dice quale compito svolga.

Questo accorgimento, oltre a semplificare la gestione del codice, consente di poter inserirsi nell’Aiuto tastiera di Jaws, facendo pronunciare il sommario anche degli script a gestione personale, nonostante che tale informazione sia salvata su un nostro file di configurazione anziché sui normali file di documentazione con estensione
JSD.

Esercizio 11.3.22. La funzione GetScriptSynopsis.

FileScript.

Default.JSS

Nome.

GetScriptSynopsis

Descrizione.

Se il nome dello script passato come parametro è uno di quelli a gestione personale, allora legge il sommario inserito nei relativi dati. In tutti gli altri casi, restituisce il sommario impostato tramite la schermata di modifica nell’Editor di script.

Ritorni.

Di tipo String. Il sommario relativo allo script indicato.

Parametri.
  1. sNome. Il nome dello script di cui rilevare il sommario. Di tipo String.
Note.
  1. Nella chiamata della nostra funzione
    LeggeCampo ()
    , nel primo parametro viene specificata una stringa vuota affinché l’informazione sia letta dal file di configurazione dell’applicativo corrente.

Codice.


String Function GetScriptSynopsis (string sNome)
Var String sSuffisso; eventuale suffisso numerico degli script a gestione personale
If ScriptPersonale (sNome, sSuffisso) Then; se lo script è uno di quelli a gestione personale,
; estrae il sommario dello script dai corrispondenti dati per l’applicazione corrente
Return LeggeCampo (NULLO, PERSONALI, sSuffisso, TERZA)
Else; altrimenti, in tutti gli altri casi,
Return GetScriptSynopsis (sNome); restituisce il dato proveniente dalla funzione nativa
EndIf; fine controllo
EndFunction

Il sistema per individuare le serie di script.

Se si torna ad analizzare il funzionamento della precedente versione dell’Aiuto in linea, esso era abbastanza semplice:

  1. La funzione
    ComprimeDati ()
    acquisiva in modo univoco gli abbinamenti tra tasti di attivazione e nomi di script all’interno dei file tasti.
  2. Il codice dello script vero e proprio leggeva questi dati, inviandoli subito al Visualizzatore Virtuale opportunamente formattati.

Ora, invece, con l’avvento delle serie di script, non possiamo più consentire questa trascrizione in tempo reale. La soluzione adottata è quella di spostare le informazioni lette in un buffer di memoria temporanea, dove mantenere tali dati finché non si siano controllate anche le informazioni successive, verificandole che non appartengano a script in serie tra loro.

Di questo ,in particolare, si occupa la prossima funzione, dove i dati sono dunque analizzati in prevalenza a coppie. Potrete dunque trovare delle variabili con un nome normale, assieme a delle altre con lo stesso nome ed il prefisso
"buffer".

Esercizio 11.3.24. La funzione TrovaSerie.

FileScript.

Default.JSS

Nome.

TrovaSerie

Descrizione.

Controlla se due voci consecutive dell’Aiuto in linea appartengano alla stessa serie numerica.

Ritorni.

Di tipo Int. TRUE, nel caso le voci di script confrontate siano in serie; FALSE, qualora non lo siano.

Parametri.
  1. sBufferTasto. prima stringa della coppia iniziale da confrontare. Di tipo String.
  2. sBufferInfo. Primo termine della seconda coppia. Di tipo String.
  3. sTasto. L’altra stringa della coppia iniziale. Di tipo String.
  4. sInfo. L’altro termine della seconda coppia. Di tipo String.
  5. s1. Per Riferimento. Esito del confronto nella coppia iniziale. Di tipo String.
  6. s2. Per Riferimento. Esito del confronto nella seconda coppia. Di tipo String.
  7. iSerie. Per Riferimento. Stato delle serie rilevate. Di tipo Int.
Novità.
  1. La funzione integrata
    StringTrimCommon
    , (RimuoviDatoTestualeComune); “Se i due termini inseriti sono variabili, li confronta, trasmettendo per riferimento solo l’eventuale contenuto diverso tra le due variabili; ad esempio, se il contenuto della variabile posta come primo parametro è la stringa
    "Pippo1"
    , mentre nel secondo parametro la variabile idnicata equivale alla stringa
    "Pippo2"
    , la funzione restituirà
    "1"
    , come prima variabile, e
    "2"
    , come seconda; la funzione ha anche un terzo parametro opzionale, che serve ad indicare se considerare solo una delle due estremità delle stringhe confrontate, oppure entrambe, ma nel nostro caso non servirà specificarlo.
  2. La funzione integrata
    GetCharacterValue
    , (OttieniValoreCarattere); Restituisce il valore del codice Ascii del primo carattere nella stringa indicata nel suo unico parametro.
Note.
  1. La funzione compara tutti i dati, utilizzando tra le altre anche le funzioni integrate
    StringTrimCommon ()
    e
    GetCharacterValue ()
    ; di seguito, esegue una serie di controlli sul fatto che i dati controllati stiano ad indicare degli script in serie.
  2. Se così non è, alla prima condizione non vera viene restituito un risultato nullo; altrimenti, se tutti i controlli hanno avuto un riscontro positivo, viene restituito tale esito.

Codice.


Int Function TrovaSerie (string sBufferTasto, string sBufferInfo, ; prima riga con due parametri,
string sTasto, string sInfo, string ByRef s1, string ByRef s2, int ByRef iSerie); e seconda riga
Var Int i1
; salva la prima stringa nel parametro per riferimento, portandola in minuscolo
Let s1 = StringLower (sBufferTasto)
; salva in minuscolo la seconda stringa nel parametro
Let s2 = StringLower (sTasto)
; porta in minuscolo il primo testo della seconda coppia, rimuovendo eventuali caratteri Punto
Let sBufferInfo = StringReplaceSubstrings (StringLower (sBufferInfo), PUNTO, NULLO)
; confronta anche il secondo testo
Let sInfo = StringReplaceSubstrings (StringLower (sInfo), PUNTO, NULLO)
StringTrimCommon (s1, s2); confronta le combinazioni tasti
StringTrimCommon (sBufferInfo, sInfo); confronta le informazioni sugli script
Let i1 = GetCharacterValue (s1); memorizza il codice Ascii del primo carattere rilevato
; se la lunghezza del primo testo variabile è diversa da 1, o è diversa da quella del secondo carattere
If (StringLength (s1) != 1 || StringLength (s1) != StringLength (s2))
; se il primo carattere variabile è diverso dalla cifra 9, ma il secondo non ha un Ascii aumentato di 1,
|| (i1 != 57 && GetCharacterValue (s2) != (i1 + 1))
|| s1 != sBufferInfo ; infine, se i primi caratteri variabili delle due coppie sono diversi,
|| s2 != sInfo Then; oppure, lo sono i secondi caratteri variabili,
If iSerie Then; se la serie di voci era già stata individuata,
Let iSerie = 2; imposta il valore per lo svuotamento del buffer
EndIf; fine controllo stato delle serie
Return FALSE; restituisce un risultato nullo
Else; altrimenti, se il flusso ha superato tutti i controlli,
Return TRUE; restituisce l’esito positivo
EndIf; fine controllo differenze
EndFunction

Esercizio 11.3.25. La funzione TogliePunto.

FileScript.

Default.JSS

Nome.

TogliePunto

Descrizione.

Rimuove un’eventuale carattere Punto presente a fine stringa.

Ritorni.

Di tipo String. Il testo eventualmente ripulito del carattere Punto finale.

Parametri.
  1. sTesto. La stringa da controllare. Di tipo String.
Note.
  1. La funzione nasce dall’esigenza di evitare che, formattando del testo, si creino delle stringhe con due caratteri punto consecutivi, che sarebbero erroneamente pronunciati dalla sintesi.

Codice.


String Function TogliePunto (string sTesto)
Let sTesto = StringTrimTrailingBlanks (sTesto); rimuove eventuali spazi finali
If StringRight (sTesto, 1) == PUNTO Then; se l’ultimo carattere è un Punto fermo,
Return StringTrimTrailingBlanks (StringChopRight (sTesto, 1)); restituisce la stringa senza
Else; altrimenti,
Return sTesto; restituisce la stringa originale, ma almeno ripulita degli spazi finali
EndIf; fine controllo carattere finale
EndFunction

Esercizio 11.3.26. La funzione ToglieUltimo.

FileScript.

Default.JSS

Nome.

ToglieUltimo

Descrizione.

Rimuove l’ultimo carattere da una stringa, assieme ad un eventuale carattere Punto che preceda quelli alfanumerici.

Ritorni.

Di tipo String. La stringa privata degli ultimi caratteri.

Parametri.
  1. sTesto. La stringa da elaborare. Di tipo String.
Novità.
  1. La nostra funzione
    TogliePunto ().
Note.
  1. In maniera analoga alla precedente, qui viene rimosso l’ultimo carattere da una stringa, badando che si tratti ad esempio del suffisso numerico di uno script in serie, e non di un carattere Punto, in quest’ultimo caso chiamando la nostra funzione
    TogliePunto ().

Codice.


String Function ToglieUltimo (string sTesto)
; restituisce la stringa senza l’ultimo carattere, al netto di eventuali punti finali
Return StringChopRight (TogliePunto (sTesto), 1)
EndFunction

Esercizio 11.3.27. La funzione AggiornaVisualizzatore.

FileScript.

Default.JSS

Nome.

AggiornaVisualizzatore

Descrizione.

Gestisce l’invio delle voci dell’Aiuto in linea al Visualizzatore Virtuale, differenziandole tra le voci normali e quelle delle serie di script.

Ritorni.

Di tipo Void. Nessuno.

Parametri.
  1. sTasto. La combinazione tasti che attiva lo script. Di tipo String.
  2. sNome. Il nome dello script elaborato. Di tipo String.
  3. sAlias. La versione virtuale del nome dello script. Di tipo String.
  4. sInfo. Le informazioni raccolte. Di tipo String.
  5. sPrimo. Il primo carattere variabile rilevato. Di tipo String. Parametro Opzionale.
  6. sUltimo. L’ultimo carattere variabile rilevato. Di tipo String. Parametro Opzionale.
Novità.
  1. La nostra funzione
    ToglieUltimo ().
Note.
  1. La funzione, dotata di un’unica struttura di controllo, smista le due diverse modalità di formattazione in base al fatto che si debbano riportare le informazioni su script singoli oppure in serie, servendosi appunto anche della nostra funzione
    ToglieUltimo ().

Codice.


Void Function AggiornaVisualizzatore (string sTasto, string sNome, ; riga con i primi due,
string sAlias, string sInfo, string sPrimo, string sUltimo); seconda riga con gli altri quattro
If !sPrimo Then; se si stanno aggiornando le normali voci,
UserBufferAddText ( ; compone la riga d’informazioni, comprensiva del link,
FormatString (hlpInfoScript, sInfo, sTasto), ; formatta il testo da visualizzare,
FormatString (hlpInfoLink, sNome), ; formatta anche il comando da eseguire,
sAlias); e aggiunge il nome virtuale per l’elenco dei link
Else; altrimenti, per le serie di voci,
UserBufferAddText ( ; compone la riga d’informazioni, formattando i caratteri variabili
FormatString (hlpInfoSerie, ToglieUltimo (sInfo), ToglieUltimo (sTasto), sPrimo, sUltimo))
EndIf; fine controllo parametri
EndFunction

Collaudo.

  1. Dopo aver correttamente compilato, s’invita a rendere opzionali gli ultimi due parametri della funzione, ponendo l’apposita stringa tra il quarto ed il quinto parametro.

Esercizio 11.3.28. La funzione AggiungePunto.

FileScript.

Default.JSS

Nome.

AggiungePunto

Descrizione.

Aggiunge un carattere Punto al termine della stringa indicata, solo nel caso non ci sia già.

Ritorni.

Di tipo String. La stringa eventualmente completata.

Parametri.
  1. sTesto. Per Riferimento. La stringa da controllare. Di tipo String.

Codice.


String Function AggiungePunto (string ByRef sTesto)
Let sTesto = StringTrimTrailingBlanks (sTesto); toglie eventuali spazi finali alla riga
If StringRight (sTesto, 1) != PUNTO Then; se l’ultimo carattere della stringa non è un punto,
Return sTesto + PUNTO; la restituisce aggiungendolo
Else; altrimenti,
Return sTesto; restituisce la forma originale
EndIf; fine controllo carattere finale
EndFunction

Esercizio 11.3.29. La nuova versione di AiutoInLinea ().

FileScript.

Default.JSS

Nome.

AiutoInLinea

Novità.
  1. Le nostre funzioni
    ComponeAiuto (),
    ImpostaNomi (),
    TrovaSerie (),
    AggiornaVisualizzatore ()
    e
    AggiungePunto ().
  2. La funzione integrata
    InHJDialog
    , (DentroFinestraDialogoDiJaws); Restituisce un valore positivo se si esegue uno script, o si chiama una funzione, quando è già aperta una finestra di dialogo di Jaws. Senza parametri.
  3. La nostra versione di
    GetScriptSynopsis ()
    , che serve a fornire il sommario anche nei nostri script a gestione personale.
Note.
  1. Le differenze tra le due versioni sono così numerose che conviene riscrivere da zero il codice. In particolare, sono state aggiunte varie fasi, la prima delle quali serve a decidere, sulla base del fatto che si sia dentro una finestra di dialogo di Jaws, e che siano impostate delle variabili globali, se si debba attivare l’Aiuto tradizionale oppure quello che prende le informazioni dai tasti attivi; nel dettaglio, qui sono coinvolte la nostra funzione
    ComponeAiuto ()
    e quella nativa
    InHJDialog ().
  2. La seconda struttura di controllo determina, verificando se ci si trovi nell’Editor di Script, se visualizzare eventuali script per l’applicativo corrente, oppure soltanto quelli del file script predefinito.
  3. I due cicli, quello che scorre i diversi archivi e quello che analizza le informazioni degli script, hanno un comportamento simile alla versione precedente, almeno finché si arriva al momento di inviare i dati al Visualizzatore Virtuale; qui sono utilizzate anche la nostra funzione
    ImpostaNomi ()
    , e quella con il nome nativo da noi aggiornata,
    GetScriptSynopsis ()
    , oltre a trarre l’elenco delle sezioni del file tasti dalla nostra apposita funzione.
  4. Come accennato in precedenza, gli aggiornamenti nel codice prevedono dei controlli sui singoli dati, verificando se lo script analizzato al momento è in serie rispetto all’ultimo registrato, grazie alla nostra
    TrovaSerie ()
    . A tal fine, si utilizzano, come detto, delle coppie di variabili, dove quella con il prefisso
    buffer
    è relativa al penultimo script, mentre le variabili con il nome normale sono quelle dello script corrente.
  5. In ogni caso, durante la scansione delle sezioni e delle chiavi, qualora lo script corrente non fosse individuato come in serie al penultimo analizzato, saranno i dati di quest’ultimo ad essere salvati, mentre quelli correnti andranno ad aggiornare le variabili che costituiscono il buffer di memoria; in ogni caso, ad occuparsi di queste trascrizioni sarà la nostra funzione
    AggiornaVisualizzatore ()
    , la quale a sua volta utilizza anche l’altra nostra funzione,
    AggiungePunto ().
  6. Al termine dei cicli, si svuota comunque il buffer di memoria, trascrivendo gli ultimi dati che non erano ancora stati inviati al Visualizzatore Virtuale, singoli o in serie che fossero.
  7. Così come nella precedente versione, alla fine si formattano ed inviano i messaggi predefiniti di chiusura schermata informativa, e si avvia la pronuncia del suo contenuto.

Codice.


Script AiutoInLinea ()
Var
Int j, ; contatore del ciclo primario
Int iStart, ; valore iniziale del ciclo
Int k, ; contatore del secondo ciclo
String sFile, ; file tasti da elaborare
String sTitolo, ; titolo per inizio informazioni
String sPrimi, ; elenco iniziale dei tasti
String sChiavi, ; elenco combinazioni tasti rilevate
String sDati, ; nomi di script abbinati ai tasti
String sTasto, ; singola combinazione tasti che funge da chiave
String sNome, ; singolo script abbinato
String sInfo, ; informazioni da visualizzare
String sAlias, ; nome alternativo dello script
Int iSerie, ; indica una serie avviata
String sBufferTasto, ; stringa registrata delle combinazioni tasti
String sBufferNome, ; stringa registrata del nome di script
String sBufferAlias, ; stringa registrata con l’alias dello script
String sBufferInfo, ; stringa registrata delle informazioni sugli script
String s1, ; primo carattere variabile
String s2, ; ultimo carattere variabile
String sPrimoDiverso, ; carattere variabile iniziale della serie
String sUltimoDiverso; carattere variabile finale della serie
EnsureNoUserBufferActive (); chiude eventuali schermate del Visualizzatore Virtuale
If InHJDialog () Then; se si è in una procedura Jaws,
If !gsTitolo ; se nessun titolo è registrato per la finestra corrente,
|| !gsEtichette Then; oppure, se non ci sono pulsanti di scelta,
SayMessage (OT_ERROR, hlpNoInLinea, hlpNoInLinea_corto); pronuncia l’avviso,
Return; e interrompe il flusso
Else; altrimenti,
ComponeAiuto (); crea e visualizza le informazioni di contesto,
Return; e interrompe il flusso
EndIf; fine controllo titolo
EndIf; fine controllo tipo finestra
If ApplicativoCorrente () != JAWS_FILE Then; se non si è nell’Editor di Script
Let iStart = APP; imposta di iniziare dal file tasti dell’applicativo corrente
Else; altrimenti,
Let iStart = JAWS; riduce la scansione al solo file tasti predefinito
EndIf; fine controllo valore iniziale
For j = iStart To JAWS; scorre i tipi di file tasti
Let sFile = NomeArchivio (j); imposta il nome del file tasti da elaborare
; crea gli elenchi leggendo dalle sezioni del file tasti da elaborare
If ComprimeDati (sFile, ElencoSezioni (), sChiavi, sDati) Then; se dei tasti sono stati rilevati,
If j == APP Then; se si sta elaborando il file tasti dell’applicazione corrente,
; formatta il titolo dell’Aiuto con il nome dell’applicativo
Let sTitolo = FormatString (hlpInfoApp, GetActiveConfiguration ())
Let sPrimi = sChiavi; registra il primo elenco di tasti
ElIf j == JAWS Then; se si sta invece elaborando il file tasti predefinito,
Let sTitolo = hlpInfoJaws; imposta il relativo titolo per l’Aiuto
If UserBufferGetLength ()Then; se nel Visualizzatore Virtuale è presente del testo,
UserBufferAddText (FormatString (msgTraVuote, sTitolo)); inizializza la seconda parte
EndIf; fine controllo testo Aiuto
EndIf; fine controllo passaggi
For k = 1 To StringSegmentCount (sChiavi, PIPE); scorre le combinazioni tasti rilevate
Let sTasto = StringSegment (sChiavi, PIPE, k); estrae la combinazione tasti da verificare
If j == APP ; se si è al primo passaggio,
|| !StringSegmentIndex (sPrimi, PIPE, sTasto, TRUE) Then; o, se i tasti non ci sono già,
If !UserBufferGetLength ()Then; se il Visualizzatore Virtuale è è vuoto,
UserBufferAddText (sTitolo + LF); lo inizializza con l’apposito titolo
EndIf; fine controllo creazione testo
If sTasto != GetCurrentScriptKeyName () Then; se i tasti non sono quelli di attivazione,
; memorizza il nome reale dello script abbinato, e dell’alias proposto nelle informazioni
Let sNome = ImpostaNomi (StringSegment (sDati, PIPE, k), sAlias)
; legge il sommario, tramite la nostra funzione creata con il nome di quella nativa
Let sInfo = GetScriptSynopsis (sNome)
If !sInfo Then; se nessuna informazione è stata rilevata,
Let sInfo = sAlias; usa come informazione il nome assegnato allo script
EndIf; fine controllo presenza informazioni
If !TrovaSerie (sBufferTasto, sBufferInfo, sTasto, sInfo, s1, s2, iSerie) ; se le ultime due voci non sono in serie,
&& !iSerie Then; e una serie non è già stata rilevata,
If sBufferTasto Then; se i dati dello script precedente sono stati rilevati,
AggiornaVisualizzatore (sBufferTasto, sBufferNome, sBufferAlias, sBufferInfo, NULLO, NULLO)
EndIf; fine controllo presenza buffer
Else; altrimenti, se una serie è stata rilevata,
If !iSerie Then; se si è all’avvio della serie,
Let sPrimoDiverso = StringUpper (s1); memorizza il primo carattere diverso della serie, portandolo i maiuscolo qualora sia una lettera,
Let iSerie = TRUE; e ne annota l’avvio
ElIf iSerie == 1 Then; se invece la serie continua,
Let sUltimoDiverso = StringUpper (s2); annota l’ultimo carattere, portandolo i maiuscolo qualora sia una lettera
Else; altrimenti, se una serie si conclude,
AggiornaVisualizzatore (sBufferTasto, NULLO, NULLO, sBufferInfo, sPrimoDiverso, sUltimoDiverso)
Let iSerie = FALSE; annulla il valore
EndIf; fine controllo serie attiva
EndIf; fine controllo presenza serie
; aggiorna i dati memorizzati per:
Let sBufferTasto = sTasto; combinazione tasti
Let sBufferNome = sNome; nome dello script
Let sBufferAlias = sAlias; alias dello script
Let sBufferInfo = AggiungePunto (sInfo); informazioni sullo script
EndIf; fine controllo tasti validi
EndIf; fine controllo tasti già elaborati
EndFor; fine ciclo scorrimento chiavi
If !iSerie Then; se non è attiva alcuna serie,
AggiornaVisualizzatore (sBufferTasto, sBufferNome, sBufferAlias, sBufferInfo, NULLO, NULLO); trascrive l’ultima voce
Else; altrimenti,
AggiornaVisualizzatore (sBufferTasto, NULLO, NULLO, sBufferInfo, sPrimoDiverso, sUltimoDiverso); annota l’ultima serie,
Let iSerie = FALSE; e ne annulla il valore
EndIf; fine controllo attivazione serie
Let sBufferTasto = NULLO; resetta il dato, per il successivo inizio
EndIf; fine controllo presenza chiavi
EndFor; fine ciclo scorrimento file
If UserBufferGetLength ()Then; se nel Visualizzatore Virtuale è presente del testo,
UserBufferActivate (); visualizza la schermata d’informazioni,
; quindi, prima formatta un testo con i tasti dello script chiamante e la formula di chiusura,
Let sInfo = FormatString (hlpUltimaInfo, GetCurrentScriptKeyName (), hlpFineInfo);
; poi, la trasmette al Buffer, avviandone la lettura.
RedirectToUserBuffer (sInfo)
EndIf; fine controllo presenza testo
EndScript

Collaudo.

  1. In questo caso, se la compilazione riesce, il collaudo può anche limitarsi al premere i tasti di attivazione,
    Insert+H
    , da dentro una qualsiasi applicazione per i quali esistano dei nostri script.
  2. Se così si facesse, per il momento non dovrebbe essere cambiato nulla rispetto al numero ed al tipo di informazioni prodotte dal nostro Aiuto.
  3. Più avanti, quando appronteremo le diverse procedure guidate, sarà possibile completare questo collaudo, sperimentando l’Aiuto sensibile al contesto da noi già predisposto in questo capitolo.

***

Riepilogo.

Analizzando quanto sin qui fatto, dal primo al terzo capitolo abbiamo proposto una sorta di introduzione agli script, senza nemmeno sapere cosa fossero ad esempio le variabili. Dal quarto al decimo capitolo, in modo progressivo, ci siamo sempre più addentrati nei molti aspetti da conoscere sul funzionamento di Jaws, e sul modo migliore per realizzarne efficaci script.

A partire da questo capitolo, e sino al termine di quest’opera divulgativa, ci spingeremo anche un po’ oltre i limiti degli script per Jaws, sconfinando in un territorio certamente più adatto alla programmazione vera e propria. Ma tant’è, qui siamo arrivati, e ormai siamo in ballo: non ci resta che ballare sino in fondo!

Questo capitolo, in particolare, l’abbiamo iniziato con un argomento che ha fatto un po’ da ponte tra la precedente e l’attuale parte delle nostre fatiche, come quello della serie di script applicato ai contrassegni numerati. Già aumentando le funzionalità dell’Aiuto in linea abbiamo compiuto un passo in più, anche se ci siamo limitati a gettare le basi per un qualcosa che potremo apprezzare solo quando tutti i pezzi delle nostre procedure saranno completati.

Alla fine del prossimo capitolo, in ogni caso, saremo in grado di effettuare delle ricerche rapide di stringhe testuali predeterminate, attivabili con la pressione di combinazioni tasti. A tal fine, realizzeremo uno strumento di ricerca che scorrerà i nostri documenti, tentando il più possibile di farlo allo stesso modo in tutti gli applicativi di nostro interesse.

Download

File script da scaricare, per gli utenti di Jaws fino alla versione 18
Archivio da scaricare, per gli utenti dalla versione 2018 in poi

Per ulteriori spiegazioni, scrivere a:

Abramo Volpato