Gli script di Jaws 09. Documento Corrente e Barra di Stato.

Programmiamoli da Soli!

Facciamo un po’ d’ordine!

Fin dall’inizio queste pagine dedicate agli Script per Jaws erano state caratterizzate

da una didattica progressiva, con versioni spesso provvisorie degli elementi di codice per renderli più facilmente comprensibili. Ora, finalmente, le nozioni teoriche si sono pressoché concluse, e a partire da questo capitolo ci dedicheremo a riprendere e concludere tutti i discorsi avviati.

Inizieremo col riproporre le funzioni di lettura e scrittura sui file in formato INI, che saranno appunto realizzate nella loro versione definitiva. Appronteremo poi una importante procedura, che serve a rilevare nome ed estensione dei documenti aperti nei vari applicativi.

Proseguiremo poi con una semplice ma efficace funzione per gestire lo spegnimento e la riattivazione della voce di Jaws, in modo sensibile al contesto. La restante parte del capitolo sarà infine dedicata ad un diverso sistema di gestire l’elaborazione dei dati, una novità importante che segnerà l’evoluzione del nostro lavoro da qui in avanti.

A dire la verità, qui almeno nel metodo torneremo un po’ indietro, poiché in particolare una funzione sarà proposta in una versione solo parziale. Essa rappresenterà, tuttavia, la classica eccezione che conferma la regola, e sarà aggiornata nei prossimi capitoli man mano che affronteremo i vari argomenti.

Per fare un primo esempio di questo nuovo sistema, realizzeremo un’interessante procedura che consentirà la lettura configurabile dei dati nella Barra di stato. Ora, come al solito, iniziamo però dai nostri file esterni.

Esercizio 9.1.1. Aggiornare il file Personale delle Costanti.


SECONDA = 2, ; valore per seconda scelta
PRIMA = 1, ; valore per prima scelta
DATI_FILE = "DatiFile", ; etichetta di sezione per la ricerca del nome file nel titolo
AIUTO = "Aiuto", ; termine omonimo
TERZA = 3, ; valore per terza scelta
SEPARA_NOME = " - ", ; separatore tra i nomi del documento e dell’applicativo correnti
TITOLO = "Titolo", ; termine omonimo
CONTROBARRA = "\\", ; carattere Controbarra, Ascii 92
BARRA = "/", ; carattere omonimo
DUE_PUNTI = ":", ; carattere omonimo
ULTIMA = -1, ; valore negativo che indica l’ultima scelta in una serie di voci
QUADRA_APERTA = "[", ; carattere omonimo
QUADRA_CHIUSA = "]", ; carattere omonimo
ZERO = "0", ; cifra omonima in forma testuale
SPACE = " ", ; carattere Spazio
DIVIDE_ZONE = ":", ; carattere di separazione standard per il testo nella barra di stato
BARRA_STATO = "BarraStato", ; etichetta di sezione negli archivi delle applicazioni
SEPARATORE = "Separatore", ; termine omonimo
TESTO = "Testo", ; termine omonimo
OK = 1, ;tipo omonimo di finestra di dialogo
OK_ANNULLA = 2, ; tipo omonimo di finestra di dialogo
INTERROMPI_RIPROVA_IGNORA = 3, ; tipo omonimo di finestra di dialogo
SI_NO_ANNULLA = 4, ; tipo omonimo di finestra di dialogo
SI_NO = 5, ; tipo omonimo di finestra di dialogo
RIPROVA_ANNULLA = 6, ; tipo omonimo di finestra di dialogo
BASE_ZONE = 2, ; valore da aggiungere per individuare la zona nella barra di stato
_O = "o", ; carattere omonimo
CICLO_VOCI = 3, ; numero delle voci per l’estrazione dei dati nella barra di stato
PRONUNCIA = "Pronuncia", ; termine omonimo
STATO = "Stato", ; termine omonimo
DATO = "Dato", ; termine omonimo

Esercizio 9.1.2. Aggiornare il file Personale dei Messaggi.


; Annullata la Fase Aiuto
@hlpNoAiuto
Fase Aiuto annullata per l’applicativo corrente.
@@
; Annullata la Fase Aiuto - versione corta
@hlpNoAiuto_corto
Fase Aiuto annullata.
@@
; Elenco delle voci per la scelta della porzione del titolo dove si trova un NomeFile
@lstParti
%1|%2|Non chiedermelo più
@@
; titolo per la scelta della porzione del titolo dove si trova un NomeFile
@ttlParti
Confermare quale parte contenga il NomeFile
@@
; un termine tra virgolette
@msgVirgolette
"%1"
@@
; nessun dato rilevato nell’elemento elaborato
@hlpNoDato
Nessun dato rilevato %1.
@@
; nessun dato rilevato nell’elemento elaborato - versione corta
@hlpNoDato_corto
Nessun dato.
@@
; suffisso per titolo del documento
@msgTitolo
nel titolo
@@
; due termini separati da una virgola
@msg2Virgola
%1, %2
@@
; controllo sull’attivazione della barra di stato
@hlpAttivaBarra
Barra di stato vuota. Controllare la sua attivazione nelle impostazioni.
@@
; controllo sull’attivazione della barra di stato - versione corta
@hlpAttivaBarra_corto
Controllare che la barra sia attivata.
@@
; titolo per carattere di separazione nella barra di stato mancante
@ttlNoSepara
Nessun separatore rilevato nella barra di stato.
@@
; conferma all’immissione di dati
@msgImmissione
Immetterl%1 ora?
@@
; immissione del separatore dei termini nella Barra di Stato
@ttlSeparatore
Immettere il carattere di separazione.
@@
; dati della barra di stato non rilevati automaticamente
@hlpNoAutoDati
Impossibile leggere Dati nella barra di stato in modo automatico.
@@
; dati della barra di stato non rilevati automaticamente - versione corta
@hlpNoAutoDati_corto
Dati non rilevati in modo automatico.
@@
; riferimento sulla posizione non corretto
@hlpInfoErrate
Posizione indicata non corretta.
@@
; riferimento sulla posizione non corretto - versione corta
@hlpInfoErrate_corto
Posizione errata.
@@
; un termine
@msg1
%1
@@

***

Generalizziamo le funzioni di lettura e scrittura.

Nel capitolo 6, creando il cuore per la procedura sulle finestre, avevamo conosciuto le quattro principali funzioni che Jaws mette a disposizione per scrivere e leggere i dati sui file in formato
INI
. Per semplificare il lavoro di allora, avevamo creato delle nostre funzioni che contenevano la maggior parte dei dati già preimpostati al loro interno, e per questo potevano valere solo per quel tipo di procedura.

Ora, invece, abbiamo bisogno di funzioni più versatili, che rendano più leggibile il codice e più facile per noi scriverlo, ma che possano adattarsi a tutte le nuove esigenze. Per questo conviene rifare le funzioni da zero, anziché copiare le precedenti versioni ed aggiornarle, perché la schermata di modifica degli elementi di codice non consente, ad esempio, di variare l’ordine o aggiornare la descrizione dei parametri.

Esercizio 9.2.1. La funzione ScriveValore.

FileScript.

Default.JSS

Nome.

ScriveValore

Descrizione.

Trascrive il valore numerico specificato in un archivio di cui si indichi il tipo, oltre che la sezione e la chiave del dato. Se il quinto parametro è presente, ed ha un valore positivo, legge anche i messaggi con l’esito della scrittura.

Ritorni.

Di tipo Int. L’esito della funzione: TRUE per la riuscita, FALSE per il fallimento.

Parametri.
  1. iTipo. Il valore che identifica il tipo di archivio da elaborare. Di tipo Int.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del dato. Di tipo String.
  4. iValore. Il dato da scrivere. Di tipo Int.
  5. iAiuto. Se positivo, indica l’attivazione dell’omonima fase, che in questo caso legge i messaggi. Di tipo Int. Parametro Opzionale.
Fasi.
  1. Salva il nome dell’archivio, tramite la chiamata dell’apposita funzione.
  2. Tenta di scrivere il dato, restituendo il valore numerico dell’esito.
  3. Se il quinto parametro opzionale è positivo, legge un messaggio con l’esito.
  4. In ogni caso, restituisce il valore dell’esito, TRUE o FALSE.

Codice.


Int Function ScriveValore (int iTipo, string sSezione, string sChiave, int iValore, int iAiuto)
Var String sArchivio; il nome dell’archivio in cui scrivere
Let sArchivio = NomeArchivio (iTipo); ricava il nome dell’archivio dall’apposita funzione
; Tenta di scrivere il valore numerico nell’archivio del tipo specificato
If IniWriteInteger (sSezione, sChiave, iValore, sArchivio) Then; se la scrittura riesce,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayFormattedMessage (OT_ERROR, hlpScritturaOk, hlpScritturaOk_corto, sArchivio)
EndIf; fine controllo Aiuto
Return TRUE; in ogni caso, restituisce l’esito positivo
Else; altrimenti, se la scrittura fallisce,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayFormattedMessage (OT_ERROR, hlpNoScrittura, hlpNoScrittura_corto, sArchivio)
EndIf; fine controllo Aiuto
Return FALSE; in ogni caso, restituisce un risultato nullo
EndIf; fine controllo esito
EndFunction

Collaudo.

Dato che si tratta di un nuovo elemento, provate a compilare. Essendoci un parametro opzionale , ci si dovrebbe portare nel file Documentazione per inserire manualmente la parola chiave relativa, ma di questa incombenza ci faremo carico solo al collaudo dell’ultima funzione di questo gruppo.

Esercizio 9.2.2. La funzione LeggeValore.

FileScript.

Default.JSS

Nome.

LeggeValore

Descrizione.

Legge il valore registrato nell’archivio del tipo indicato, dalla sezione e con la chiave specificate come parametri.

Ritorni.

Di tipo Int. Il valore letto dall’archivio specificato.

Parametri.
  1. iTipo. Il valore che identifica il tipo di archivio da elaborare. Di tipo Int.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del dato. Di tipo String.
Note.

I parametri da indicare sono tre perché il quarto, la costante da restituire in caso di mancata lettura, viene preimpostato

Codice.


Int Function LeggeValore (int iTipo, string sSezione, string sChiave)
; restituisce il valore numerico memorizzato nell’archivio del tipo indicato
Return IniReadInteger (sSezione, sChiave, FALSE, NomeArchivio (iTipo))
EndFunction

Esercizio 9.2.3. La funzione ScriveDato.

FileScript.

Default.JSS

Nome.

ScriveDato

Descrizione.

Trascrive il dato testuale specificato in un archivio di cui si indichi il tipo, oltre che la sezione e la chiave del dato. Se il quinto parametro è presente, ed ha un valore positivo, legge anche i messaggi con l’esito della scrittura.

Ritorni.

Di tipo Int. L’esito della funzione: TRUE per la riuscita, FALSE per il fallimento.

Parametri.
  1. iTipo. Il valore che identifica il tipo di archivio da elaborare. Di tipo Int.
  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.
  5. iAiuto. Se positivo, indica l’attivazione dell’omonima fase, che in questo caso legge i messaggi. Di tipo Int. Parametro Opzionale.
Note.

Le fasi di questa funzione sono le stesse di quella del punto 9.2.1. Con la sola differenza che ad essere trattato è stavolta un dato testuale, non un valore numerico.

Codice.


Int Function ScriveDato (int iTipo, string sSezione, string sChiave, string sDato, int iAiuto)
Var String sArchivio; il nome dell’archivio in cui scrivere
Let sArchivio = NomeArchivio (iTipo); ricava il nome dell’archivio dall’apposita funzione
; Tenta di scrivere il dato testuale nell’archivio del tipo indicato
If IniWriteString (sSezione, sChiave, sDato, sArchivio) Then; se la scrittura riesce,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayFormattedMessage (OT_ERROR, hlpScritturaOk, hlpScritturaOk_corto, sArchivio)
EndIf; fine controllo Aiuto
Return TRUE; in ogni caso, restituisce l’esito positivo
Else; altrimenti,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayFormattedMessage (OT_ERROR, hlpNoScrittura, hlpNoScrittura_corto, sArchivio)
EndIf; fine controllo Aiuto
Return FALSE; in ogni caso, restituisce un risultato nullo
EndIf; fine controllo esito
EndFunction

Esercizio 9.2.4. La funzione LeggeDato.

FileScript.

Default.JSS

Nome.

LeggeDato

Descrizione.

Legge il dato testuale registrato nell’archivio del tipo indicato, dalla sezione e con la chiave specificate come parametri.

Ritorni.

Di tipo String. Il dato registrato nell’archivio specificato.

Parametri.
  1. iTipo. Il valore che identifica il tipo di archivio da elaborare. Di tipo Int.
  2. sSezione. La sezione dell’archivio in cui operare. Di tipo String.
  3. sChiave. La chiave del dato. Di tipo String.

Codice.


String Function LeggeDato (int iTipo, string sSezione, string sChiave)
; restituisce il dato testuale memorizzato nell’archivio del tipo indicato
Return IniReadString (sSezione, sChiave, NULLO, NomeArchivio (iTipo))
EndFunction

Collaudo.

Giunti all’ultima funzione del gruppo, come promesso, non ci possiamo occupare del collaudo vero e proprio, bensì delle modifiche da apportare per rendere opzionali gli ultimi parametri delle due funzioni di scrittura.

Nel dettaglio, seguite questi passi:

  1. Aprite il file di Documentazione
    Default.JSD
    , e cercate il nome della prima funzione,
    ScriveValore.
  2. Portatevi sull’ultimo parametro descritto, ed inserite la solita iscrizione:
  3. 
    :Optional
    

  4. Cercate ora il nome dell’altra funzione,
    ScriveDato
    , ed inserite anche lì la citata parola chiave nella riga prima dell’ultimo parametro.
  5. Chiudete il file di Documentazione con
    Control+F4
    , tornando all’Editor, dove provate a compilare. Se non ci sono problemi, ricordiamo che conviene a questo punto uscire dall’Editor di Script per poi rientrarvi, così da rendere effettive le modifiche effettuate sui parametri opzionali.

***

Nome ed estensione del documento corrente.

Nello scorso capitolo, avevamo approntato la procedura per il ritorno all’ultima riga memorizzata in un file, applicandola al solo Blocco Note. Se ricordate, nelle Conclusioni del capitolo, avevamo accennato al fatto che il sistema adottato aveva però dei difetti, il principale dei quali era di non legare al nome del documento, aperto in quel momento, il valore memorizzato come ultima riga.

Come al solito, Jaws conosce benissimo il nome del file aperto in un applicativo, attraverso una serie di funzioni che però noi invece non conosciamo del tutto, e che comunque faremo fatica ad inserire in modo lineare nei nostri script. Per questo, lo scopo di questa serie di nostre funzioni è, appunto, restituirci in modo semplice il nome, e casomai l’estensione, del documento aperto in un applicativo.

Ovviamente, si farà largo uso delle funzioni native di Jaws, soprattutto di quella principale che ci fornirà i dati necessari, anche se ciascun applicativo ha un proprio modo di proporli. Per questo, il nostro sforzo sarà quello di creare una procedura che si adatti al maggior numero possibile di applicativi, la quale tenti di interpretare i dati rilevati, e prevedendo un’eventuale fase interattiva nel caso in cui tali dati non siano riconosciuti con esattezza.

Quelle da realizzare, in almeno due casi su tre, sono funzioni abbastanza corpose, ma che in realtà non hanno niente di troppo complicato. La loro lunghezza è data soprattutto dalla serie di verifiche e controlli che le compongono, le quali tentano di interpretare i dati rilevati nel modo più automatico possibile.

Questa procedura sarà la base su cui si svilupperanno gran parte degli script realizzati a partire dal prossimo capitolo, dove sarà indispensabile sapere quale sia il documento aperto su cui agire, o anche semplicemente quale sia la sua estensione.

Esercizio 9.3.1. La funzione NomeNelTitolo.

FileScript.

Default.JSS

Nome.

NomeNelTitolo

Descrizione.

Tenta di individuare il nome del documento corrente all’interno dei due dati passati come parametri. Se lo trova, oltre a restituirlo, salva il restante dato per evitare le successive chiamate della funzione, oppure l’annullamento degli effetti della fase Aiuto quando questa viene invocata.

Ritorni.

Di tipo String. Il nome del documento corrente.

Parametri.
  1. sPrima. La parte iniziale del titolo della finestra corrente. Di tipo String.
  2. sDopo. La seconda parte del titolo della finestra. Di tipo String.
  3. iAiuto. Se positivo, indica l’attivazione dell’omonima fase. In questo caso, oltre a far pronunciare eventuali messaggi, abilita la modalità interattiva per determinare quale sia, tra i dati rilevati, quello relativo al nome del documento. Di tipo Int.
Novità.
  1. La funzione integrata
    StringLower
    , (DatoTestualeMinuscolo), che porta in caratteri tutti minuscoli il testo passato come parametro.
  2. Le nostre funzioni
    LeggeDato
    e
    ScriveDato
    , alla loro prima chiamata.
  3. Le costanti
    DATI_FILE,
    TITOLO
    e
    AIUTO
    , che equivalgono tutte al termine omonimo. Nel dettaglio, la prima di queste è il nome della sezione in cui scrivere i dati, mentre le altre due sono dei nomi di chiavi per annotare le relative impostazioni.
  4. Le costanti numeriche
    PRIMA,
    SECONDA
    e
    TERZA
    , che corrispondono ai valori 1, 2 e 3.
  5. La costante
    SEPARA_NOME
    , che contiene i caratteri che separano il nome del file da quello dell’applicativo nel titolo del documento corrente.
Fasi.
  1. In una prima struttura annidata di controlli, si verifica dapprima se l’etichetta dell’applicativo corrente sia presente, nei dati passati come parametri. Poi, si controlla casomai se in tali dati sia presente un carattere Punto, il quale può rivelare la posizione di un’estensione di file. In caso positivo di una delle due verifiche, viene impostato un valore che identifica quale sia la parte contenente il dato interessato.
  2. Nel caso in cui i primi due controlli non abbiano dato alcun esito, la struttura verifica innanzi tutto se sia stata richiesta la fase Aiuto. Nel caso in cui quest’ultima sia stata comunque disabilitata in precedenza tramite la finestra di dialogo interattiva, viene letto l’apposito avviso ed interrotto il flusso.
  3. Sempre nella condizione contemplata al punto precedente, con nessun dato rilevato e la fase di Aiuto richiesta, se questa risulta ancora attiva, viene proposta una finestra di scelta dove poter confermare direttamente in quale posizione nel titolo sia posto il nome del documento. Sarà anche possibile annullare i successivi controlli di questo tipo, selezionando la voce
    "Non chiedermelo più"
    , ed in tal caso salvando nel file configurazione tale scelta. Solo in quest’ultimo caso, il flusso sarà interrotto, restituendo una stringa vuota.
  4. In una terza struttura di controllo, qualora non sia stata individuata la parte del dato dove si trovi il nome del documento aperto, il flusso viene interrotto restituendo una stringa vuota.
  5. Se invece i dati appena citati sono stati definiti, il flusso prosegue impostando sia il nome rilevato del documento, sia il contenuto dell’altra parte del dato, corrispondente di solito ad un nome che identifica l’applicativo aperto. Quest’ultimo sarà quindi salvato nell’archivio dell’applicativo corrente, mentre il primo verrà invece restituito come risultato della funzione, interrompendo il flusso.
Note.
  1. Come anticipato negli scopi, tale funzione dovrebbe essere di norma chiamata solo una volta per ciascun applicativo, in quanto il suo fine principale è quello di salvare le impostazioni che la rendano inutile. Come analizzeremo più avanti, infatti, quando i dati prodotti dalla funzione sono salvati, la funzione chiamante andrà a leggere tali dati anziché chiamare nuovamente la funzione.
  2. Da notare, nella formattazione del dato da scrivere per salvare il titolo dell’applicativo rilevato, l’utilizzo del messaggio
    msgVirgolette
    , impostato come gli altri ad inizio capitolo, il quale consente appunto di racchiudere il testo passato come parametro in un dato tra virgolette, così consentendo di mantenere anche eventuali spazi iniziali e finali che tale dato potrebbe avere.

Codice.


String Function NomeNelTitolo (string sPrima, string sDopo, int iAiuto)
Var
String sAttiva, ; nome dell’applicazione corrente
Int iParte, ; segmento di stringa individuato
String sTitolo, ; titolo da salvare per l’applicativo
Int iPrima, ; punteggiatura trovata nella prima stringa
Int iDopo, ; punteggiatura nella seconda stringa
String sNome; dato da restituire
Let sAttiva = StringLower (GetActiveConfiguration ());fissa l’etichetta per l’applicazione
; se l’etichetta si rileva nella parte iniziale della stringa,
If StringContains (StringLower (sPrima), sAttiva) Then
Let iParte = SECONDA; allora il nome si trova nella seconda parte
; se invece l’etichetta si trova nella seconda parte,
ElIf StringContains (StringLower (sDopo), sAttiva) Then
Let iParte= PRIMA; allora il nome si trova in quella iniziale
Else; se invece l’etichetta dell’applicativo non è stata rilevata,
Let iPrima = StringContains (sPrima, PUNTO); cerca un carattere Punto nella parte iniziale,
Let iDopo = StringContains (sDopo, PUNTO); e lo cerca anche nella parte finale del dato
If iPrima && !iDopo Then; se il punto è presente nella prima parte e non nella seconda,
Let iParte = PRIMA; allora il nome deve trovarsi nella prima parte
ElIf iDopo && !iPrima Then; se invece il punto è nella seconda parte e non nella prima,
Let iParte = SECONDA; allora il nome dovrebbe essere nella seconda parte
EndIf; fine controllo punto nel dato
EndIf; fine controllo etichetta applicativo
If !iParte ; se la parte dove si trova il nome non è stata rilevata,
&& iAiuto Then; ma la fase omonima è stata specificata,
If LeggeDato (CORRENTE, DATI_FILE, AIUTO) == NESSUNO Then; se la fase non è attiva,
SayMessage (OT_ERROR, hlpNoAiuto, hlpNoAiuto_corto); avvisa di tale annullamento,
Return NULLO; e restituisce una stringa vuota
EndIf; fine controllo annullamento Aiuto
Delay (1, TRUE); sospende momentaneamente il flusso e disattiva funzioni di autolettura
; consente di scegliere in quale tra le due parti del titolo sia presente il nome del file
Let iParte = DlgSelectItemInList (FormatString (lstParti, sPrima, sDopo), ttlParti, FALSE)
If iParte == TERZA Then; se si è scelto di annullare l’analisi,
ScriveDato (CORRENTE, DATI_FILE, AIUTO, NESSUNO); annota la scelta,
Return NULLO; e restituisce una stringa vuota
EndIf; fine controllo scelte
EndIf; fine primo controllo rilevazione parte
If !iParte Then; se la porzione dove si trova il nome non è ancora stata individuata,
Return NULLO; restituisce una stringa vuota
EndIf; fine secondo controllo rilevazione parte
If iParte == PRIMA Then; se il nome è stato rilevato nella parte iniziale,
Let sNome = sPrima; ne memorizza il testo per restituirlo,
Let sTitolo = SEPARA_NOME + sDopo; e compone anche il titolo da salvare nell’archivio
ElIf iParte == 2 Then; se invece il nome è stato individuato nella parte finale,
Let sNome = sDopo; ne copia il testo per la restituzione,
Let sTitolo = sPrima + SEPARA_NOME; e compone anche il titolo da archiviare
EndIf; fine controllo parte
; salva il nome dell’applicativo rilevato nel titolo, per semplificare le successive ricerche
ScriveDato (CORRENTE, DATI_FILE, TITOLO, FormatString (msgVirgolette, sTitolo))
Return sNome; e restituisce il dato rilevato
EndFunction

Collaudo.

Se la compilazione va a buon fine, per questa e la prossima funzione, considerando che entrambe non hanno nemmeno parametri da rendere opzionali, rinviamo il test della procedura all’ultimo suo elemento.

Esercizio 9.3.2. La funzione TagliaSpazi.

FileScript.

Default.JSS

Nome.

TagliaSpazi

Descrizione.

Utilizza le due funzioni native per togliere ad una stringa testuale, passata come parametro, gli eventuali spazi iniziali e finali, riducendo ad uno quelli consecutivi.

Ritorni.

Di tipo String. Il testo originale senza gli eventuali spazi in eccesso.

Parametri.
  1. sTesto. Il testo da elaborare. Di tipo String.
Novità.
  1. La funzione integrata
    StringTrimTrailingBlanks
    , (TagliaDalTestoSpaziVuotiFinali). Oltre allo scopo chiarito dalla traduzione, essa elimina anche gli spazi in eccesso eventualmente presenti nel corpo della stringa testuale, riducendoli ad uno soltanto. Il suo unico parametro è il testo da passare alla funzione per verificarlo, ed il risultato sarà lo stesso testo eventualmente modificato.
Note.
  1. Lo scopo di questa funzione è quello di risparmiare del codice, unificando in una sola istruzione, formata da pochi caratteri, l’azione che sarebbe svolta invece solo grazie alla chiamata annidata di due funzioni distinte, e per giunta tra quelle col nome più lungo fra quelle fornite da Jaws.

Codice.


String Function TagliaSpazi (string sTesto)
; restituisce il testo senza gli spazi iniziali, finali e consecutivi
Return StringTrimLeadingBlanks (StringTrimTrailingBlanks (sTesto))
EndFunction

Esercizio 9.3.3. La funzione TogliePercorso.

FileScript.

Default.JSS

Nome.

TogliePercorso

Descrizione.

Esegue due controlli sulla presenza di un percorso o di un solo carattere Due Punti nel nome, restituendo in entrambi i casi la stringa più a destra.

Ritorni.

Di tipo String. Il solo nome del documento corrente, completo di eventuale estensione.

Parametri.
  1. sNome. La stringa contenente il nome da estrapolare. Di tipo String.
Novità.
  1. La prima chiamata della nostra funzione
    TagliaSpazi ()
    , utilizzata per risparmiare codice.
  2. Le costanti
    CONTROBARRA,
    BARRA
    e
    DUE_PUNTI
    , equivalenti ciascuna agli omonimi caratteri.
  3. La costante
    ULTIMA
    , che equivale al valore negativo -1, che sta ad indicare, ad esempio, di contare le voci di una zona di testo ad iniziare da destra.
Fasi.
  1. Se il parametro passato è privo di contenuti, viene restituita una stringa vuota, interrompendo il flusso.
  2. Se il flusso continua, inizia un ciclo che sottopone alla ricerca i caratteri registrati nelle citate costanti, corrispondenti ai separatori nei percorsi Windows e nei nomi di file di alcuni applicativi, cui si aggiunge il carattere Barra per eliminare eventuali percorsi web.
  3. Se un carattere viene trovato, il nome viene ridotto tramite la funzione nativa
    StringSegment ()
    , in cui come ultimo parametro viene specificato il valore
    "-1"
    , che sta appunto ad indicare il segmento più a destra del testo inserito nella funzione.
  4. Alla conclusione del ciclo di ricerca, il dato viene restituito rimuovendone eventuali spazi iniziali e finali.

Codice.


String Function TogliePercorso (string sNome)
If !sNome Then; se il parametro passato è vuoto,
Return NULLO; restituisce una stringa vuota, interrompendo il flusso
EndIf; fine controllo parametro
Var
Int i, ; contatore del ciclo
String sTrova; carattere da cercare
For i = 1 To 3; compie le tre iterazioni del ciclo
If i == 1 Then; se si è al primo passaggio,
Let sTrova = CONTROBARRA; imposta il carattere di separazione per i percorsi Windows
ElIf i == 2 Then; se invece si è al secondo,
Let sTrova = BARRA; imposta il separatore nei percorsi web
Else; altrimenti,
Let sTrova = DUE_PUNTI; imposta il separatore tra il nome ed eventuali dati accessori
EndIf; fine controllo passaggio
If StringContains (sNome, sTrova) Then; se il carattere è stato trovato,
; riduce la stringa al segmento a destra dell’ultima occorrenza del carattere
Let sNome = TagliaSpazi (StringSegment (sNome, sTrova, ULTIMA))
EndIf; fine controllo carattere
EndFor; fine ciclo ricerca
Return TagliaSpazi (sNome); restituisce il dato , eliminando gli spazi in eccesso
EndFunction

Esercizio 9.3.4. La funzione DocumentoCorrente.

FileScript.

Default.JSS

Nome.

DocumentoCorrente

Descrizione.

Rileva il nome del file aperto in un applicativo, trasmettendone per riferimento il nome completo privo di un eventuale percorso. Nel caso il documento abbia un’estensione, viene anch’essa trasmessa come secondo dato per riferimento, comprensiva del punto iniziale.

Ritorni.

Di tipo Int. L’esito dell’analisi: TRUE in caso di riuscita, FALSE per il fallimento.

Parametri.
  1. sNomeFile. Per Riferimento. Il nome del file completo di estensione, ma privo di eventuale percorso. Di tipo String.
  2. sEstensione. Per Riferimento. La sola estensione del file, comprensiva del carattere Punto iniziale. Di tipo String. Parametro Opzionale.
  3. iAiuto. Se positivo, indica l’attivazione dell’omonima fase che consente, in questo caso, oltre alla lettura dei messaggi suppletivi, di completare le informazioni raccolte tramite una finestra di scelta. Di tipo Int. Parametro Opzionale.
Novità.
  1. La funzione integrata
    StringLength
    , (LunghezzaDatoTestuale), che restituisce il valore numerico corrispondente alla lunghezza del testo posto come unico parametro della funzione.
  2. La funzione integrata
    SubString
    , (SottoDatoTestuale), che estrae una stringa da un testo. Essa ha tre parametri:
    • Il testo in cui cercare.
    • Il punto di inizio della sottostringa da estrarre.
    • La lunghezza della sottostringa. Quando si vuole estrarre il sottodato dal punto specificato sino alla fine del testo, se non si conosce la lunghezza totale, si può specificare un numero qualsiasi, purché si sia certi che sia maggiore della lunghezza del testo originale.
  3. Le nostre funzioni
    NomeNelTitolo ()
    e
    TogliePercorso ().
  4. La funzione integrata
    PathRemoveExtension
    , (RimuoviEstensioneDalPercorso), che serve appunto a togliere l’eventuale estensione da un testo contenente un nome di file. Essa ha come unico parametro il percorso da verificare.
Fasi.
  1. Dopo aver rilevato il dato da elaborare, tramite la funzione integrata
    GetWindowName ()
    , si verifica dapprima se un titolo sia già stato registrato per l’applicazione corrente. Se così è, si controlla se esso sia presente nel dato, ed in tal caso si imposta la restante porzione di stringa come il nome del documento.
  2. La fase centrale della funzione serve a verificare se nel dato vi sia un carattere che separa le eventuali sue parti. Se così è, divide il testo in una stringa prima ed una dopo tale separatore, passandole poi alla nostra funzione
    NomeNelTitolo ()
    , la quale provvede ad individuarne quella con il nome del documento.
  3. Nella terza ed ultima parte, qualora non sia stato ancora individuato il nome del documento, si interrompe il flusso restituendo una stringa vuota.
  4. Se il flusso invece continua, si inizia dapprima ad eliminare dal nome rilevato un eventuale percorso assoluto, tramite la nostra funzione
    TogliePercorso ()
    . Di seguito, si cercherà il nome individuato, cui si toglierà l’eventuale estensione del file, tramite la funzione nativa
    PathRemoveExtension ()
    , descritta in precedenza. Se il nome aggiornato è diverso da quello estratto direttamente dal dato, l’estensione viene trasmessa per riferimento, memorizzandola negli archivi dell’applicativo. Al termine, poiché nessun’altra condizione aveva sino ad allora interrotto il flusso, sarà restituito un risultato positivo.
Note.
  1. La prima variabile trasmessa per riferimento, come detto, contiene sia il nome, sia l’estensione. Tale dato sarebbe quindi sufficiente, anche qualora servisse la sola estensione, ma per semplicità si è voluto fornire l’opzione di avere direttamente dal secondo parametro anche questa parte del nome. Essendo però un parametro opzionale, se non si prevede di utilizzarla, sarà sempre possibile non specificare questo secondo parametro al momento di chiamare la funzione dal codice.
  2. Sempre a riguardo del secondo parametro opzionale , da notare che l’estensione comprende anche il punto di separazione. Nei casi in cui servisse il dato senza tale prefisso, si potrà utilizzare la funzione nativa
    SubString ()
    , appena illustrata, per ricavarne il contenuto dal secondo carattere in poi.

Codice.


Int Function DocumentoCorrente (string ByRef sNomeFile, ; intestazione con un parametro,
string ByRef sEstensione, int iAiuto); e seconda riga con gli altri due
Var
String sDato, ; testo del titolo originale
String sTitolo, ; nome dell’applicativo nel titolo
Int iPosiz, ; posizione di un testo in una stringa
int iLungo, ; lunghezza della stringa
String sPrima, ; porzione di testo che precede il separatore
String sDopo, ; porzione del nome che segue il separatore
String sNome; il solo nome del documento
Let sDato = GetWindowName (GetRealWindow (GetFocus ())); rileva il dato originario
Let sTitolo = LeggeDato (CORRENTE, DATI_FILE, TITOLO); legge l’eventuale titolo salvato
If sTitolo Then; se un nome dell’applicativo è stato già registrato,
Let iPosiz = StringContains (sDato, sTitolo ); cerca tale titolo nel dato
If iPosiz Then; se il titolo è stato individuato,
Let iLungo = StringLength (sTitolo); rileva la lunghezza del titolo
If iPosiz == 1 Then; se il titolo è stato rilevato ad inizio stringa, ne estrae la parte col nome
Let sNomeFile = TagliaSpazi (SubString (sDato, iLungo + 1, StringLength (sDato) - iLungo))
Else; se invece il nome è stato rilevato nella parte iniziale,
Let sNomeFile = StringLeft (sDato, iPosiz - 1); ne estrae il testo prima
EndIf; fine controllo posizione titolo
EndIf; fine controllo presenza titolo
EndIf; fine controllo registrazione titolo
If !sNomeFile Then; se il nome non è stato ancora individuato,
Let iPosiz = StringContains (sDato, SEPARA_NOME); cerca un separatore nel nome
If iPosiz Then; se tale separatore è stato trovato,
Let sPrima = TagliaSpazi (StringLeft (sDato, iPosiz - 1)); ne estrae la prima parte,
Let iLungo = iPosiz + (StringLength (SEPARA_NOME) - 1); ne segna l’inizio della seconda,
; e la estrae dal dato
Let sDopo = TagliaSpazi (SubString (sDato, iLungo + 1, StringLength (sDato) - iLungo))
; infine, assegna al nome la parte corretta del titolo
Let sNomeFile = NomeNelTitolo (sPrima, sDopo, iAiuto)
Else; se invece il separatore non è stato trovato,
Let sNomeFile = sDato; memorizza il dato nella forma originale
EndIf; fine controllo separatore
EndIf; fine controllo presenza nome del file
If !sNomeFile Then; se non è stato individuato alcun Nome nel titolo,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayFormattedMessage (OT_ERROR, hlpNoDato, hlpNoDato_corto, msgTitolo)
EndIf; fine controllo Aiuto
Return FALSE; in ogni caso, restituisce un valore nullo
EndIf; fine controllo rilevazione del NomeFile
Let sNomeFile = TogliePercorso (sNomeFile); toglie l’eventuale percorso dal dato
Let sNome = PathRemoveExtension (sNomeFile); toglie casomai l’estensione nel NomeFile
If sNome != sNomeFile Then; se i due nomi sono diversi, e quindi esiste una estensione,
; trasmette per riferimento anche l’estensione del nome rilevato
Let sEstensione = StringRight (sNomeFile, StringLength (sNomeFile) - StringLength (sNome))
ElIf StringRight (sNomeFile, 1) == QUADRA_CHIUSA Then; se invece a fine stringa vi è una parentesi quadra,
Let sNome = StringTrimTrailingBlanks (StringSegment (sNomeFile, QUADRA_APERTA, PRIMA))
If PathRemoveExtension (sNome) != sNome Then; se nella stringa è presente un’estensione,
Let sNomeFile = sNome; aggiorna il nome del file completo
Let sNome = PathRemoveExtension (sNomeFile); crea la versione del nome senza estensione,
; trasmette per riferimento l’estensione del nome rilevato
Let sEstensione = StringRight (sNomeFile, StringLength (sNomeFile) - StringLength (sNome))
Else; altrimenti, se un’estensione non c’è,
Let sEstensione = NULLO; trasmette una stringa vuota
EndIf; fine controllo blocco tra parentesi quadre
Else; altrimenti, se la ricerca di un’estensione ha avuto esito negativo,
Let sEstensione = NULLO; trasmette una stringa vuota
EndIf; fine controllo presenza estensione
Return TRUE; restituisce l’esito positivo
EndFunction

Collaudo.

  1. Se la compilazione va a buon fine, la prima cosa da fare è rendere opzionali i due parametri indicati come tali. Diamo per scontato siate in grado di compiere da soli tale azione, e se avete dubbi tornate agli esempi precedenti. Ricordiamo solo che in questo caso la parola chiave
    :Optional
    va inserita tra il primo ed il secondo parametro, e soprattutto di uscire dall’Editor di Jaws dopo aver ricompilato a seguito della modifica, per evitare malfunzionamenti.
  2. Al fine di realizzare il collaudo delle tre funzioni coinvolte nella procedura, dovremo prima completare la prossima esercitazione, nella quale aggiorneremo lo script provvisorio di cui ci eravamo serviti nel sesto capitolo.

Esercizio 9.3.5. L’aggiornamento dello script Prova ().

FileScript.

Default.JSS

Nome.

Prova

Note.
  1. Sul contenuto dello script, l’unica novità da segnalare è il messaggio
    msg2Virgola
    , impostato ad inizio capitolo, il quale consente di formattare due termini passati come parametro separati da un carattere Virgola, per far pronunciare una breve pausa tra l’uno e l’altro.

Codice.


Script Prova ()
Var
String sNomeFile, ; nome completo del documento
String sEstensione; estensione del file
If DocumentoCorrente (sNomeFile, sEstensione, IsSameScript ()) Then; se i dati ci sono,
SayFormattedMessage (OT_HELP, msg2Virgola, NULLO, sNomeFile, sEstensione); li legge
EndIf; fine controllo Nome del documento
EndScript

Collaudo.

  1. Da dentro all’Editor di Jaws, con aperto il file script Predefinito, attivate lo script di Prova premendo
    Alt+Control+Apostrofo
    , e Jaws dovrebbe pronunciare:
  2. "Default.JSS, .JSS"

  3. In pratica, la procedura è stata in grado di rilevare entrambi i dati relativi al file script Predefinito, il nome completo e la sola estensione. In particolare, poiché il dato rilevato all’inizio dalla funzione nativa di Jaws comprende soltanto il nome del file, esso è stato elaborato direttamente, senza quindi neppure chiamare l’altra nostra funzione,
    NomeNelTitolo ().
  4. Per eseguire un collaudo più significativo, richiamate ora il Blocco Note, e così caricando il documento vuoto predefinito. Da dentro a questo applicativo, eseguite lo script di Prova, ed in questo caso non sentirete pronunciare nulla perché la procedura non è stata in grado di rilevare da sola i dati necessari.
  5. Provate allora ad attivare la fase Aiuto, premendo due volte velocemente la combinazione di avvio
    Alt+Control+Apostrofo
    . Stavolta, sarà proposta una finestra di scelta che avrà come messaggio
    "Confermare quale parte contenga il NomeFile"
    , e di seguito sarà proposto un elenco delle tre seguenti voci:
    • Senza nome
    • Blocco note
    • Non chiedermelo più
  6. Poiché quella con il nome del documento è la prima, essendo tale scelta già selezionata al vostro ingresso nella finestra di dialogo, basterà confermare con Invio per raggiungere lo scopo, e di seguito Jaws pronuncerà nuovamente il testo della voce confermata:
  7. Senza nome

  8. Ora, se provate ad eseguire lo script
    Prova ()
    , sentirete nuovamente pronunciare il solo nome del documento predefinito, che è privo di estensione. Questo succede perché la procedura ha salvato i dati necessari a leggere il modo corretto il nome del file aperto nel Blocco Note. Questi dati sono stati salvati nel file di configurazione dell’applicativo,
    Notepad.JCF
    , e se li andate a controllare al suo interno dovrebbero essere come quelli posti di seguito:
  9. 
    [DatiFile]
    Titolo=" - Blocco note"
    

  10. Tali impostazioni fanno sì che, ogni volta che si attiva la funzione
    DocumentoCorrente ()
    da dentro al Blocco Note, la procedura andrà a leggersi i dati registrati, rileverà che il titolo dell’applicazione che va rimosso dal dato ottenuto è quello posto tra virgolette nell’assegnazione appena proposta, e quindi ciò che ne rimane del dato acquisito tramite la funzione nativa di Jaws è, appunto, il nome del documento aperto.
  11. Per completare le informazioni, in tutti i casi nei quali la procedura non sarà in grado di ricavare il nome dai dati rilevati, come è successo al precedente punto 5, alla chiamata della funzione essa non produrrà alcun avviso. Se si attivasse la fase Aiuto, invece, la procedura farà pronunciare un messaggio che informa dell’assenza dei dati.
  12. Infine, vi sono molti applicativi che non hanno documenti aperti di cui poter leggere i dati. Se voi aveste uno script che comunque chiama la funzione
    DocumentoCorrente ()
    da dentro un tale programma, la funzione non avrebbe anche in questo caso alcun effetto. Se però vi capitasse di avviare la fase Aiuto da dentro uno di questi applicativi, allora potrebbe essere proposta la schermata di scelta. Per questo, sarà possibile in tal caso confermare con Invio l’ultima voce in fondo,
    "Non chiedermelo più"
    , con la quale si inibisce la presentazione della schermata di scelta alle prossime chiamate della funzione. Qualora si attivi la fase Aiuto una volta annullata l’impostazione, si sarà comunque avvertiti dello stato tramite un messaggio, pronunciato sulla base dei livelli di prolissità attivi, ma che avrà in comune la seguente parte iniziale:
  13. "Fase Aiuto annullata…"

***

Gestire lo spegnimento e la riattivazione della Sintesi Vocale.

Fin dal primo capitolo abbiamo imparato come spegnere o riattivare la sintesi vocale. Ora, faremo un passo in più, analizzando come gestire al meglio tali fasi, e come evitare spiacevoli malfunzionamenti.

Provate a ripensare al capitolo scorso, quando abbiamo creato la funzione
ComandoTrova ()
, e soprattutto a quando l’abbiamo chiamata da dentro all’altra nostra funzione
EsegueRicerca ()
. Se ricordate, all’inizio di questa seconda funzione vi era dapprima un’istruzione per spegnere la sintesi,
SpeechOff ()
. Seguita immediatamente dalla chiamata alla nostra prima funzione,
ComandoTrova ()
. Nel codice originale di questa funzione vi erano la classica coppia di comandi che riguardavano la sintesi, il primo che la spegneva e l’altro che la riattivava. Se noi li avessimo lasciati così com’erano, i due comandi citati avrebbero avuto il seguente effetto:

  1. La prima istruzione
    SpeechOff ()
    , essendo la sintesi già spenta dall’istruzione precedente della funzione che l’aveva chiamata, non avrebbe avuto alcun effetto.
  2. L’istruzione
    SpeechOn ()
    , presente alla fine del codice originale della prima funzione, avrebbe invece riacceso la sintesi quando in realtà essa doveva rimanere spenta.

Per risolvere in modo temporaneo l’inghippo, nello scorso capitolo ci siamo limitati a disabilitare tali istruzioni all’interno di
ComandoTrova ()
, anteponendovi il carattere Punto e Virgola. In realtà, tale funzione dovrebbe essere ancora in grado di spegnere e riattivare la sintesi, quando a chiamarla sono degli script come
TrovaTesto ()
dove non ci sono dei comandi che agiscono sul suo stato di attivazione, ma al tempo stesso dovrebbe anche riuscire a lasciare inalterato lo stato della voce, quando a chiamarla sono altre funzioni come ad esempio
EsegueRicerca ()
, che contengono già tali tipo di comandi.

Come spesso accade, per illustrare questo problema sono stati indispensabili più passaggi e molte righe di testo, mentre per risolverlo saranno sufficienti una sola nostra funzione e poche righe di codice. Oltre a proporre un modo semplice per gestire tali comandi, la funzione che segue consente di sfruttare appieno le potenzialità dei comandi
SpeechOff ()
e
SpeechOn ()
, i quali consentono anche di specificare un parametro, valorizzato in TRUE, per azzerare il testo presente nel buffer di memoria della sintesi ed ancora da leggere.

Esercizio 9.4.1. La funzione ControllaSintesi.

FileScript.

Default.JSS

Nome.

ControllaSintesi

Descrizione.

Spegne la sintesi, a meno che non sia già spenta, oppure la riattiva, ma solo nel caso che a spegnerla sia stata in precedenza la funzione stessa.

Ritorni.

Di tipo Int. Il valore, TRUE o FALSE, che indica se riattivare o meno la sintesi.

Parametri.
  1. iStato. Il valore, TRUE o FALSE, che indica se la sintesi sia da spegnere o da riattivare. Di tipo Int. Parametro Opzionale.
  2. iAzzera. Se di valore TRUE, resetta il buffer di memoria della sintesi, simulando la pressione ripetuta del comando
    Control
    . Di tipo Int. Parametro Opzionale.
Novità.
  1. La funzione integrata
    IsSpeechOff
    , (E’LaSintesiSpenta), che restituisce TRUE, quando la voce è spenta, e FALSE, quando è in funzione. Senza parametri.
  2. La possibilità di esprimere un valore, TRUE o FALSE, come parametro nelle istruzioni
    SpeechOff ()
    e
    SpeechOn ().
Fasi.
  1. Nel caso la sintesi sia attiva, viene eseguito un controllo se sia stato indicato o meno di spegnerla.
  2. Sempre se la sintesi fosse attiva, in ogni caso viene restituito un valore TRUE.
  3. Nel caso invece la sintesi sia spenta, e sia stato indicato di riattivarla, si esegue la relativa istruzione.
  4. Se infine nessuno dei precedenti casi si fosse verificato, viene restituito un risultato FALSE.
Note.
  1. Così come le istruzioni native, anche le chiamate a questa funzione devono essere per forza eseguite come minimo in coppia. In altre parole, all’interno di uno stesso elemento di codice, la funzione deve essere chiamata una prima volta per verificare se spegnere la voce, e, prima della sua conclusione, almeno un’altra volta per casomai riattivarla. Nel caso in cui vi siano più strutture di controllo che ramificano il flusso, al termine di ciascuna possibile via deve trovarsi la chiamata con l’eventuale riattivazione.
  2. Il secondo parametro, anch’esso opzionale, serve soltanto nei casi in cui la chiamata a funzione intervenga quando sia necessario zittire la voce. Tale parametro va usato con attenzione, perché a volte si rischia di annullare la pronuncia di informazioni viceversa necessarie. Va inoltre chiarito che, quando si spegne la sintesi usando tale parametro, bisogna per forza riutilizzarlo anche per riattivarla, pena il mancato funzionamento dell’azione. In genere, può essere sufficiente fare come abbiamo fatto sinora, cioè non specificare alcun parametro, lasciando così il valore False, che sarà in ogni caso quello predefinito.

Codice.


Int Function ControllaSintesi (int iStato, int iAzzera)
If !IsSpeechOff () Then; se la sintesi non è spenta,
If iStato == FALSE Then; se si è impostato un valore nullo,
SpeechOff (iAzzera); spegne la sintesi
EndIf; fine controllo impostazione
Return TRUE; annota di mantenerla accesa, o di riaccenderla, alla successiva chiamata
ElIf iStato == TRUE Then; se invece si è indicata la riattivazione, mentre la sintesi è spenta,
SpeechOn (iAzzera); riattiva la sintesi
EndIf; fine controllo spegnimento
Return FALSE; restituisce un valore nullo
EndFunction

Collaudo.

  1. Se la compilazione va a buon fine, anche qui rendiamo subito opzionali entrambi i parametri. Stavolta la parola chiave
    :Optional
    dovrà essere inserita prima di tutti e due i parametri esistenti, poi ricordatevi di uscire dopo la ricompilazione.
  2. Dopo questo necessario passaggio, facciamo subito un esempio di come tale funzione dovrebbe essere chiamata.

Esercizio 9.4.2. La versione aggiornata di ComandoTrova ().

FileScript.

Notepad.JSS

Nome.

ComandoTrova

Novità.
  1. La nostra funzione
    ControllaSintesi ()
    , alla sua prima chiamata.
Note.
  1. Aprite il file
    Notepad.JSS
    , e portatevi sulla intestazione della funzione
    ComandoTrova ()
    . Nella riga appena sotto, inserite la seguente dichiarazione di variabile:
  2. 
    Var Int iStato; valore restituito dalla funzione di controllo
    

  3. Scendete di una riga sulla prima istruzione riguardante la sintesi vocale,
    SpeechOff ()
    , e cancellate l’intera riga di codice inserendo al suo posto la seguente istruzione:
  4. 
    Let iStato = ControllaSintesi (); verifica l’attivazione della sintesi, casomai spegnendola
    

  5. Scendete ora fino alla riga contenente l’altra istruzione sulla sintesi,
    SpeechOn ()
    , cancellatela mettendo al suo posto la seguente forma di chiamata:
  6. 
    ControllaSintesi (iStato); verifica se riattivare la sintesi, sulla base del valore impostato
    

  7. Quindi, alla prima chiamata la nostra funzione imposterà un valore numerico, TRUE o FALSE, che poi sarà passato come parametro alla chiamata successiva della stessa funzione. In questo modo, la sintesi sarà lasciata spenta, qualora il suo stato alla prima chiamata fosse tale, altrimenti sarà riattivata, nel caso in cui prima la chiamata precedente l’avesse spenta.

Codice.


Void Function ComandoTrova ()
Var Int iStato; valore restituito dalla funzione di controllo
Let iStato = ControllaSintesi (); verifica l’attivazione della sintesi, casomai spegnendola
TypeKey ("Alt+M"); richiama il menu Modifica
Pause (); sospende temporaneamente lo script
TypeString ("O"); richiama il comando Trova dal menu
ControllaSintesi (iStato); verifica se riattivare la sintesi, sulla base del valore impostato
EndFunction

Collaudo.

Se provate a compilare il file script del Blocco Note e fosse tutto a posto, provate a premere
Control+F
per attivare lo script
TrovaTesto ()
, il quale a sua volta chiama la funzione appena modificata. Se compare la finestra di ricerca, potete proseguire.

***

La Gestione dei Dati.

Lo scopo di questa sezione è approntare quel sistema, di cui si accennava nella premessa del capitolo, destinato a cambiare il nostro modo di realizzare gli script. In generale, tale sistema consiste nel far passare attraverso una funzione principale, di gestione appunto, gran parte delle chiamate alle varie procedure da noi realizzate.

La parte interessante di questo metodo di approccio sarà che la funzione di gestione ricaverà i dati necessari al suo funzionamento non tanto da eventuali parametri, così come abbiamo fatto sinora, bensì elaborando il nome dello script chiamante. Questo metodo, seppure forse poco ortodosso rispetto ai normali canoni della programmazione, sarà particolarmente utile più avanti, quando affronteremo la creazione di script in serie, ma già da subito ci consentirà di applicarlo alla procedura che poi realizzeremo.

Ciò che ci consente di ricavare dei dati in modo diretto, elaborando i nomi degli script eseguiti, ci è fornita da una serie di funzioni:

  1. GetCurrentScriptKeyName ()
    ,già utilizzata nel settimo capitolo, la quale restituisce la stringa relativa ai tasti, o alla combinazione di tasti, premuti per attivare uno script.
  2. GetScriptAssignedTo ()
    , anch’essa conosciuta due capitoli fa, la quale ci restituisce il nome dello script collegato ai tasti specificati.
  3. StringMixedCaseToMultiword
    , (TestoCaratteriMescolatiParolaMultipla), che crea una nuova parola ad ogni lettera maiuscola incontrata nel testo passato come parametro.

Queste tre funzioni sono strettamente correlate tra loro, in quanto la prima funzione va passata come parametro alla seconda, ed entrambe determinano il parametro da passare alla terza.

Prendiamo, ad esempio, il nostro script
DefinisceTipiFinestra ()
. Se noi lo eseguissimo, servendoci delle tre funzioni citate, noi avremmo questa sequenza di risultati:

  1. La prima funzione ci restituirebbe i suoi tasti di attivazione,
    Control+Windows+I.
  2. Ponendo tali tasti come parametro della seconda, noi ne ricaveremmo il suo nome completo.
  3. Infine, se noi sottoponessimo questo risultato alla terza istruzione, noi avremmo alla fine le singole parti del nome separate tra loro da uno spazio, come nella forma seguente:
  4. "Imposta Tipi Finestra"

A questo punto, noi potremmo usare la funzione
StringSegment ()
, ponendo uno spazio come separatore delle diverse parole, e potendo così utilizzare ogni singola componente del nome come fossero dei parametri passati in modo tradizionale all’interno della funzione.

L’unica avvertenza sarà, quindi, fare attenzione ai nomi da specificare per i singoli script, accertandosi di porre sempre l’iniziale maiuscola ai diversi termini che li compongono. Oltre che a favorirne la lettura, così come avevamo suggerito fin da subito, tale espediente ci consentirà di semplificare al massimo il contenuto dei nostri script, che potrà essere composto anche da una sola chiamata alla funzione di gestione.

Come sempre, l’utilità di questo sistema sarà più evidente quando collauderemo tutti gli elementi di codice nel loro assieme. Bisognerà però avere un po’ di pazienza, perché il test complessivo sarà possibile solo quando avremo realizzato sia quelli più direttamente legati al sistema in sé, sia quelli della procedura che realizzeremo come primo esempio concreto.

Iniziamo dunque, dai due primi elementi del sistema, che sono quelli più direttamente legati all’estrazione dei dati dai nomi di script. Proseguiremo poi con la procedura di esempio, cui dedicheremo un titolo introduttivo.

Esercizio 9.5.1. La funzione EstraeNumero.

FileScript.

Default.JSS

Nome.

EstraeNumero

Descrizione.

Cerca un eventuale valore numerico posto a destra del testo passato come parametro, e casomai lo restituisce trasmettendo il resto della stringa per riferimento.

Ritorni.

Di tipo String. L’eventuale valore in forma testuale inserito alla fine del dato.

Parametri.
  1. sTesto. Per Riferimento. Il testo da elaborare. Di tipo String.
  2. sOrigine. L’eventuale forma originale del testo da elaborare, da utilizzarsi qualora la variabile iniziale non debba essere modificata. Di tipo String. Parametro Opzionale.
Novità.
  1. La costante
    ZERO
    , che contiene la cifra in forma testuale per adattarla a questo tipo di confronti.
  2. La funzione integrata
    StringToInt ()
    , già presentata nel quarto capitolo, che ora useremo nel codice per la prima volta.
Fasi.
  1. Una prima struttura di controllo verifica se un qualche testo sia stato specificato come primo o secondo parametro, altrimenti interrompe il flusso restituendo una stringa vuota.
  2. Un ciclo
    While
    scorre il testo all’indietro, da destra a sinistra, analizzandolo carattere per carattere.
  3. Quando viene rilevato un carattere che non sia una cifra testuale, viene considerata come numerica la parte di stringa dalla posizione precedente sino alla sua fine, mentre il testo sarà ridotto alla sola parte iniziale priva di numeri. Se invece già al primo carattere non si trova un numero, come cifra sarà restituita una stringa vuota, mentre il testo originale sarà ritrasmesso per riferimento.
  4. Se invece il ciclo si conclude, e quindi rilevando solo numeri della stringa, come testo viene trasmessa una stringa vuota, mentre la cifra restituita sarà il testo originale.

Codice.


String Function EstraeNumero (string ByRef sTesto, string sOrigine)
Let sTesto = TagliaSpazi (sTesto); rimuove eventuali spazi iniziali e finali
Let sOrigine = TagliaSpazi (sOrigine); li rimuove anche dall’eventuale stringa di origine
If !sOrigine Then; se non è stata indicata una stringa di origine,
If sTesto Then; se però ne è stata indicata una per riferimento,
Let sOrigine = sTesto; la duplica per semplificare il flusso
Else; altrimenti, se nemmeno come primo parametro è stato espresso un testo,
Return NULLO; restituisce una stringa vuota
EndIf; fine controllo primo parametro
EndIf; fine controllo secondo parametro
Var
Int iPartenza, ; lunghezza della stringa indicata
Int iPosiz, ; puntatore di estrazione testo
String sCarattere; singolo carattere testuale
Let iPartenza = StringLength (sOrigine); registra la lunghezza del dato testuale
Let iPosiz = iPartenza; duplica il valore, per far partire il ciclo
While iPosiz; continua finché il contatore rimane positivo
Let sCarattere = SubString (sOrigine, iPosiz, 1); estrae un singolo carattere dal testo
If sCarattere == ZERO ; se il testo corrisponde alla cifra 0 in forma testuale,
|| StringToInt (sCarattere) Then; oppure se tale carattere è un valore numerico,
Let iPosiz = iPosiz - 1; aggiorna il puntatore all’indietro
Else; altrimenti, se il carattere non è un numero,
Let sTesto = StringLeft (sOrigine, iPosiz); trasmette il resto del dato testuale prima della cifra,
Return StringRight (sOrigine, iPartenza - iPosiz); e restituisce come cifra la parte rimanente di stringa
EndIf; fine controllo carattere
EndWhile; fine ciclo scorrimento stringa
Let sTesto = NULLO; a fine scansione, trasmette solo una stringa vuota,
Return sOrigine; perché restituisce tutto il testo originale come cifra
EndFunction

Collaudo.

  1. Dato il secondo parametro opzionale, anche qui è necessario portarsi nel file documentazione ed inserire il termine
    :Optional
    tra i due parametri esistenti.

Esercizio 9.5.2. La funzione SeparaParole.

FileScript.

Default.JSS

Nome.

SeparaParole

Descrizione.

Rileva e separa le parole individuate nel nome dello script chiamante sulla base delle iniziali maiuscole, restituendo l’eventuale numero progressivo presente alla fine del nome.

Ritorni.

Di tipo String. L’eventuale numero progressivo, in forma testuale, rilevato alla fine del nome script.

Parametri.
  1. sPrima. Per Riferimento. La parola iniziale rilevata. Nel caso sia l’unica, ad essa potrebbe essere sottratto un numero progressivo presente alla sua destra. Di tipo String.
  2. sSeconda. Per Riferimento. La seconda parola rilevata, qualora ve ne siano almeno tre. Di tipo String.
  3. sUltima. Per Riferimento. L’ultima parola rilevata, a cui sottrarre l’eventuale numero progressivo presente alla sua destra. Di tipo String.
Novità.
  1. La funzione integrata
    StringMixedCaseToMultiword ()
    , descritta nella nota precedente.
  2. La nostra funzione
    EstraeNumero
    , in questo caso usata con il solo primo parametro obbligatorio.
  3. La costante
    SPACE
    , che come si intuisce corrisponde al carattere Spazio, e che viene proposta nella versione inglese per facilitarne il riconoscimento.
Fasi.
  1. Dopo aver separato le eventuali parole che compongono l’ultimo script attivato, la prima parola, o il testo nel suo complesso, viene memorizzato nella prima variabile per riferimento.
  2. Con una prima struttura di controllo, qualora vi sia solo una parola nella stringa d’origine, si interrompe il flusso, restituendo l’eventuale numero progressivo presente alla sua destra e, in tal caso, trasmettendo la parte restante.
  3. Diversamente, il flusso prosegue, e viene rilevata anche l’ultima parola a destra della stringa.
  4. Con un’ultima struttura di controllo, si verifica se le parole individuate siano almeno tre. In tal caso la seconda parola rilevata viene trasmessa per riferimento.
  5. In ogni caso, viene restituito l’eventuale numero progressivo presente alla destra dell’ultima parola rilevata, la quale sarà trasmessa anch’essa per riferimento, casomai priva della parte numerica.

Codice.


String Function SeparaParole (string ByRef sPrima, ; prima riga dell’intestazione,
string ByRef sSeconda, string ByRef sUltima); e seconda riga, con gli altri due parametri
Var
String sChiamante, ; il nome dello script chiamante
String sParole, ; Parole in maiuscolo presenti nel nome
Int iConta; numero delle parole rilevate
Let sChiamante = GetScriptAssignedTo (GetCurrentScriptKeyName ()); rileva il nome,
Let sParole = StringMixedCaseToMultiword (sChiamante); e ne separa le parole maiuscole
Let iConta = StringSegmentCount (sParole, SPACE); conta il numero di parole rilevate
Let sPrima = StringSegment (sParole, SPACE, PRIMA); preleva la parola iniziale dello script
If iConta == PRIMA Then; se vi è un’unica parola,
; restituisce l’eventuale numero progressivo a destra del termine trasmesso
Return EstraeNumero (sPrima)
Else; altrimenti, se ci sono altre parole,
Let sUltima = StringSegment (sParole, SPACE, ULTIMA); preleva la parola finale
If iConta > SECONDA Then; se sono rilevate più di due parole,
Let sSeconda = StringSegment (sParole, SPACE, SECONDA); trasmette la seconda parola
EndIf; fine secondo controllo parole
; restituisce l’eventuale numero progressivo a destra del termine trasmesso
Return EstraeNumero (sUltima)
EndIf; fine primo controllo parole
EndFunction

Leggere i dati nella Barra di stato.

L’ultima riga in basso nello schermo, almeno negli editor e nei word processor in cui stiamo operando, contiene spesso delle utili informazioni sul lavoro che si sta svolgendo, come ad esempio la riga o la pagina correnti. Questa porzione dello schermo, di cui ci siamo occupati già dal nostro secondo script, viene solitamente chiamata
Barra di stato.

Questi dati possono talvolta essere mostrati oppure no, come abbiamo potuto analizzare sia nel Blocco Note che con L’Editor di Script. In tal caso sarà sufficiente agire sul relativo comando, o sulle impostazioni del programma, per attivare tale zona dello schermo.

In ogni applicativo questa barra contiene dati diversi, e soprattutto disposti in modo diverso, mentre l’unico aspetto comune è il fatto di essere spesso presenti in un’unica riga. Questo ci dà un piccolo vantaggio, tanto da consentirci di realizzare un’unica procedura che, grazie ad alcune impostazioni iniziali, riesca poi a leggere questi dati nel modo più corretto, e nei diversi applicativi di nostro interesse.

Nel dettaglio, tale procedura ci servirà adesso soprattutto nel leggere le righe totali nell’Editor di Script, poiché tale dato non si riesce ad acquisire tramite altre funzioni. Come detto, poiché la procedura è facilmente configurabile, la useremo d’ora in avanti anche per ricavarne ogni altra informazione presente nella Barra di stato, o almeno di quelle di cui i nostri script potrebbero aver bisogno.

Nei prossimi sei elementi di codice, in qualche modo dedicati a tale procedura, i due centrali riguardano una funzione di utilizzo generale, che useremo spesso da qui in avanti. Questi due elementi collegati tra loro saranno preceduti da una breve pillola teorica, riguardante i dati in formato esadecimale.

Esercizio 9.5.4. La funzione BarraStato.

FileScript.

Default.JSS

Nome.

BarraStato

Descrizione.

Utilizza la funzione nativa di Jaws per rilevare il contenuto dell’ultima riga in basso nella finestra.

Ritorni.

Di tipo String. Il contenuto dell’ultima riga in basso nella finestra.

Novità.
  1. La funzione integrata
    GetBottomLineOfWindow
    , (OttieniUltimaRigaInBassoDellaFinestra), la cui traduzione spiega già tutto. Si tratta della funzione usata anche dallo script originale, che viene chiamata con la più volte citata combinazione tasti
    TastoJaws+PaginaGiù
    . Non ha parametri.
  2. La costante
    DIVIDE_ZONE
    , equivalente al separatore predefinito, quest’ultimo che di norma corrisponde al carattere Due Punti.
Fasi.
  1. Rileva il testo dell’ultima riga tramite la funzione integrata
    GetBottomLineOfWindow ().
  2. Tramite una struttura di controllo, verifica se del testo sia stato rilevato, quindi se in esso vi sia, o il carattere di separazione standard, corrispondente ai Due Punti, oppure almeno uno spazio, ed in tal caso restituisce il contenuto rilevato.
  3. Se il controllo dà esito negativo, viene restituita una stringa vuota.

Codice.


String Function BarraStato ()
Var String sTesto; il contenuto nella Barra di stato
Let sTesto = GetBottomLineOfWindow (); rileva l’ultima riga in basso con la funzione nativa
If sTesto ; se un qualche contenuto è stato rilevato,
&& (StringContains (sTesto, DIVIDE_ZONE) ; e se nel testo vi è o, il carattere separatore,
|| StringContains (sTesto, SPACE)) Then; oppure, almeno un carattere Spazio,
Return sTesto; restituisce il contenuto rilevato
Else; altrimenti,
Return NULLO; restituisce una stringa vuota
EndIf; fine controllo contenuto
EndFunction

Collaudo.

Per questa e tutte le altre funzioni del gruppo, rinviamo il collaudo agli script finali della procedura.

Esercizio 9.5.5. La funzione ControllaSeparatore.

FileScript.

Default.JSS

Nome.

ControllaSeparatore

Descrizione.

Verifica la presenza di un separatore già registrato per l’applicativo corrente, oppure imposta quello standard, casomai salvandolo se risulta presente nel testo passato come parametro.

Ritorni.

Di tipo Int. L’esito del controllo: TRUE per separatore rilevato, o impostato, e trovato nel testo, FALSE per nessun separatore individuato.

Parametri.
  1. sTesto. Il contenuto della riga dove cercare il separatore impostato. Di tipo String.
  2. sDivide. Per Riferimento. Il carattere usato come separatore dei dati nella Barra di stato. Di tipo String.
Novità.
  1. Le costanti
    BARRA_STATO
    e
    SEPARATORE
    , che rappresentano rispettivamente l’etichetta di sezione e la chiave del dato da elaborare.
Fasi.
  1. Verifica se sia stato registrato un dato come separatore delle voci nella Barra di stato dell’applicativo corrente.
  2. Se la prima verifica ha esito negativo, imposta il separatore standard, registrato nella costante
    DIVIDE_ZONE.
  3. A prescindere dalla sua origine, controlla che il separatore impostato non sia quello nullo, e che sia presente nella Barra di stato.
  4. Se tale presenza è verificata, e la scrittura del dato è stata attivata, salva il separatore nell’archivio corrente, quindi restituisce un risultato positivo.
  5. Se invece il separatore impostato non è valido, oppure non è presente nella riga di stato, non si operano salvataggi e si restituisce un risultato nullo.

Codice.


Int Function ControllaSeparatore (string sTesto, string ByRef sDivide)
Var Int iScrivi; valore che attiva la scrittura dei dati
; tenta di leggere un dato dall’archivio dell’applicazione attiva
Let sDivide = LeggeDato (CORRENTE, BARRA_STATO, SEPARATORE)
If !sDivide Then; se nessun separatore delle voci è stato rilevato,
Let sDivide = DIVIDE_ZONE; imposta il carattere di separazione standard
Let iScrivi = TRUE; imposta il valore per la trascrizione
EndIf; fine controllo presenza separatore
If sDivide != NESSUNO ; se il separatore non è quello nullo,
&& StringContains (sTesto, sDivide) Then; e se nella Barra di stato vi è un separatore,
If iScrivi Then; se la trascrizione del dato è stata attivata,
ScriveDato (CORRENTE, BARRA_STATO, SEPARATORE, sDivide); trascrive il separatore,
CancellaChiave (CORRENTE, BARRA_STATO, TESTO); e rimuove un’eventuale trascrizione lineare
EndIf; fine controllo scrittura
Return TRUE; restituisce l’esito positivo
Else; altrimenti, se il carattere non è stato trovato,
Let sDivide = NULLO; resetta il dato,
Return FALSE; e restituisce un risultato nullo
EndIf; fine controllo presenza separatore
EndFunction

Trattare i dati esadecimali.

Nel settimo capitolo, illustrando la funzione
ExMessageBox ()
, avevamo citato alcune delle costanti con il prefisso
MB
, anch’esse contenute nel file delle costanti di Jaws,
HJConst.JSH
. Nella circostanza, ci eravamo limitati ad elencare le sei che determinano il tipo di tasti proposti nella finestra di dialogo, ma non avevamo chiarito che si trattasse di valori registrati in formato
esadecimale
. Questo aspetto, nonostante consenta di memorizzare in variabili di tipo
Integer
tali valori, non permette poi di controllarne, tramite le classiche strutture di controllo, se ad esempio tali variabili abbiano un qualche valore o siano vuote.

Tra poco noi dovremo creare una nostra funzione dedicata proprio alla citata funzione nativa,
ExMessageBox ()
,impostandone l’utilizzo con dei valori predefiniti , i quali consentano di utilizzarla anche senza specificare alcun parametro. Proprio a causa di questi valori esadecimali, che sarebbero invece da impostare direttamente, abbiamo bisogno di creare una precedente funzione, la quale si occupi soltanto di trasformare un valore
Integer
in
esadecimale
, così da poterlo poi utilizzare per impostare gli opportuni parametri di
ExMessageBox ().

Esercizio 9.5.7. La funzione AssegnaEsadecimali.

FileScript.

Default.JSS

Nome.

AssegnaEsadecimali

Descrizione.

Trasmette per riferimento i valori esadecimali, impostati sulla base del valore indicato, per i tipi di tasti proposti, le icone e suoni delle finestre di dialogo in stile Windows.

Ritorni.

Di tipo Void. Nessuno.

Parametri.
  1. iOpzioni. Per Riferimento. Il valore corrispondente ai tasti da impostare per la finestra di dialogo. Di tipo Int.
  2. iDettagli. Per Riferimento. Il valore corrispondente all’icona ed ai suoni in abbinamento ai tasti indicati al primo parametro. Di tipo Int.
Novità.
  1. Le nostre costanti
    OK,
    OK_ANNULLA,
    INTERROMPI_RIPROVA_IGNORA,
    SI_NO_ANNULLA,
    SI_NO
    e
    RIPROVA_ANNULLA
    , equivalenti nell’ordine ad un valore da 1 a 6, le quali servono ad indicare alla funzione di impostare il valore esadecimale corrispondente alle scelte dei tasti nella versione inglese.
  2. Le costanti native
    MB_ICONHAND,
    MB_ICONQUESTION
    e
    MB_ICONASTERISK
    , equivalenti ai valori esadecimali che, a loro volta, corrispondono ad altrettante coppie di icone e suoni.
Note.
  1. Nell’unica struttura di controllo il valore indicato come primo parametro serve a determinare quale opzione impostare, aggiornando il valore stesso che sarà così ritrasmesso per riferimento convertendolo nel relativo valore esadecimale.
  2. L’altro valore esadecimale trasmesso per riferimento, quello relativo ad icone e suoni, viene abbinato alle diverse opzioni sui tasti sulla base del tipo di messaggio proposto con tali scelte.

Codice.


Void Function AssegnaEsadecimali (int ByRef iOpzioni, int ByRef iDettagli)
If iOpzioni == OK Then; se è stato impostato il primo tipo di finestra di dialogo,
Let iOpzioni = MB_OK; lo aggiorna con il relativo valore esadecimale,
Let iDettagli = MB_ICONHAND; e l’abbinato valore per icona e suoni
ElIf !iOpzioni || iOpzioni == OK_ANNULLA Then; se non è stato specificato nulla, oppure il secondo tipo,
Let iOpzioni = MB_OKCANCEL; aggiorna il valore con il relativo esadecimale
Let iDettagli = MB_ICONQUESTION; e l’abbinato valore per icona e suoni
ElIf iOpzioni == INTERROMPI_RIPROVA_IGNORA Then; se è stato impostato il terzo tipo,
Let iOpzioni = MB_ABORTRETRYIGNORE; aggiorna il valore con il relativo esadecimale
Let iDettagli = MB_ICONASTERISK; e l’abbinato valore per icona e suoni
ElIf iOpzioni == SI_NO_ANNULLA Then; se è stato impostato il quarto tipo,
Let iOpzioni = MB_YESNOCANCEL; aggiorna il valore con il relativo esadecimale,
Let iDettagli = MB_ICONQUESTION; e l’abbinato valore per icona e suoni
ElIf iOpzioni == SI_NO Then; se è stato impostato il quinto tipo,
Let iOpzioni = MB_YESNO; aggiorna il valore con il relativo esadecimale,
Let iDettagli = MB_ICONQUESTION; e l’abbinato valore per icona e suoni
ElIf iOpzioni == RIPROVA_ANNULLA Then; se è stato impostato il sesto tipo,
Let iOpzioni = MB_RETRYCANCEL; aggiorna il valore con il relativo esadecimale
Let iDettagli = MB_ICONASTERISK; e l’abbinato valore per icona e suoni
EndIf; fine controllo tipo
EndFunction

Collaudo.

  1. Questa, e la funzione che segue, pur avendo una valenza autonoma, saranno testate assieme agli altri elementi di codice appartenenti a questo blocco solo al termine della sezione.

Esercizio 9.5.8. La funzione ChiedeConferma.

FileScript.

Default.JSS

Nome.

ChiedeConferma

Descrizione.

Consente di proporre la finestra di dialogo in formato Windows, potendo personalizzare con i parametri titolo, messaggio, opzioni dei tasti, pulsante predefinito e presenza dei suoni. Ciascuna impostazione avrà comunque un valore predefinito, che consentirà anche di non indicare alcun parametro. In quest’ultimo caso, la funzione proporrà una conferma all’uscita dalla procedura.

Ritorni.

Di tipo Int. La scelta effettuata.

Parametri.
  1. sTitolo. Il testo da proporre come titolo della finestra di dialogo; se non lo si indica, sarà usato un messaggio sulla conferma all’uscita. Di tipo String. Parametro Opzionale.
  2. sMessaggio. Il messaggio da proporre nel corpo della finestra di dialogo; se non si indica nulla, sarà lasciato vuoto. Di tipo String. Parametro Opzionale.
  3. iOpzioni. Valore che indica il tipo ed il numero di scelte per i pulsanti proposti; per un elenco completo delle sei opzioni possibili, vedere il file personale delle costanti; se non si indica nulla, saranno proposti i pulsanti
    Ok
    e
    Annulla
    . Di tipo Int. Parametro Opzionale.
  4. iTasto. Il numero del pulsante da rendere come predefinito, nell’ordine determinato dalla linea dei Tab; se non si indica nulla, sarà impostato il primo tasto. Di tipo Int. Parametro Opzionale.
  5. iNoSuoni. Se valorizzato con TRUE, elimina l’icona ed i suoni per la finestra di dialogo; se non si indica nulla, icone e suoni saranno proposti, secondo l’abbinamento sulla base del valore indicato come terzo parametro. Di tipo Int. Parametro Opzionale.
Novità.
  1. La chiamata della nostra funzione
    AssegnaEsadecimali ().
  2. Le costanti native
    MB_DEFBUTTON1,
    MB_DEFBUTTON2,
    MB_DEFBUTTON3
    e
    MB_DEFBUTTON4
    , equivalenti ai valori esadecimali che impostano il pulsante progressivo indicato come quello predefinito, dove si posiziona il cursore all’ingresso nella finestra di dialogo.
Fasi.
  1. Dopo aver casomai attivato la sintesi, chiamando la nostra apposita funzione, sono effettuati una serie di controlli sui parametri eventualmente specificati, impostando i valori predefiniti nel caso in cui il parametro relativo a ciascun dato sia vuoto.
  2. Tra le impostazioni preliminari, viene chiamata la nostra funzione
    AssegnaEsadecimali ()
    , che determina il tipo di tasti, e le icone ed i suoni abbinati.
  3. Se il quinto parametro è vuoto, oppure non ha un valore positivo, viene proposta la finestra di dialogo con testo, icona e suoni. Se tale parametro è stato invece valorizzato con
    TRUE
    ,si propone invece una conferma solo testuale.
  4. Dopo aver casomai di nuovo spento la sintesi, si analizza la scelta effettuata. Nel dettaglio, sarà restituito un valore negativo, nel caso in cui si sia risposto
    "No"
    , oppure un valore nullo, nel caso di Escape o Annulla, o altrimenti ogni altro valore positivo che sia stato scelto.
Note.
  1. Tale funzione nasce dall’esigenza di automatizzare sia l’inserimento dei testi per titoli o messaggi, sia soprattutto l’analisi delle scelte operate, che in questa forma consentono di utilizzare la funzione anche direttamente come struttura di controllo.
  2. Mentre per quel che riguarda tipo di tasti, icone e suoni, abbiamo delegato l’impostazione materiale ad una funzione esterna, il pulsante predefinito viene impostato direttamente all’interno della funzione, tramite un’apposita struttura di controllo. Tale scelta è dettata dal fatto che le opzioni possibili sono solo quattro, anziché sei come quelle dei pulsanti, delle icone e dei suoni.

Codice.


Int Function ChiedeConferma (string sTitolo, string sMessaggio, ; intestazione con due parametri,
int iOpzioni, int iTasto, int iNoSuoni); seconda riga con gli altri tre
Var
Int iStato, ; attivazione della sintesi vocale
int iDettagli, ; valore esadecimale per icona e suoni
Int iScelta; valore della scelta effettuata
Let iStato = ControllaSintesi (TRUE, TRUE); riattiva la sintesi, annotandone l’attuale stato di attivazione
If !sTitolo ; se nessun titolo è stato specificato,
&& !sMessaggio Then; e se non lo è stato neppure un messaggio,
Let sTitolo = msgConfermaUscita; imposta un messaggio come titolo
EndIf; fine controllo titolo e messaggio
AssegnaEsadecimali (iOpzioni, iDettagli); imposta i valori tramite l’apposita funzione
If !iTasto || iTasto == PRIMA Then; se non è stato indicato nulla, oppure il primo valore,
Let iTasto = MB_DEFBUTTON1; aggiorna come predefinito il primo pulsante nella linea dei tasti Tab
ElIf iTasto == SECONDA Then; se invece è stato indicato il secondo valore,
Let iTasto = MB_DEFBUTTON2; aggiorna come predefinito il secondo pulsante
ElIf iTasto == TERZA Then; se invece è stato indicato il terzo valore,
Let iTasto = MB_DEFBUTTON3; aggiorna come predefinito il terzo pulsante
Else; altrimenti,
Let iTasto = MB_DEFBUTTON4; aggiorna come predefinito il quarto pulsante
EndIf; fine controllo tasto predefinito
If !iNoSuoni Then; se non è stata indicata la cancellazione dei suoni,
Let iScelta = ExMessageBox (sMessaggio, sTitolo, iOpzioni|iTasto|iDettagli); propone la classica conferma
Else; altrimenti,
Let iScelta = ExMessageBox (sMessaggio, sTitolo, iOpzioni|iTasto); la propone senza icona e suoni
EndIf; fine controllo sintassi
ControllaSintesi (iStato, TRUE); ripristina, o lascia invariato, il precedente stato di attivazione della sintesi
If iScelta == IDNO Then; se si è premuto il tasto No,
Return -1; restituisce un risultato negativo
ElIf iScelta == IDCANCEL Then; se invece si è premuto Escape o Annulla,
Return FALSE; restituisce un risultato nullo
Else; altrimenti,
Return iScelta; restituisce la scelta operata
EndIf; fine controllo scelta
EndFunction

Collaudo.

  1. Pur rinviando al primo script utile il collaudo operativo della funzione, si consiglia di rendere subito opzionali tutti e cinque i parametri previsti, ponendo la parola chiave
    :Optional
    immediatamente dopo l’indicazione della categoria nella scheda della funzione all’interno del file
    JSD
    . Ricordiamo di uscire dall’Editor dopo aver salvato le modifiche ed aver ricompilato correttamente il file script, per rendere effettivi i cambiamenti.

Esercizio 9.5.9. La funzione DatiStato.

FileScript.

Default.JSS

Nome.

DatiStato

Descrizione.

Rileva i dati registrati per il tipo richiesto. In caso di mancata lettura, se viene attivata la fase Aiuto, assegna al tipo richiesto il primo dato utile nella Barra di stato.

Ritorni.

Di tipo Int. L’esito del controllo: 1 o TRUE se le informazioni registrate per il tipo di dato sono state rilevate, 0 o FALSE, per informazioni mancanti.

Parametri.
  1. sNome. Il tipo di dato da estrarre. Di tipo String.
  2. sDivide. Il carattere di separazione delle diverse zone nella Barra di stato. Di tipo String.
  3. sInfo. Per Riferimento. La stringa registrata per il tipo di dato richiesto. Di tipo String.
  4. iPosiz. Per Riferimento. La posizione della zona da estrarre nella Barra di stato. Di tipo Int.
  5. iAiuto. Per Riferimento. Se positivo, indica l’attivazione dell’omonima fase. Di tipo Int.
Novità.
  1. La nostra funzione
    CancellaChiave ().
  2. La funzione integrata
    StringStartsWith
    , (IniziaDatoTestualeCon), che serve a determinare se la stringa posta come primo parametro inizia con quella specificata come secondo. La funzione ha anche un terzo parametro opzionale, che se valorizzato con
    TRUE
    , stabilisce che il confronto tra le due stringhe deve rispettare le maiuscole e minuscole. Se non lo si indica, sarà impostato il valore
    FALSE
    , che invece disabilita questo tipo di controllo.
  3. Le costanti
    TESTO
    e
    SEPARATORE
    , che equivalgono alle chiavi del dato in cui memorizzare, nell’ordine, il contenuto della Barra di stato ed il separatore predefinito.
  4. L’altra nostra costante
    BASE_ZONE
    , che comprende un valore da aggiungere per identificare le zone nella Barra di stato divise dal separatore predefinito, di norma corrispondente al valore 2.
Fasi.
  1. Se sono lette delle informazioni registrate sul tipo di dato richiesto, trasmette anche il valore con la posizione e restituisce l’esito positivo.
  2. Se invece non sono state lette tali informazioni, qualora non sia stata attivata la fase di Aiuto, il flusso si interrompe restituendo un risultato nullo.
  3. Sempre in caso di mancata lettura, ma con la fase Aiuto attiva, si assegna al tipo di dato richiesto la prima zona utile nella Barra di stato, per poi restituire comunque un esito positivo.
Note.

L’assegnazione in modo automatico di una zona al tipo di dato richiesto , che avviene solo nel caso di fase Aiuto attiva, suppone che tale tipo di dato sia il primo tra quelli privi di una qualsiasi assegnazione. Se poi il dato estratto dalla Barra di stato si rivelasse inesatto, si dovrà correggere o completare con una modifica manuale delle impostazioni.

Codice.


Int Function DatiStato (string sNome, string sDivide, ; intestazione con due parametri,
string ByRef sInfo, int ByRef iPosiz, int iAiuto); seconda riga con gli altri tre
Var
String sElenco, ; chiavi dei dati registrati
String sChiave, ; singola chiave del dato
Int i, ; contatore del ciclo
Int iValidi; numero dei dati da considerare
; tenta di leggere le informazioni sul dato da estrarre, trasmettendole casomai per riferimento
Let sInfo = StringLower (LeggeDato (CORRENTE, BARRA_STATO, sNome))
If sInfo Then; se delle voci sono state rilevate,
Let iPosiz = StringToInt (StringSegment (sInfo, PIPE, PRIMA)); ne trasmette la posizione,
Return TRUE; e restituisce l’esito positivo
Else; altrimenti, se non è registrata alcuna informazione sul dato richiesto,
If !iAiuto Then; se la fase omonima non è attiva,
Return FALSE; interrompe il flusso, restituendo un risultato nullo
EndIf; fine controllo Aiuto
CancellaChiave (CORRENTE, BARRA_STATO, sNome); rimuove l’eventuale chiave
Let sElenco = LeggeChiavi (CORRENTE, BARRA_STATO); rileva le chiavi dei dati registrati
For i = 1 To StringSegmentCount (sElenco, PIPE); scorre i dati rilevati
Let sChiave = StringSegment (sElenco, PIPE, i); estrae una singola chiave dall’elenco
If !StringStartsWith (sChiave, TESTO) ; se il dato non corrisponde ad una delle zone
&& sChiave != SEPARATORE Then; e nemmeno al carattere separatore delle zone,
Let iValidi = iValidi + 1; aggiorna il contatore dei dati da considerare
EndIf; fine controllo dati
EndFor; fine ciclo scansione dati
If sDivide == DIVIDE_ZONE Then; se il separatore è quello standard,
; trasmette la posizione aggiungendo il numero base a quello rilevato
Let iPosiz = iValidi + BASE_ZONE
Else; altrimenti,
Let iPosiz = iValidi + 1; la trasmette aggiungendovi solo un’unità
EndIf; fine controllo separatore
Let sInfo = IntToString (iPosiz); trasmette per riferimento la sola posizione del dato,
ScriveDato (CORRENTE, BARRA_STATO, sNome, sInfo); trascrive i dati rilevati,
Return TRUE; e restituisce l’esito positivo
EndIf; fine controllo presenza voci
EndFunction

Esercizio 9.5.10. La funzione InfoStato.

FileScript.

Default.JSS

Nome.

InfoStato

Descrizione.

Verifica il tipo di dato richiesto nella Barra di stato, e se vi siano i dati per rilevarlo, casomai restituendolo sotto forma testuale.

Ritorni.

Di tipo String. Il dato richiesto, rilevato dall’ultima riga in basso nella finestra.

Parametri.
  1. sNome. Il tipo di dato richiesto. Di tipo String.
  2. iAiuto. Se positivo, indica l’attivazione dell’omonima fase. Di tipo Int.
Novità.
  1. Le nostre funzioni
    BarraStato (),
    ControllaSeparatore (),
    ChiedeConferma ()
    e
    DatiStato ().
  2. La costante
    CICLO_VOCI
    , la quale corrisponde al numero di voci che compone una
  3. La costante
    _O
    , che contiene l’omonimo carattere usato per formattare al maschile singolare un messaggio.
Fasi.
  1. Si rileva il testo tramite la nostra funzione
    BarraStato ().
  2. Nel caso in cui non si sia rilevato alcun testo, e sia attiva la fase Aiuto, viene letto un avviso che invita a far visualizzare la Barra di stato dall’applicativo. In ogni caso, il flusso si interrompe restituendo una stringa vuota.
  3. Nel caso che del testo sia invece presente, si controlla poi se dentro a quest’ultimo vi sia registrato un separatore. In caso contrario, se la fase Aiuto è attiva, viene proposta una conferma, e la possibilità di inserire direttamente il dato richiesto.
  4. Se anche dopo l’eventuale aggiornamento il separatore non c’è, si annota di tale assenza nell’archivio, restituendo una stringa vuota ed interrompendo il flusso.
  5. Se invece un separatore è presente, dapprima si annotano nel file configurazione le varie porzioni di testo suddivise dal separatore definito, quindi Si tenta di leggere i dati registrati per il tipo richiesto. Qualora non ve ne siano di registrati, il flusso viene interrotto restituendo una stringa vuota.
  6. Se i dati sono stati registrati, si tenta di leggere il tipo di dato richiesto dentro al testo rilevato. Se tale operazione non riesce, si interrompe il flusso tramite la restituzione di una stringa vuota, casomai leggendo un avviso se fosse attiva la fase Aiuto.
  7. Se la zona richiesta della Barra di stato è stata rilevata, si inizia un ciclo che tenta di prelevare, all’interno della zona estratta, il dato richiesto, eventualmente cancellando le stringhe indicate a tal scopo, oppure estraendolo da i sottodati specificati. In ogni caso, il testo elaborato viene restituito come risultato della funzione.
Note.

In fase di collaudo sarà più chiaro come riuscire ad estrarre il meglio da tale funzione, che rappresenta un modello di come si possa utilmente impostare il lavoro degli script tramite gli archivi di configurazione. Essa è il vero cuore della procedura, dove le funzioni precedenti sono necessarie soltanto per consentire la sua chiamata dalle diverse tipologie di applicativo.

Codice.


String Function InfoStato (string sNome, int iAiuto)
Var;
String sTesto, ; contenuto della Barra di stato
String sDivide, ; carattere di separazione delle voci nella Barra di stato
Int i, ; contatore del ciclo
String sInfo, ; informazioni registrate
Int iPosiz, ; numero del segmento da estrarre
String sDato, ; stringa da estrarre
Int iTotali, ; numero complessivo delle voci da analizzare
Int iVoci , ; contatore delle voci analizzate
String sVoce, ; singola informazione registrata
Int iFase; contatore delle fasi di analisi delle voci
Let sTesto = BarraStato (); rileva la riga di stato tramite l’apposita funzione
If !sTesto Then; se nessun testo è stato rilevato,
If iAiuto Then; se è attiva la fase ,
SayFormattedMessage (OT_ERROR, hlpAttivaBarra, hlpAttivaBarra_corto); legge l’avviso
EndIf; fine controllo aiuto
Return NULLO; in ogni caso, restituisce una stringa vuota
EndIf; fine controllo testo
If !ControllaSeparatore (sTesto, sDivide) Then; se nessun carattere separatore è valido,
If iAiuto Then; se è attiva la fase,
If ChiedeConferma (ttlNoSepara, FormatString (msgImmissione, _O)) Then; se lo si vuole inserire,
Let sDivide = DIVIDE_ZONE; preimposta il carattere predefinito per l’inserimento
If InputBox (msgInserisciRiga, ttlSeparatore, sDivide); Then; se il dato è stato immesso,
ScriveDato (CORRENTE, BARRA_STATO, SEPARATORE, sDivide); trascrive il separatore,
CancellaChiave (CORRENTE, BARRA_STATO, TESTO); e rimuove un’eventuale trascrizione lineare
EndIf; fine controllo inserimento
EndIf; fine controllo conferma
If !sDivide Then; se non vi è alcun separatore,
; trascrive nel file di configurazione Personale:
ScriveDato (CORRENTE, BARRA_STATO, TESTO, sTesto); il testo rilevato,
ScriveDato (CORRENTE, BARRA_STATO, SEPARATORE, NESSUNO); l’assenza del separatore,
Return NULLO; e restituisce una stringa vuota
EndIf; fine controllo presenza dato
EndIf; fine controllo aiuto
EndIf; fine controllo separatore
For i = 1 To StringSegmentCount (sTesto, sDivide); scorre le porzioni del testo separate dal carattere individuato
Let sDato = TagliaSpazi (StringSegment (sTesto, sDivide, i)); estrae la singola zona,
ScriveDato (CORRENTE,BARRA_STATO, FormatString (msg2, TESTO, i), sDato); e la trascrive
EndFor; fine scansione segmenti
If !DatiStato (sNome, sDivide, sInfo, iPosiz, iAiuto) Then; se i dati non sono stati rilevati,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayMessage (OT_ERROR, hlpNoAutoDati, hlpNoAutoDati_corto)
EndIf; fine controllo aiuto
Return NULLO; in ogni caso, interrompe il flusso restituendo una stringa vuota
EndIf; fine controllo informazioni sul dato
; rileva il segmento relativo al dato richiesto, rendendolo minuscolo e togliendo spazi inutili
Let sDato = StringLower (TagliaSpazi (StringSegment (sTesto, sDivide, iPosiz)))
If !sDato Then; se non è stata rilevata alcuna stringa relativa al tipo di dato,
If iAiuto Then; se è attiva la fase, legge l’avviso
SayMessage (OT_ERROR, hlpInfoErrate, hlpInfoErrate_corto)
EndIf; fine controllo Aiuto
Return NULLO; in ogni caso, interrompe il flusso restituendo una stringa vuota
EndIf; fine controllo rilevamento zona
Let iTotali = StringSegmentCount (sInfo, PIPE); conta il numero delle voci per estrarre il dato
If iTotali < CICLO_VOCI Then; se il numero di analisi è inferiore al minimo,
Let iTotali = CICLO_VOCI; aggiorna il valore
EndIf; fine controllo voci rilevate
Let iFase = SECONDA; predispone la fase di analisi delle voci per partire dalla terza
Let iVoci = PRIMA; e il contatore delle voci per iniziare dalla seconda
While iFase || iVoci < iTotali; continua se una fase è impostata e ci sono voci da elaborare
Let iVoci = iVoci + 1; aggiorna il contatore
Let sVoce = StringSegment (sInfo, PIPE, iVoci); estrae la singola voce
Let iFase = iFase + 1; aggiorna il contatore della fase di estrazione
If iFase == PRIMA Then; se la voce è relativa al separatore,
If sVoce Then; se la stringa non è vuota,
Let sDivide = sVoce; imposta il separatore della zona del dato
Else; altrimenti,
Let sDivide = SPACE; imposta il carattere Spazio
EndIf; fine controllo voce
ElIf iFase == SECONDA Then; se invece si estrae il valore numerico,
Let iPosiz = StringToInt (sVoce); converte e salva la posizione del dato nel segmento estratto
If !iPosiz Then; se nessun valore è stato rilevato,
Let iPosiz = PRIMA; imposta la parte del dato da estrarre
EndIf; fine controllo posizione
; estrae il sottodato, rimuovendo gli spazi in eccesso
Let sDato = TagliaSpazi (StringSegment (sDato, sDivide, iPosiz))
ElIf iFase == TERZA Then; se infine si tratta di una stringa da rimuovere,
If sVoce Then; se tale stringa non è vuota,
; rimuove la parte di dato non necessaria, eliminando anche gli spazi in eccesso
Let sDato = TagliaSpazi (StringReplaceSubstrings (sDato, sVoce, NULLO))
EndIf; fine controllo rimozione stringa
Let iFase = FALSE; e azzera il valore per poter iniziare da capo
EndIf; fine controllo fasi
EndWhile; fine scansione voci
Return sDato; restituisce il testo estratto
EndFunction

Unificare la gestione dei dati.

Siamo così giunti all’ultimo blocco di elementi della sezione, il quale comprende gli script che useremo per il collaudo e, soprattutto, la funzione,
GestisceDato
. Essa ha l’intento di centralizzare tutte le azioni inerenti alla gestione dei dati e, così come si accennava, sarà proposta in una prima versione molto minimale che aggiorneremo nel corso dei prossimi capitoli.

In generale, essa rappresenta un elemento fondamentale dei nostri script. Il suo compito, oltre a quello di eseguire delle mansioni preliminari, sarà principalmente quello di verificare se le azioni richieste siano conformi e, in tal caso, raccogliere i dati necessari a completare correttamente il lavoro da svolgere.

La vera novità di questo elemento di codice sarà la funzione integrata
CallFunctionByName
, (ChiamaFunzioneTramiteNome). Essa consente di indicare un primo parametro composto dal nome della funzione da chiamare, ed in quelli successivi gli eventuali parametri da far passare alla funzione chiamata.

Per questa sua prima versione, la funzione di gestione non avrà parametri, e raccoglierà i dati necessari al suo funzionamento dai nomi degli script chiamanti. Ciò consentirà di attivarla usando nel contenuto degli script il solo nome, senza altri dati, generalizzando e semplificando così le istruzioni per tale attivazione.

Ad esempio, ipotizziamo che a chiamare la funzione che si occupa di gestire i dati sia uno script che ha per nome:

PronunciaStatoRiga ()

In questo caso, la prima parola,
Pronuncia
, sarebbe l’azione, cui andrà aggiunto un suffisso comune a tutti gli elementi di questo tipo, che sarà
Dato
. Così, la funzione chiamata da
CallFunctionByName
, sarà la nostra
PronunciaDato ()
, che andremo tra poco a realizzare.

Esercizio 9.5.12. La funzione NoZero.

FileScript.

Default.JSS

Nome.

NoZero

Descrizione.

Converte in un dato testuale il valore passato come parametro, restituendo una stringa vuota qualora il valore fosse 0.

Ritorni.

Di tipo String. Il valore in forma testuale, oppure una stringa vuota in caso di zero.

Parametri.
  1. iValore. Il dato numerico di cui restituire la forma testuale. Di tipo Int.

Codice.


String Function NoZero (int iValore)
If iValore Then; se un valore è stato specificato,
Return IntToString (iValore); lo restituisce in forma testuale
Else; altrimenti,
Return NULLO; restituisce una stringa vuota
EndIf; fine controllo valore
EndFunction

Esercizio 9.5.13. La funzione PronunciaDato.

FileScript.

Default.JSS

Nome.

PronunciaDato

Descrizione.

Gestisce la lettura di un dato, testuale o numerico, eventualmente facendolo precedere da un termine esplicativo, nei casi di messaggi lunghi, oppure segnala la mancanza del dato da leggere.

Ritorni.

Di tipo Void. Nessuno.

Parametri.
  1. sTitolo. Il termine esplicativo da anteporre al dato nei messaggi lunghi. Di tipo String.
  2. sDato. Il dato testuale da leggere. Di tipo String.
  3. iAiuto. Se positivo, attiva la fase Aiuto. Di tipo Int.
Fasi.
  1. Se un dato è stato specificato, in caso di messaggi lunghi una prima funzione di lettura viene attivata per leggere il titolo esplicativo del dato. Di seguito, una seconda funzione di lettura legge in ogni caso il dato.
  2. Se invece nessun dato è presente, nel caso sia stata attivata la fase Aiuto, si viene avvisati di tale assenza.
Note.
  1. In questo caso, il titolo ed il dato si sarebbero potuti leggere anche con una sola funzione di lettura. Tale sdoppiamento, tuttavia, ci consente di far leggere il solo titolo esplicativo in un tono diverso dal dato, così da poterli meglio distinguere anche in caso della lettura di entrambi.
  2. La soluzione adottata, inoltre, ci consente anche di illustrare il funzionamento della costante
    CR
    , la quale può essere inserita in una dei due parametri riservati ai messaggi lunghi o corti di una funzione di lettura, al fine di disabilitarli a prescindere dalle impostazioni di prolissità attive.

Codice.


Void Function PronunciaDato (string sTitolo, string sDato, int iAiuto)
If sDato Then; se una posizione è stata rilevata,
SayMessage (OT_ERROR, sTitolo, CR); legge il termine solo in caso di messaggi lunghi
SayFormattedMessage (OT_HELP, msg1, NULLO, sDato); legge comunque il dato
ElIf iAiuto Then; se invece non vi è alcun dato, e si è nell’omonima fase,
SayFormattedMessage (OT_ERROR, hlpNoDato, hlpNoDato_corto, sTitolo); legge un avviso
EndIf; fine controllo dato
EndFunction

Esercizio 9.5.14. La funzione GestisceDato.

FileScript.

Default.JSS

Nome.

GestisceDato

Descrizione.

Raccoglie le richieste di azioni sui dati, verificandone la correttezza e smistando il flusso verso gli opportuni elementi di codice.

Ritorni.

Di tipo Void. Nessuno.

Novità.
  1. La nostra funzione
    SeparaParole ()
    , che serve in questo caso a leggere l’azione da compiere e l’oggetto cui si rivolge, nonché la categoria dell’azione, se indicata nel nome dello script.
  2. La funzione integrata
    CallFunctionByName ()
    , descritta in precedenza, che chiama a sua volta la funzione di cui compone il nome utilizzando i dati elaborati.
  3. La nostra funzione
    InfoStato ()
    , che determina quale dato leggere nella Barra di stato.
  4. La nostra funzione
    NoZero ()
    , che serve solo a convertire il dato numerico togliendo eventuali valori nulli.
  5. Le costanti
    PRONUNCIA,
    STATO
    e
    DATO
    , che servono, la prima, per intercettare l’azione di lettura dati, la seconda, per identificare la tipologia di azione richiesta, e la terza, per costituire il suffisso comune a tutte le funzioni che appartengono alla procedura di gestione dati.
Fasi.
  1. Un controllo sulla finestra, se negativo, ripete gli ultimi tasti premuti ed interrompe il flusso. Altrimenti, si rilevano la fase Aiuto ed i dati rilevati dal nome dello script.
  2. Una prima struttura verifica che l’azione richiesta sia di lettura e, in caso positivo, controlla poi se i dati debbano essere rilevati dalla Barra di stato. Se così è, si attiva l’apposita procedura ponendo come parametro l’oggetto rilevato dal nome script
  3. Se si è chiesta la lettura, ma la categoria dell’azione è una qualsiasi altra, il dato viene ricavato da una funzione il cui nome sarà composto dalla categoria stessa più l’oggetto.
  4. Rilevato il dato da leggere, si utilizza l’istruzione che chiama a sua volta la nostra apposita funzione, il cui nome sarà composto dall’azione rilevata più il suffisso comune a tutte le funzioni di questo tipo.

Codice.


Void Function GestisceDato ()
If !SiamoNellaFinestra (EDITING) Then; se non si è nella finestra corretta,
PronunciaEsegue (); ripete i tasti di attivazione,
Return; e interrompe il flusso
EndIf; fine controllo finestra
Var
Int iAiuto, ; stato di attivazione della fase Aiuto
String sProg, ; eventuale numero progressivo indicato tramite il nome dello script
String sAzione, ; operazione richiesta dallo script chiamante
String sCategoria, ; tipologia dell’azione da compiere
String sOggetto, ; nome dell’oggetto cui rivolgere l’azione
String sDato; dato testuale da sottoporre all’azione
Let iAiuto = IsSameScript (); rileva l’eventuale doppia pressione dei tasti di attivazione
; estrae i dati dal nome dello script chiamante tramite l’apposita funzione
Let sProg = SeparaParole (sAzione, sCategoria, sOggetto)
If sAzione == PRONUNCIA Then; se si sono chieste azioni di lettura,
If sCategoria == STATO Then; se si sono richiesti dati dalla Barra di stato,
Let sDato = InfoStato (sOggetto, iAiuto); rileva il dato dalla funzione generica
Else; altrimenti, in tutti gli altri casi,
; Rileva il dato dalla funzione di cui si compone il nome
Let sDato = NoZero (CallFunctionByName (sCategoria + sOggetto))
EndIf; fine controllo categoria
CallFunctionByName (sAzione + DATO, sOggetto, sDato, iAiuto); esegue l’azione
EndIf; fine primo controllo azioni
EndFunction

Esercizio 9.5.15. Lo script PronunciaStatoRiga.

FileScript.

Default.JSS

Nome.

PronunciaStatoRiga

Sommario.

Legge il numero di riga.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla riga in cui è posto il cursore.

TastiAttivazione.

Control+J

Novità.
  1. La prima chiamata della nostra funzione
    GestisceDato ()
    , la quale consente di passare dei parametri attraverso il nome dello script che la attiva.

Codice.


Script PronunciaStatoRiga ()
GestisceDato (); chiama la funzione generica
EndScript

Collaudo.

Nonostante si tratti di uno script, portate ancora un po’ di pazienza, perché dovremo attendere ancora l’ultimo dei tre per collaudare la procedura nel suo complesso.

Esercizio 9.5.16. Lo script PronunciaStatoColonna.

FileScript.

Default.JSS

Nome.

PronunciaStatoColonna

Sommario.

Legge il numero di colonna.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla colonna in cui è posto il cursore.

TastiAttivazione.

Control+K

Codice.


Script PronunciaStatoColonna ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.5.17. Lo script PronunciaStatoLunghezza.

FileScript.

Default.JSS

Nome.

PronunciaStatoLunghezza

Sommario.

Legge la lunghezza del documento corrente.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato corrispondente alla lunghezza del documento aperto nell’applicativo.

TastiAttivazione.

Control+OGrave

Note.
  1. Circa il tasto di attivazione proposto, seguendo la serie dei tasti affiancati, a questo script che riguarda la lunghezza, sarebbe stato lecito attendersi di usare la combinazione con il tasto successivo,
    Control+L
    . Tale combinazione, tuttavia, ha un’importante utilizzo proprio nell’Editor di Script, attivandone la ricerca rapida, ed anche solo per questo motivo si è proposto, assieme al tasto
    Control
    , di premere quello ancora più a destra, la
    OGrave
    , appunto.

Codice.


Script PronunciaStatoLunghezza ()
GestisceDato (); chiama la funzione generica
EndScript

Collaudo della procedura sulla Barra di stato.

Siamo finalmente arrivati al test che riguarda in realtà entrambe le procedure, sia quella relativa ai dati nella Barra di stato, sia quella per la gestione generica dei dati.

Nelle varie funzioni interessate, in ogni caso, pochi parametri e nessuno di questi opzionale. La compilazione, dunque, non dovrebbe aver riservato grosse sorprese, e per eseguire il collaudo non vi resta quindi che seguire questi passi:

  1. Da dentro all’Editor di Jaws, con un qualunque file script caricato, diamo per scontato che abbiate già attivato la Barra di stato nel menu
    Visualizza
    , e per verificarlo agite sul comando di Jaws
    TastoJaws+PaginaGiù
    , leggendo così l’ultima riga in basso nello schermo. Assieme ad altre informazioni, fate attenzione se tra i dati letti vi sono due o tre numeri, ed in particolare uno riferito alla colonna su cui è posto il cursore, la cui presenza dipende dalla versione dell’Editor di Script che state usando. Se avete dubbi, consultate la
    Cronologia della Sintesi
    , per rilevarlo in modo più comodo.
  2. eseguite quindi lo script
    PronunciaStatoRiga ()
    ,premendo una sola volta
    Control+J
    . In apparenza non è successo nulla, perché niente è stato vocalizzato, ma in realtà nell’archivio di configurazione dell’Editor di Script si è già creata la sezione denominata
    BarraStato
    , si è tentato di annotare il carattere di separazione delle zone di testo e, qualora questa operazione non fosse riuscita, si è trascritto il contenuto dell’ultima riga in basso nello schermo.
  3. Adesso, senza muovervi dalla riga dove eravate, premete due volte rapidamente la combinazione dello script,
    Control+J
    . Se tutto va bene, la procedura ha individuato la zona della Barra di stato che contiene il numero analizzato in precedenza, e l’ha isolato dalle altre informazioni presenti. Per questo, vi dovrebbe essere pronunciato uno dei numeri letti in precedenza, casomai preceduto dal termine
    Riga
    , qualora abbiate impostati i livelli di prolissità per i messaggi lunghi. Da questo punto in poi, ad ogni pressione di
    Control+J
    , vi sarà ripetuta la lettura del numero di riga su cui è posto il cursore.
  4. Ora, solo nel caso in cui i dati numerici presenti nella Barra di stato fossero tre, con la presenza quindi anche del numero di colonna, premete due volte rapidamente i tasti di attivazione per lo script
    PronunciaStatoColonna()
    , che se vi ricordate è
    Control+K
    . Anche in questo caso, se tutto va bene, Jaws dovrebbe leggervi il dato corrispondente alle colonne, sempre preceduto dal prefisso identificativo qualora vi siano letti i messaggi lunghi.
  5. In qualsiasi caso, a questo punto premete due volte rapidamente la combinazione che attiva lo script
    PronunciaStatoLunghezza ()
    , che è
    Control+OGrave
    . Come in precedenza, vi sarà letto un valore, che dovrà corrispondere a quello che avete appena rilevato nella riga di stato. Anche in tal caso, da questo momento in poi, ogni altra pressione di
    Control+OGrave
    vi pronuncerà il numero delle righe totali del file script.

Tutto a posto, quindi, e tutto facile?

In realtà, il caso dell’Editor di Script è abbastanza particolare, perché la procedura, seguendo i passi consigliati nella sequenza suggerita, consente di impostare i dati correttamente ed in modo automatico. Appare opportuno, tuttavia, fermarci per capire come funziona la procedura, così da essere in grado poi di modificare a mano le impostazioni in tutti gli altri casi dove tale automatismo non è possibile.

Come funziona la procedura.

Per capire cosa è stato fatto, e cosa quindi bisogna fare in altre occasioni, apriamo l’archivio di configurazione dell’Editor di Script, che avrà il nome definito sulla base della versione da voi utilizzata, come abbiamo già analizzato nel Capitolo 7.

Una volta aperto, cercate la sezione
BarraStato
, ricordandovi di specificare anche le parentesi quadre agli estremi. Il suo contenuto potrebbe avere una forma simile, a prescindere dai valori presenti nei dati delle righe contrassegnate dalla chiave che inizia con il termine
Testo
, seguito da un suffisso numerico, che abbiamo assegnato noi in modo arbitrario:

Questi, nel dettaglio, potrebbero essere i dati trascritti nelle versioni precedenti dell’Editor di Script, quelle senza il numero di colonna:


[BarraStato]
Separatore=:
Testo1=Per la guida, premere F1 Riga
Testo2= 22 Righe totali
Testo3=33
Riga=2
Lunghezza=3

Dall’analisi di queste impostazioni, si inizia con l’evidenziare che il separatore individuato, quello che divide la riga di testo nelle diverse zone, è quello predefinito, il carattere Due Punti.

Partendo da questa base, la riga che si trovava in basso nello schermo è stata suddivisa proprio in base a tale separatore, in tre segmenti, che corrispondono ad altrettante zone di dati.

Di queste zone, la seconda è quella che contiene il numero di riga, che nel nostro esempio abbiamo rappresentato con il valore 22, ed in effetti il dato che ha come chiave la parola
Riga
, è proprio il numero 2.

Allo stesso modo, poiché il numero delle righe totali, che abbiamo invece rappresentato con 33, è inserito nella terza zona, ed il valore del dato che ha come chiave la parola
Lunghezza
è appunto il numero 3.

In pratica, la procedura, per estrarre i dati dalle varie zone, si serve di tre dati:

  1. Il carattere Separatore.
  2. Il numero progressivo della zona da estrarre.
  3. Un eventuale testo da rimuovere.

I primi due dati sono necessari, e per quanto riguarda il nostro caso sono il carattere Due Punti come separatore, definito nell’assegnazione omonima a sé stante, ed il primo valore nelle due assegnazioni dopo il carattere Uguale, 2 per
Riga
, e 3 per
Lunghezza.

A proposito del valore numerico, va chiarito che se esso è positivo, così come nei nostri due esempi, il valore corrisponde al numero progressivo delle zone a partire da sinistra. Se invece il numero specificato fosse negativo, preceduto quindi dal segno Meno,
-
, tali zone sarebbero da intendersi da destra.

I dati relativi al solo numero progressivo di una prima zona estratta non sono però sufficienti a farci ricavare il dato pulito, senza informazioni che non ci interessano. Infatti, se noi volessimo isolare ad esempio il dato sul numero di riga, che è inserito nella seconda zona, quella contrassegnata dalla chiave
Testo2
, sulla base della sola prima serie di dati, noi otterremmo questo testo:


22 Righe totali

Quindi, poiché noi da questo dobbiamo estrarre il solo dato
"22"
, abbiamo bisogno di almeno un’altra serie di tre dati, i due obbligatori e quello facoltativo. Per essere passati alla procedura, questi dati devono essere separati tra loro dal carattere Pipe, l’Ascii 124, il quale crea in pratica dei campi distinti che possono avere o meno un loro contenuto. Se un dato non viene specificato, bisogna mettere comunque un carattere Pipe per ogni dato che si vuole sia considerato, almeno così da creare un campo che poi andrà comunque conteggiato dalla procedura. Se non si specifica nulla tra uno di questi caratteri speciali e l’altro, il dato viene ignorato oppure ne viene assunto il valore predefinito.

Tornando al nostro esempio precedente, è come se noi avessimo questa riga di dati:


Riga=2|| |1

Questi dati rappresentano quindi due serie, che fanno compiere alla procedura due azioni distinte:

  1. Usando il separatore impostato a sé stante, preleva la seconda zona delimitata dai due punti, senza cancellare alcun carattere perché il campo relativo è vuoto.
  2. Dal testo così ottenuto, usa come separatore un carattere Spazio, indicato nel campo apposito, che preleva la sottozona 1 del testo elaborato, anche in questo caso senza cancellare nulla, poiché stavolta l’ultimo campo non è nemmeno stato specificato.

Quando ci si limita ad indicare un numero dopo l’assegnazione, senza aggiungere una seconda serie di dati, la procedura esegue comunque, ed in modo automatico, una seconda serie di azioni. Per ovviare all’assenza dei dati, essa assumerà per ciascuno di essi i valori predefiniti, che sono proprio un carattere Spazio come separatore ed il numero 1 come sottozona da prelevare.

Per completare l’informazione, proponiamo la stessa trascrizione di dati, relativa però alle versioni più aggiornate dell’Editor di Script, quelle con i tre dati:


[BarraStato]
Separatore=:
Testo1=Per la guida, premere F1 Ln
Testo2=22 Col
Testo3=33 Linee totali
Testo4= 44
Riga=2
Colonna=3
Lunghezza=4

Tra le differenze, essendoci un dato in più, la lunghezza sarà estratta dalla quarta sezione della riga, mentre dalla terza se ne ricaverà il dato sul numero di colonna. Per il resto, il funzionamento è uguale all’altra versione, il dato viene prelevato in automatico da sinistra, e non sarà quindi necessario specificare una seconda serie di dati.

Nei casi come quello dell’Editor di Script, quindi, la nostra procedura sulla Barra di stato non necessita di particolari manovre. Conviene perciò analizzare il caso di un altro applicativo, in modo da testare più efficacemente la nostra procedura sulla Barra di stato.

Impostare i dati per il Blocco Note.

Prima di qualsiasi prova all’interno del Blocco Note, dobbiamo prima eliminare un elemento di codice che svolge la stessa funzione, utilizzando gli stessi tasti, di quello appena creato per leggere il numero di riga, che è ancora presente nel file script esterno di questo applicativo. Provate quindi a seguire questi passi:

  1. Aprite il file script
    BloccoNote.JSS.
  2. Portatevi sullo script
    PronunciaValoreRiga ()
    e cancellatelo con
    Control+Delete
    . Compilate, e chiudete il file script con
    Control+F4.
  3. Caricate il Blocco Note, ed aprite un file che abbia almeno qualche riga di testo. Da qui, premete subito due volte velocemente la combinazione
    Control+J.
  4. Qualora la procedura non individui alcun dato utile nell’ultima riga in basso nello schermo, sarete avvisati di tale mancanza e vi sarà chiesto di controllare che la Barra di Stato sia attivata. Se questo è il vostro caso, rimediate cambiando l’impostazione nel menu Visualizza, casomai uscendo e poi rientrando nel Blocco Note, e ripetete la doppia pressione.
  5. Qualora invece la barra sia attivata, sarete avvisati che non è stato individuato un separatore delle voci, consentendo di inserirlo direttamente. Premete tuttavia il tasto Escape, o cliccate su
    Annulla
    in quanto, prima di continuare, dovremo cercare di capire cosa è successo.
  6. Per questo motivo, aprite ora l’archivio di configurazione del Blocco Note,
    Notepad.JCF
    , e portatevi anche qui nella solita sezione, che dovrebbe avere il seguente aspetto:
  7. 
    [BarraStato]
    Testo=Linea 11, colonna 22 ...
    Separatore=Nessuno
    

Come potete notare, qui il separatore non è stato individuato, essendoci al suo posto la dicitura
Nessuno
, perché il carattere Due Punti non è presente nel testo riportato relativo all’ultima riga dello schermo. Proprio per questo motivo, tale contenuto è posto stavolta in un’unica riga, che ci serve ora per capire quale carattere poter utilizzare come separatore.

Analizzandone il suo contenuto, infatti, ci si può accorgere che almeno i due dati di nostro interesse, quelli relativi a riga e colonna, sono divisi da un carattere Virgola, che perciò potremo usare appunto come separatore.

Ora, chiudete il file di configurazione, tornate nel Blocco Note, e premete ancora due volte velocemente il comando di lettura riga,
Control+J
. Stavolta confermate l’inserimento, cliccando su
Ok
, ed al successivo campo digitate il carattere Virgola, quindi premete Invio.

A questo punto sarà pronunciato un dato, ma sarà la parola
Linea
, che è quella che precede il dato numerico.

Provate ora ad eseguire l’altro script,
PronunciaStatoColonna ()
, che si attiva con
Control+K
, anche in questo caso premuto due volte velocemente.

Il risultato dovrebbe essere analogo, e la parola letta in questo caso dovrebbe essere
Colonna.

Proviamo allora a riaprire l’archivio di configurazione del Blocco Note. Nell’apposita sezione, voi adesso dovreste trovare:


[BarraStato]
Separatore=,
Testo1=Linea 11
Testo2=colonna 22 ...
Riga=1
Colonna=2

Le impostazioni del numero di zona da prelevare, come abbiamo verificato, sono corrette, la prima per il numero di riga e la seconda per quello di colonna.

Se noi però vogliamo farci leggere il dato numerico, non la parola che lo precede, dovremmo far sì che il dato estratto non sia quello a sinistra, il quale è quello predefinito, bensì quello a destra, per il quale dovremo quindi integrare la forma dell’assegnazione attuale.

Qui, abbiamo due possibili modi di estrarre il solo dato a destra. Nell’esempio, utilizzeremo il primo per ottenere il numero di riga, ed il secondo metodo per acquisire quello di colonna:

  1. Nel primo caso, cancellare la parola che precede il dato, separandola con un carattere Pipe, e lasciando i valori predefiniti per la seconda serie di dati, ottenendo questa forma:
  2. 
    Riga=1|Linea
    

  3. Nel secondo caso, non cancellare nulla, confermando il separatore predefinito per la seconda serie di dati, e specificando per quest’ultima la zona 2. In questo caso, la forma per ottenere il numero di colonna sarebbe la seguente:
  4. 
    Colonna=2|||2
    

Se fate le modifiche proposte, e salvate la nuova forma delle due assegnazioni, tornate al Blocco Note per provare il risultato del vostro lavoro.

Un’ultima informazione, per chiudere l’argomento: da dentro il Blocco note, con un qualsiasi documento aperto, se provate a premere due volte velocemente anche la combinazione che esegue il nostro terzo script, quello sulla lunghezza totale,
Control+OGrave
, la procedura vi avviserà che la posizione è errata, e che non vi è nessun dato.

La posizione in questione è quella che in automatico la procedura ha assegnato a quel dato, che nel caso specifico appartiene alla zona numero 3. Se aprite il file di configurazione, troverete quindi la chiave
Lunghezza
con un valore impostato, il 3 appunto.

In questo caso, il dato necessario non esiste nella Barra di Stato, quindi non è neppure possibile tentare di modificarlo. In altri casi in cui, diversamente, la procedura non fosse in grado di rilevare il dato corretto, conviene comunque eseguire lo script relativo al dato da leggere perché, se non altro, predispone il file di configurazione con la chiave del dato già preimpostata, che è quindi solo casomai da aggiornare.

***

La Barra di stato e la gestione unificata dei dati.

Per fare il collaudo della procedura sulla Barra di stato, ci siamo serviti sin qui dell’Editor di Jaws e del Blocco Note, ma soltanto perché si tratta di programmi che conosciamo bene. In realtà, l’utilizzo della Barra di stato per recuperare il numero di riga, di colonna e delle righe complessive, in questi due applicativi non è né il solo sistema, né il più stabile.

Vi sono dei programmi dove, diversamente, leggere i dati nell’ultima riga in basso dello schermo risulta l’unico metodo possibile per acquisire quel tipo di dati. In generale, quindi, ogni applicativo tratta in modo molto diverso questo elemento dell’interfaccia, e la possibilità di potervi applicare la nostra procedura non è sempre scontata.

Il problema è, banalmente, quello di riuscire sempre ad acquisire con esattezza il contenuto della Barra di stato. Può capitare, infatti, che neppure la funzione nativa di Jaws riesca a recuperarlo, come ad esempio nei più recenti pacchetti Microsoft Office, per i quali Jaws utilizza a livello locale una speciale funzione integrata.

Proprio per questa spiccata variabilità, gli elementi di codice che prelevano i dati dalla Barra di stato dovranno essere posti soprattutto nei file script dei singoli applicativi. Anche i tre script che abbiamo realizzato dentro a
Default.JSS
, infatti, saranno nel prossimo capitolo sostituiti da una versione pressoché identica, la quale però utilizza altre fonti per i dati.

Tali elementi di codice non sono tuttavia stati realizzati inutilmente, in quanto rappresentano un modello per le versioni da inserire nei file script locali, che potremo perciò duplicare così come sono per poi modificarne solo il nome. Questo lavoro di copia ed incolla, che ora ci serve per risparmiare tempo e fatica, anticipa soltanto l’opera che produrremo tra un paio di capitoli, quando metteremo a punto una procedura che scriva gli elementi di codice al posto nostro.

Gli script rivolti alla gestione dei dati.

L’aspetto più importante degli script realizzati per leggere i dati su righe e colonne, senza dubbio, è il cambio di approccio cui essi hanno portato. In pratica, da script che contengono controlli e procedure, quelli più classici realizzati sinora, a questi che hanno una sola riga di codice e, soprattutto, dal contenuto sempre uguale.

Tale contenuto, così come abbiamo già esaminato, sarà la chiamata alla nostra funzione
GestisceDato ()
, utilizzata per ora senza neppure dei parametri. Sarà quindi solo il nome La parte variabile di tali script, quella che indica cosa deve fare alla funzione chiamata, il quale sarà costituito dagli elementi seguenti:

  1. L’azione da compiere, che nel caso dei nostri primi esempi è
    Pronuncia
    , che rappresenta una parte obbligatoria.
  2. La categoria del dato da elaborare, in questi casi il termine
    Stato
    , che serve ad identificare l’omonima barra di dati, la quale potrà essere specificata oppure no.
  3. L’oggetto cui si rivolge l’azione, che nel caso dei nostri primi tre esempi è stato utilizzato come
    Riga,
    Colonna
    e
    Lunghezza
    , ma che sarà presente solo quando necessario.
  4. Un numero progressivo, posto come suffisso alla destra del nome, che può essere usato in alternativa all’oggetto, ma anche assieme ad esso, e che sarà usato in particolare quando realizzeremo le citate serie di script.

Microsoft Word e la Barra di stato.

Completata una breve panoramica anche sugli script di gestione dati in generale, proviamo a fornire ora qualche utile informazione per adattare la nostra procedura al famoso programma di videoscrittura.

Abbiamo già detto di come negli ultimi prodotti del pacchetto Office il sistema per rilevare la Barra di stato non si basi più soltanto sulla funzione usata sinora, ma utilizzi soprattutto
GetUIAStatusBarText
, (OttieniTestoBarraStatoDalAgenteDiInterfacciaUtente). Questa funzione, che interviene quando sono presenti una serie di finestre Office, svolge appunto il compito di restituirci il testo della Barra di stato in modo specifico, perché tratta i componenti di Word come un
Oggetto
di cui legge direttamente le
Proprietà.

Una delle cose che dovremo fare, quindi, sarà creare una nuova versione di
BarraStato ()
, con lo scopo di inserire questa speciale funzione nativa. In particolare, useremo come base la precedente versione della nostra funzione, limitandoci ad inserire la chiamata al nuovo elemento di codice al posto dell’istruzione che restituisce una stringa vuota.

Prima, però, dovremo compiere un passaggio che ci consenta di capire quali e quante versioni locali dei nostri script dovremo inserire nel file script di Word, scegliendo i dati che vogliamo siano visualizzati nella Barra di stato.

Per svolgere questa funzione, il programma di videoscrittura fornisce un apposito menu, che si visualizza cliccando con il tasto destro del mouse nell’ultima riga in basso nello schermo. Aprite quindi un qualsiasi documento tramite Microsoft Word e, facendo attenzione ad avere aperta possibilmente solo quella finestra, potreste dunque fare così:

  1. Attivate il
    Cursore Jaws
    , e poi sincronizzatelo alla posizione del PC.
  2. Andate all’ultima riga in basso nello schermo.
  3. Simulate la pressione del tasto destro del mouse.
  4. Tornate al
    Cursore PC.

Se tutto va bene, dovreste essere in grado di scorrere con le frecce un menu composto da una serie di voci, che possono essere attive o disattive. Se non vi crea troppi problemi, usate la Barra Spaziatrice o il tasto Invio per lasciare attivate, disattivando tutte le altre, solamente le voci seguenti:

  • Numero pagina;
  • Posizione verticale nella pagina;
  • Numero riga;
  • Colonna;
  • Conteggio parole.

Selezionando queste cinque voci in realtà si possono ottenere sei dati, perché quello della pagina contiene sia il numero di quella corrente, sia quello delle pagine totali.

Alla fine, sarà sufficiente uscire premendo il tasto Escape, senza dover confermare le impostazioni effettuate.

Terminate queste operazioni preliminari, passiamo dunque a inserire nel file script di Word sia la versione aggiornata della funzione che rileva il contenuto della Barra di stato, sia gli script veri e propri che serviranno per leggere i dati.

Esercizio 9.6.3. La versione di BarraStato () per Microsoft Word.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

BarraStato

Descrizione.

Tenta di utilizzare la funzione originaria di Jaws per rilevare il contenuto dell’ultima riga in basso nella finestra. Se non vi riesce, prova ad utilizzarne la versione nativa più aggiornata.

Ritorni.

Di tipo String. Il contenuto dell’ultima riga in basso nella finestra.

Novità.
  1. La funzione integrata
    GetUIAStatusBarText ().
Note.
  1. Aprite il file script Predefinito, quindi portatevi sulla funzione
    BarraStato ()
    , selezionate tutto il codice con
    Control+R
    , copiate negli appunti, ed uscite infine dall’Editor.
  2. Aprite Microsoft Word, richiamate l’Editor di Script e così caricando il file script dell’applicativo, che potrà avere un nome diverso a seconda della versione a vostra disposizione. In ogni caso, portatevi alla fine dello script ed incollate la funzione appena copiata.
  3. Portatevi verso la fine della funzione, all’interno del secondo elemento di controllo, nella riga con l’istruzione
    Return
    , e cancellatela.
  4. Inserite prima l’assegnazione della nuova funzione speciale alla variabile testuale, poi il ritorno della funzione con cui sostituire in tale testo gli eventuali ritorni a capo presenti, identificati dalla costante
    LF
    , con il carattere di separazione standard delle voci nella Barra di stato. Per controllare l’esatto codice da inserire, esaminate la forma proposta di seguito.

Codice.


String Function BarraStato ()
Var String sTesto; il contenuto nella Barra di stato
Let sTesto = GetBottomLineOfWindow (); rileva il contenuto dell’ultima riga nello schermo
If sTesto ; se un qualche contenuto è stato rilevato,
&& (StringContains (sTesto, DIVIDE_ZONE) ; e se nel testo c’è o, il separatore standard,
|| StringContains (sTesto, SPACE)) Then; oppure, almeno un carattere Spazio,
Return sTesto; restituisce il contenuto rilevato
Else; altrimenti,
Let sTesto = GetUIAStatusBarText (); rileva la Barra di stato con la funzione speciale
Return StringReplaceSubstrings (sTesto, LF, DIVIDE_ZONE); sostituisce i ritorni a capo
EndIf; fine controllo contenuto
EndFunction

Collaudo.

  1. Se ci fosse un errore in compilazione, in particolare relativo alla funzione speciale, avvisiamo che tale istruzione si può compilare dalla versione 17 di Jaws in poi. Se avete una versione precedente della sintesi vocale, questa funzione non si può usare ma, probabilmente, non sarebbero neppure compatibili le ultime versioni di Office che usano questo tipo di elementi.
  2. Se invece tutto va bene, attendiamo come al solito i prossimi script per testare appieno la funzione. Soprattutto, non uscite dall’Editor di Script, perché proseguiamo subito con il resto del lavoro.

Esercizio 9.6.4. Gli script sulla Barra di stato in Microsoft Word.

FileScript.

Word.JSS o WordClassic.JSS

Note.
  1. Se siete già dentro all’Editor di Script, richiamate il file script Predefinito con
    Shift+Control+D
    . Selezionate e copiate i nostri tre script per leggere i dati dalla Barra di stato,
    PronunciaStatoRiga (),
    PronunciaStatoColonna ()
    , e
    PronunciaStatoLunghezza ()
    . Chiudete poi la schermata del file script Predefinito con
    Control+F4.
  2. Se non siete tornati nel file script di Word, riapritelo cercandolo nella lista dei file recenti nel menu File. Qui, portatevi alla fine del file, incollate una prima volta i tre script in memoria, distanziatevi di una riga vuota dall’ultimo degli script precedenti, quindi incollate una seconda volta, ottenendo così un totale di sei script.
  3. Per il codice ottenuto, seguite le sei schede poste di seguito, corrispondenti agli altrettanti script appena copiati, dei quali si dovrà di volta in volta aggiornare solo i dati, oppure anche modificarne il contenuto.

Esercizio 9.6.5. La versione di PronunciaStatoRiga () per Microsoft Word.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoRiga

Sommario.

Legge la riga () sul cursore.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla riga (), presente nella Barra di stato.

TastiAttivazione.

Control+J

Note.
  1. Andate al primo script della serie, aprite la schermata di modifica, ed aggiungete i dati mancanti.
  2. Sebbene i tasti di attivazione sarebbero già impostati per l’omonimo script nel file predefinito, inserite nuovamente la combinazione
    Control+J
    . Sarete avvisati che quella combinazione è già in uso, come detto di sicuro dal file script Predefinito, e probabilmente anche da Word. Spostatevi quindi su
    Ok
    una o due volte per confermare la scelta.

Codice.


Script PronunciaStatoRiga ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.6.6. La versione di PronunciaStatoColonna () per Microsoft Word.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoColonna

Sommario.

Legge la colonna () sul cursore.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla colonna (), presente nella Barra di stato.

TastiAttivazione.

Nessuno

Note.
  1. Per completare l’aggiornamento, portatevi dentro al codice dello script, e aprite la schermata di modifica per aggiungere i dati mancanti.
  2. Anche in questo caso si consiglia di ribadire i tasti di attivazione, malgrado non sia indispensabile farlo in quanto quelli originali,
    Control+K
    , non dovrebbero essere già occupati. Va però chiarito che, nel caso questi non siano immessi nuovamente, lo script attivato dalla citata combinazione sarà quello presente nel file script Predefinito,
    PronunciaValoreColonna ()
    , che non prende i dati dalla Barra di stato bensì dalla funzione nativa.

Codice.


Script PronunciaStatoColonna ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.6.7. La versione di PronunciaStatoLunghezza () per Microsoft Word.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoLunghezza

Sommario.

Legge la lunghezza in pagine del file.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla lunghezza del file in pagine), presente nella Barra di stato.

TastiAttivazione.

Control+OGrave

Note.
  1. Nell’occasione, entrando nella schermata di modifica, si dovranno certamente aggiornare i dati della documentazione.
  2. Così come per il numero di colonna, se si lasciassero i tasti di attivazione preimpostati, sarebbe eseguito lo script del file Predefinito,
    PronunciaValoreLunghezza ()
    , che però legge il numero di caratteri complessivi del documento. Se si vuole che invece sia letto il numero complessivo delle pagine, si dovrà dapprima cancellare e poi ribadire la precedente impostazione, così da far eseguire questo script che trae i suoi dati dalla Barra di stato.

Codice.


Script PronunciaStatoLunghezza ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.6.8. Lo script PronunciaStatoPagina.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoPagina

Sommario.

Legge il numero di pagina corrente.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla pagina corrente, presente nella Barra di stato.

TastiAttivazione.

Control+L

Note.
  1. Il codice relativo a questo elemento è il quarto script della serie, la copia di
    PronunciaStatoRiga ()
    . Portatevi sulla riga d’intestazione dello script, e prima di tutto sostituite, nell’ultima parte del nome, il termine
    Riga
    con
    Pagina.
  2. Aprite poi la schermata di modifica, e compilate i dati mancanti.
  3. Nel campo per inserire i tasti di attivazione, premendo
    Control+L
    ,non dovrebbero esserci precedenti impostazioni di Jaws. Tale combinazione, tuttavia, è una scelta rapida di Word, che serve per assegnare uno stile al paragrafo attivo. Sta quindi a voi, decidere se è più frequente l’utilizzo di tale funzione, oppure conoscere il numero della pagina corrente.
  4. Qualora sceglieste di mantenere tale combinazione per i nostri script, vi sarà sufficiente trovare un’altra qualsiasi combinazione tasti libera, ed assegnarvi uno script che avesse come unica istruzione il comando
    TypeKey ()
    con la combinazione
    Control+L
    espressa tra virgolette oppure preventivamente salvata in una costante con il carattere Sottolineato al posto del segno Più.

Codice.


Script PronunciaStatoPagina ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.6.9. Lo script PronunciaStatoPosizione.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoPosizione

Sommario.

Legge la posizione dall’alto nella pagina.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alla posizione dall’alto della pagina, presente nella Barra di stato.

TastiAttivazione.

Control+AGrave

Note.
  1. Andate al quinto script della serie, la copia di
    PronunciaStatoColonna ()
    , e portatevi sulla riga d’intestazione. Qui, prima di ogni altra cosa, sostituite manualmente, nell’ultima parte del nome, il termine
    Colonna
    con
    Posizione.
  2. Aprite la schermata di modifica, ed aggiungete i dati mancanti, compresi i tasti di attivazione,
    Control+AGrave
    , che dovrebbero essere anch’essi liberi.

Codice.


Script PronunciaStatoPosizione ()
GestisceDato (); chiama la funzione generica
EndScript

Esercizio 9.6.10. Lo script PronunciaStatoParole.

FileScript.

Word.JSS o WordClassic.JSS

Nome.

PronunciaStatoParole

Sommario.

Legge le parole complessive.

Descrizione.

Chiama la funzione generica di gestione, attivando i comandi di lettura del dato relativo alle parole complessive del file, presente nella Barra di stato.

TastiAttivazione.

Control+UGrave

Note.
  1. Andate all’ultimo script di quelli inseriti, la copia di
    PronunciaStatoLunghezza ()
    . Portatevi sulla riga d’intestazione e sostituite manualmente, nell’ultima parte del nome, il termine
    Lunghezza
    con
    Parole.
  2. Aprite la schermata di modifica, aggiungete i dati mancanti, compresi i tasti di attivazione,
    Control+UGrave
    , che non dovrebbero darvi problemi.

Codice.


Script PronunciaStatoParole ()
GestisceDato (); chiama la funzione generica
EndScript

Collaudo.

La compilazione non dovrebbe dare problemi, quindi resta solo l’onere di come impostare nel modo corretto i dati relativi alla Barra di stato nel file di configurazione.

Chiariamo subito che non conviene usare il metodo della doppia pressione iniziale dei tasti di attivazione degli script dentro a Word, al fine di preimpostare delle zone standard, perché la procedura automatica non è in grado di rilevare da sola le corrette impostazioni. Conviene quindi entrare nel file di configurazione di Word, e copiarvi lo schema dei dati che vi proporremo di seguito, relativo a due diverse versioni di Word, 2007 e 2016.

Tali schemi danno per scontato che voi abbiate attivato nel menu apposito soltanto le cinque voci elencate in precedenza. Se così fosse, le configurazioni dovrebbero funzionare.

I dati per la Barra di stato in Word 2007.

Si tratta di una versione un po’ datata, ma che funziona bene con la sintesi vocale perché è ancora possibile sfruttarne direttamente i comandi.

Il testo della Barra di stato, in questo caso, è rilevato ancora con la funzione generica,
GetBottomLineOfWindow ()
. Tale testo è perciò normalmente posto in una sola riga, e le varie voci sono separate dal separatore standard, i Due Punti.

Anche stavolta proporremo ciò che potrebbe apparire nel file di configurazione di Word, con le diverse voci poste su ciascuna riga, e precedute dalla chiave composta dalla parola
Testo
, seguita da un suffisso numerico progressivo. Allo stesso modo, abbiamo assegnato i diversi dati usando numeri corrispondenti alle voci, così da far comprendere meglio la successione dei dati.

Fate attenzione al fatto che il termine esplicativo del dato si trova nella riga che precede il dato stesso, proprio perché il carattere separatore Due Punti è posto di solito appena prima del dato.

Ad esempio, il dato
"2 di 22"
, si trova nella zona 2, ma è relativo al termine
"Pagine"
, il quale si trova nella prima riga.

Allo stesso modo, il dato
"3,3 cm"
è posto nella zona 3 , seppure riguardi la
"Posizione"
che, come termine, è presente nella seconda riga.


[BarraStato]
Separatore=:
Testo1=Pagina
Testo2=2 di 22 Posizione
Testo3=3,3 cm Riga
Testo4= 44 Colonna
Testo5=55 Parole
Testo6= xx/6.666

Come potete notare, in ciascuna zona il valore è il primo, o al massimo il secondo, dei dati inseriti. Questo consente nella maggior parte dei casi di utilizzare i valori predefiniti, che portano ad usare il carattere Spazio come separatore delle sottovoci, ed il prelievo del primo dato a sinistra nella seconda serie di elaborazioni.

Il dato più complesso da estrapolare è quello delle parole, che nell’esempio proposto è preceduto da un dato da cui è separato tramite un carattere Barra, Ascii 47. Tale dato è il numero di caratteri evidenziati, che abbiamo posto come lettere per evitare confusioni. In realtà tale dato potrebbe anche non esserci, ma bisogna considerarlo perché altrimenti, nelle volte che c’è, il dato letto sarebbe errato.

In ogni caso, è necessario estrarlo tramite due cicli di modifica:

  1. Isolare i dati nella zona 6, cancellandone eventuali caratteri Punto.
  2. Il prelievo di una sottozona di quella principale, che ha per separatore il carattere Barra, da cui si estragga l’ultimo dato a sinistra, tramite il valore
    "-1".

Data questa premessa, proponiamo i dati come dovrebbero essere copiati alla fine dell’archivio di configurazione di Word che, ricordiamo, ha il nome base del file script aperto nell’Editor di Jaws con l’aggiunta dell’estensione
JCF.

Qualora tale archivio non esistesse ancora nella cartella delle
Impostazioni per l’Utente
, significa che non avete ancora registrato in questo applicativo le finestre dei tipi previsti dalle nostre procedure. Per farlo, attivate una prima volta la procedura di registrazione premendo
Control+Windows+I
, selezionando poi il tipo
Editing
, e concludendo la conferma dei dati, quindi eseguendola una seconda volta per registrare il tipo
Posizione.

Una volta caricato correttamente il file, e portatisi alla sua conclusione, inserite le iscrizioni poste di seguito:


[BarraStato]
Separatore=:
Pagina=2
Lunghezza=2| di||2
Posizione=3| |||riga
Riga=4
Colonna=5
Parole=6|.|/|-1

I dati per la Barra di stato in Word 2016.

Qui abbiamo invece una delle versioni più recenti del programma, dove il testo della Barra di stato è rilevato grazie alla funzione speciale,
GetUIAStatusBarText ().

Il testo viene restituito con ciascuna zona in una riga diversa, separata da un carattere di ritorno a capo,
LF
, l’Ascii 10. Per questo, prima di restituire il testo alla funzione chiamante, se ricordate, abbiamo sostituito questi ritorni a capo con dei separatori standard, il carattere due punti.

Come già detto, poiché la procedura crea le zone testuali sulla base dei separatori, in pratica ripristiniamo la forma di partenza. Anche in questo caso, i dati sono proposti con numerazioni progressive, che ne rivelano le zone, ma qui il vantaggio è che il termine esplicativo è posto nella stessa riga del dato cui si riferisce. Esso andrà inserito come al solito nel file configurazione con l’estensione
JCF
. Qualora non lo troviate, fate riferimento a quanto riportato in proposito per la versione 2007 di Word.


[BarraStato]
Separatore=:
Testo1=Numero pagina Pagina 1 di 11
Testo2=Posizione verticale nella pagina 22, 2 cm
Testo3=Numero riga 33
Testo4=Colonna 44
Testo5=Conteggio parole 55 parole

Come si può notare, diversamente dalla versione 2007, i dati numerici nelle zone sono quasi sempre a destra, l’ultimo o penultimo valore. Per questo, anziché usare i valori positivi, dovremo usare il segno Meno,
-
, davanti ai valori per identificare le zone da estrarre.

In tale modo, si indica di prelevare l’ultimo dato a destra, mettendo
"-1"
, oppure il penultimo dato a destra, mettendo
"-2"
. Proprio per questo, non sarà possibile usare i valori predefiniti, dovendo anche in qualche caso ricorrere alla cancellazione di alcune parole per semplificare il raggiungimento dei dati.

Detto questo, di seguito poniamo i dati come dovrebbero essere copiati alla fine dell’archivio di configurazione di Word:


[BarraStato]
Separatore=:
Pagina=1| di||-2
Lunghezza=1| di||-1
Posizione=2||a|-1
Riga=3|||-1
Colonna=4|||-1
Parole=5|||-2

Collaudo delle configurazioni della Barra Stato per Microsoft Word.

Una volta entrati in Word, se avete seguito tutti i passaggi, la procedura di configurazione dovrebbe avervi posto nelle condizioni di leggere i dati dalla Barra di stato. Sulla base degli script da noi prodotti, e delle voci attivate nel menu della Barra di stato, ricordiamo che i tasti a disposizione dovrebbero essere i seguenti:

  1. Control+J
    , per la lettura del numero di riga.
  2. Control+K
    , per il numero di colonna.
  3. Control+L
    , per il numero della pagina corrente.
  4. Control+OGrave
    , per il numero totale delle pagine.
  5. Control+AGrave
    , per la distanza dal bordo superiore.
  6. Control+UGrave
    , per il numero delle parole nel documento.

Provate quindi a premere qualcuna di queste combinazioni di tasti. Se tali pressioni non producessero alcun effetto, il problema potrebbe essere quello di dover ancora registrare i dati per il tipo di finestra
Editing
dentro a questo applicativo.

Per verificarlo, provate innanzi tutto a premere due volte velocemente i tasti di attivazione degli script. Se non succede nulla, allora provate ad avviare la procedura di registrazione premendo
Control+Windows+I
, selezionando e poi confermando il citato tipo di finestra.

Se anche dopo aver compiuto questo passo la pressione dei comandi non producesse alcun effetto, provate ancora a premere due volte una qualsiasi delle combinazioni per sentire l’eventuale messaggio dalla procedura.

Qualora il problema fosse la mancanza del carattere di separazione, sarà proposta una finestra di dialogo nella quale si potrà scegliere di inserirlo direttamente. In tal caso, dopo aver confermato la scelta, si entrerà in un campo di editazione dove sarà preimpostato il carattere predefinito, che si potrà quindi confermare o modificare.

Usciti da questo inserimento, se il carattere di separazione immesso risulterà quello corretto, i comandi di lettura dovrebbero iniziare a funzionare.

Se, in ogni caso, alla fine i dati letti non risultassero quelli corretti, provate a riaprire il file di configurazione di Word, e ricontrollate i dati impostati.

***

Riepilogo.

Questo capitolo, il più lungo sinora, ha già portato delle novità interessanti, ed altre ci attendono a breve. Si è spesso trattato, in ogni caso, di procedure di carattere generale, che serviranno nella gran parte degli elementi di codice da realizzare da qui in avanti.

Proprio per questo , dovremo attendere la fine del prossimo capitolo per avere i primi risultati più concreti ed innovativi, legati al movimento all’interno dei documenti. Il nostro sforzo sarà inoltre quello di continuare ad operare su diversi ambienti, rendendo comuni le procedure a tutti e quattro gli applicativi cui abbiamo rivolto sinora le nostre attenzioni.

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *