Logo dell'UIC Logo TUV

Unione Italiana dei Ciechi e degli Ipovedenti ETS - APS

 

Uiciechi.it

torna alla visualizzazione del numero 05 del Uiciechi.it

Numero 05 del 2021

Titolo: Gli script di Jaws 12. La ricerca rapida di stringhe predeterminate. (2)

Autore: Abramo Volpato.


Articolo:
Gli script di Jaws 12. La ricerca rapida di stringhe predeterminate.

Di Abramo Volpato.

Seconda parte.

Collaudo.

1. Dopo aver correttamente compilato, è necessario porre come opzionali gli ultimi due parametri.

12.3.10. Immissione e modifica di un testo.

La prossima coppia di funzioni si occupa dell'immissione materiale del testo nelle nostre procedure. Per quanto riguarda il testo da trattare, va chiarito che noi avremo due formati principali per farlo:

1. "riga unica", nella quale gli eventuali contenuti di più righe sono posti l'uno accanto all'altro, come i campi di un record, e divisi tra loro da una speciale stringa di separazione composta da una coppia di parentesi quadre con dentro due punti esclamativi.

2. "su più righe", dove gli eventuali diversi contenuti sono suddivisi dai normali caratteri di fine riga, Ritorno a Capo e Nuova Linea, Ascii 13 e 10.

Nel dettaglio, il primo formato è quello che ci consente di registrare, e poi leggere, i nostri dati negli archivi in formato "INI", mentre il secondo è quello che ci consente di poter modificare tali dati tramite lo strumento per inserire testo, la funzione "InputBox ()".

Tornando agli elementi da realizzare, il primo di questi sarà una funzione che si occupa di convertire il testo elaborato nei due possibili formati, mentre il secondo contiene la procedura di immissione vera e propria, quella che richiama la citata funzione nativa.

In particolare, questa seconda funzione contiene anche un ciclo che analizza il testo inserito, consentendo di ritornare all'inserimento nel caso in cui:

1. non si sia specificato alcun testo, oppure si sia usciti dall'immissione.

2. Il testo inserito sia compreso nell'elenco di quelli vietati, specificato in un parametro della funzione stessa.

3. Nel testo sia presente il Carattere Pipe, e tra i parametri della funzione si è indicato che ciò non sia possibile.

Inoltre, l'ingresso e l'uscita dal campo d'inserimento sono segnalati dai suoni che Jaws propone, per le stesse fasi, ad esempio nei campi d'immissione delle pagine web, per dare anche un riscontro sonoro sulle azioni da svolgere.

Esercizio 12.3.11. La funzione InverteForma.

FileScript. Default.JSS

Nome. InverteForma

Descrizione. Converte i caratteri di fine riga nei separatori di voce, lasciando vuoto il secondo parametro o ponendovi il valore FALSE, oppure, viceversa, dai separatori di voce ai caratteri di fine riga, ponendo TRUE nel secondo parametro. Come sequenza di fine riga, sarà utilizzata quella classica, Ascii 13 e 10, nel caso in cui come terzo parametro non sia indicato nulla, altrimenti si utilizzerà quella specificata.

Ritorni. Di tipo String. Il testo di cui si siano eventualmente convertiti i caratteri di fine riga o i separatori di voce, sulla base del tipo eventualmente specificato come secondo parametro.

Parametri.

1. sTesto. La stringa testuale da convertire. Di tipo String.

2. iTipo. Se valorizzato con TRUE, converte gli eventuali separatori di voce, definiti tramite l'apposita costante personale, nei caratteri di fine riga, predefiniti o impostati nel terzo parametro; lasciando vuoto o mettendo il valore FALSE, viceversa, i caratteri di fine riga saranno convertiti nei separatori di voce. Di tipo Int. Parametro Opzionale.

3. sRitorno. L'eventuale carattere di ritorno a capo per la sostituzione; qualora non si specifichi nulla, sarà usata la classica sequenza di ritorno a capo, Ascii 13 e 10. Di tipo String. Parametro Opzionale.

Novità.

1. La costante "RN", che equivale alla classica sequenza di ritorno a capo composta dai caratteri Ascii 13 e 10, e la costante "SPV", che contiene il separatore di voce personale, costituito da due punti esclamativi dentro ad una coppia di parentesi quadre.

Note.

1. L'utilizzo più semplice della funzione, specificando solo il testo da convertire, sostituisce gli eventuali caratteri di Ritorno a Capo nei Separatori di Voce.

2. Se oltre al testo si pone anche la costante "TRUE" nel secondo parametro, saranno i Separatori di Voce ad essere convertiti nei caratteri definiti come ritorni a capo.

3. Se poi si specifica un terzo parametro, i caratteri in esso indicati saranno considerati come i ritorni a capo per le sostituzioni.

Codice.

String Function InverteForma (string sTesto, int iTipo, string sRitorno)
If !sRitorno Then; se non è stata specificata alcuna stringa di fine riga alternativa,
Let sRitorno = RN; imposta come fine riga la sequenza classica, Ascii 13 e 10
EndIf; fine controllo caratteri di fine riga
If iTipo Then; se si è richiesta la conversione dai separatori di voce ai caratteri di fine riga,
Return StringReplaceSubstrings (sTesto, SPV,sRitorno); sostituisce i primi con i secondi
Else; altrimenti,
Return StringReplaceSubstrings (sTesto, sRitorno, SPV); cambia i fine riga con i separatori di voce
EndIf; fine controllo tipo conversione
EndFunction

Collaudo.

1. Anche in questo caso, dopo aver compilato la funzione, aprite il file documentazione per rendere opzionali il secondo e terzo parametro.

Esercizio 12.3.12. La funzione InserisceTesto.

FileScript. Default.JSS

Nome. InserisceTesto

Descrizione. Consente di inserire del testo in un normale campo d'immissione stile Windows; nel caso non si specifichi nulla, o si abbandoni l'inserimento, viene proposta una ulteriore conferma se uscire o se tornare all'immissione di testo. Se si specifica un elenco di stringhe testuali come quarto parametro, si controlla che il testo immesso non sia già presente nell'elenco, casomai costringendo a modificarlo. Se non si specifica nulla come quinto parametro, qualora si immetta anche un carattere Pipe, Ascii 124, viene segnalata la necessità di rimuoverlo.

Ritorni. Di tipo String. Il testo eventualmente inserito.

Parametri.

1. sTitolo. L'eventuale titolo da proporre nella finestra d'inserimento; qualora non lo si specifichi, viene assunto un titolo predefinito. Di tipo String. Parametro Opzionale.

2. sTesto. L'eventuale stringa che sarà predisposta nel campo d'inserimento; qualora non la si specifichi, il campo sarà vuoto. Di tipo String. Parametro Opzionale.

3. iMultiple. Se valorizzato con TRUE, indica di considerare il testo su righe multiple, quindi riconvertendolo all'uscita con i separatori di voce lineari; nel caso non si indichi nulla, il testo verrà troncato al primo eventuale carattere di ritorno a capo. Di tipo Int. Parametro Opzionale.

4. sVietati. L'eventuale elenco di termini, separati dal carattere Pipe, che non devono essere immessi, pena l'interruzione dell'inserimento e l'invito alla modifica. Di tipo String. Parametro Opzionale.

5. iPipe. Se valorizzato con TRUE, consente di immettere nel campo testuale anche il carattere Pipe, Ascii 124; se non si specifica nulla, tale inserimento causerà un messaggio d'errore. Di tipo Int. Parametro Opzionale.

Novità.

1. La nostra funzione "InverteForma ()".

2. Le costanti "INGRESSO_CAMPO" e "USCITA_CAMPO", che equivalgono ai file di suoni, senza estensione, impostati nel file delle costanti personali "_PSConst.JSH".

Fasi.

1. Le impostazioni iniziali prevedono comunque di attivare la sintesi vocale, e sostituire poi gli eventuali separatori di voce in ritorni a capo, grazie alla nostra funzione "InverteForma ()", quindi di determinare il testo del messaggio a video, ed infine di salvare eventuali dati memorizzati circa il titolo e le etichette dei pulsanti della funzione chiamante.

2. Si entra poi nel ciclo d'inserimento testo dove, prima e dopo la chiamata alla funzione integrata d'immissione testo, viene emesso un suono.

3. Il testo eventualmente inserito viene sottoposto ai tre tipi di controlli, elencati nella premessa, che possono far ritornare all'inserimento; se il testo immesso è valido, viene casomai riconvertito nel formato lineare, o interrotto al primo carattere di ritorno a capo, ed in ogni caso il flusso viene fermato restituendo l'esito positivo.

4. Se invece si conferma l'abbandono dell'immissione, si esce dal ciclo.

5. In ogni caso, sono ripristinati lo stato di Attivazione della sintesi, nonché i dati memorizzati su titoli ed etichette, al momento della chiamata della funzione.

Codice.

String Function InserisceTesto (string sTitolo, string sTesto, ; prima riga con due parametri,
int iMultiple, string sVietati, int iPipe); seconda riga d'intestazione, con gli altri tre
Var
Int iStato, ; stato di attivazione della sintesi
String sPrefisso, ; testo da premettere al messaggio
String sMessaggio, ; testo informativo
String sBufferTitolo, ; eventuale precedente contenuto del titolo predefinito
String sBufferEtichette, ; eventuale precedente contenuto delle etichette dei pulsanti
Int iScelta, ; l'esito delle finestre di dialogo
String sDato; variabile temporanea

Let iStato = ControllaSintesi (TRUE, TRUE); riattiva la sintesi, annotandone lo stato
Let sTesto = InverteForma (sTesto, TRUE); sostituisce i separatori di voce con i ritorni a capo
If iMultiple Then; se il testo può essere scritto su più righe,
Let sPrefisso = msgRigheMultiple; imposta il prefisso da formattare nel messaggio
EndIf; fine controllo righe immissione
Let sMessaggio = FormatString (msgMettiTesto, sPrefisso); formatta il testo del messaggio
; memorizza gli eventuali contenuti di titolo ed etichette della finestra di dialogo
ScambiaTitoli (FormatString (msg2Spazi, sTitolo, sMessaggio), sBufferTitolo, sBufferEtichette)
While iScelta <= FALSE ; continua finché il valore di controllo rimane non superiore a 0
Let sDato = sTesto; duplica la stringa, per non compromettere l'originale
Suona (INGRESSO_CAMPO); emette un suono di avvio editazione
Let iScelta = InputBox (sMessaggio, sTitolo, sDato); consente di immettere o modificare una stringa
Suona (USCITA_CAMPO); emette un suono di uscita dall'editazione
If !sDato Then; se la stringa è vuota, anche per l'abbandono dell'inserimento,
Let iScelta = ChiedeConferma (ttlNoModifica, msgConferma, FALSE, SECONDA); propone la conferma
ElIf StringSegmentIndex (sVietati, BELL, StringLower (sDato), TRUE) Then; se il dato immesso è già presente,
ChiedeConferma (FormatString (ttlPresenzaDato, gsTermine, sDato), msgAggiornaTesto, OK)
Let iScelta = FALSE; imposta il valore per il ritorno nel campo d'immissione
ElIf !iPipe && StringContains (sDato, PIPE) Then; se è stato inserito anche il carattere Pipe,
ChiedeConferma (ttlNoPipe, msgAggiornaTesto, OK)
Let iScelta = FALSE; imposta il valore per il ritorno nel campo d'immissione
Else; altrimenti, se un testo è stato immesso,
ControllaSintesi (iStato, TRUE); ripristina lo stato della sintesi all'ingresso nel campo d'inserimento
ScambiaTitoli (NULLO, sBufferTitolo, sBufferEtichette); ripristina le variabili globali
If !iMultiple Then; se il dato è disposto su una riga,
Return TroncaTesto (sDato, CR); interrompe la stringa sino ad un eventuale primo ritorno a capo, erroneamente presente
Else; altrimenti,
Return InverteForma (sDato); restituisce la stringa con gli eventuali ritorni a capo convertiti in separatori estesi
EndIf; fine controllo righe multiple
EndIf; fine controllo presenza stringa
EndWhile; fine ciclo immissione
ControllaSintesi (iStato, TRUE); ripristina lo stato della sintesi all'ingresso nel campo d'inserimento
ScambiaTitoli (NULLO, sBufferTitolo, sBufferEtichette); ripristina le variabili globali,
Return NULLO; e restituisce una stringa vuota
EndFunction

Collaudo.

1. Dopo aver correttamente compilato il codice, sono da rendere opzionali tutti i parametri della funzione.

12.3.13. Il controllo sui tasti validi.

La prossima funzione è davvero quasi un'intrusa, tanto avanti sarà il suo primo utilizzo . Come detto più volte, tuttavia, dobbiamo sin d'ora predisporre la forma definitiva del codice, e per questo la prevediamo già come opzione delle fasi d'inserimento testo.

Il suo compito è quello di controllare che il testo passato come parametro equivalga ad un nome di un tasto, o di una combinazione di tasti, nella forma estesa in inglese. per fare ciò, si sfrutterà la funzione integrata "IsScriptKey", (SonoTastiDiScript), che restituisce un valore positivo se, nel suo unico parametro, si indicano tasti, o la combinazione di tasti, che possono attivare uno script.

Ad esempio, il tasto "Home" attiva lo script "JAWSHome", mentre il tasto "End" esegue lo script "JAWSEnd". Quindi, sottoponendo alla funzione "IsScriptKey ()" i termini "Home", oppure "End", la funzione restituirà un esito positivo.

sarà inoltre predisposto un apposito elenco, per consentire di far superare il controllo anche ad altri termini d'uso comune non coinvolti da script. Tale elenco, generato creando gli archivi di configurazione delle procedure, potrà comunque essere aggiornato direttamente tramite una finestra di dialogo della nostra funzione, confermando la validità di eventuali nuovi termini non riconosciuti.

Esercizio 12.3.14. La funzione ConfermaAzioni.

FileScript. Default.JSS

Nome. ConfermaAzioni

Descrizione. Controlla se le azioni immesse corrispondano a dei tasti riconosciuti come validi, casomai consentendo di aggiungerli all'archivio di quelli memorizzati come tali sul file di configurazione personale.

Ritorni. Di tipo Int. TRUE, se le azioni immesse sono ritenute dei tasti validi; FALSE, se non lo sono, ed alla successiva conferma si clicca su Annulla.

Parametri.

1. sTesto. Di tipo String.

Novità.

1. La funzione integrata "IsScriptKey ()", già descritta nella premessa.

2. La costante "VIRGOLA_SPAZIO", che equivale alla stringa composta dai due caratteri che ne costituiscono il nome.

Fasi.

1. Come impostazioni iniziali, sono dapprima raccolti i termini validi, registrati nell'apposita sezione dell'archivio di configurazione personale, suddividendo il testo specificato come parametro nelle eventuali diverse righe su cui è posto.

2. Un primo ciclo analizza ciascuna riga in cui è casomai diviso il testo, controllando se si tratti di un termine valido. Se così non è, si apre un secondo ciclo nel quale si prova a considerare il termine come una combinazione tasti, sottoponendolo alla funzione integrata "IsScriptKey ()", quindi tentando di sezionarla nelle eventuali parti separate dal segno Più.

3. Se anche questo secondo ciclo non riconosce il termine, lo stesso viene memorizzato come errore, aggiungendolo ad un altro elenco a ciò dedicato.

4. Alla conclusione dei cicli, se i termini indicati sono tutti validi, viene restituito l'esito positivo del controllo. Se invece vi sono degli errori, i termini non riconosciuti sono proposti a video, chiedendo conferma se siano comunque validi. Se così è, i singoli termini sono aggiunti all'apposito elenco, restituendo l'esito positivo, altrimenti viene restituito un risultato nullo.

Codice.

Int Function ConfermaAzioni (string sTesto)
Var
String sValidi, ; elenco dei tasti archiviati come validi
String sDati, ; elenco dei dati immessi
Int j, ; contatore del ciclo principale
String sDato, ; singolo dato da controllare
Int k, ; contatore del secondo ciclo
String s, ; singolo frammento tra i segni di congiunzione
String sErrori, ; elenco degli errori riscontrati
String sTitolo, ; testo per la finestra di dialogo
Int x; contatore dell'ultimo ciclo

; rileva i tasti presenti nell'archivio dei validi, portandoli in caratteri minuscoli
Let sValidi = StringLower (LeggeChiavi (PERSONALE, ARCHIVIO + TASTI))
; mette dei caratteri di Nuova Linea, Ascii 10, al posto di eventuali separatori di voce
Let sDati = InverteForma (sTesto, TRUE, LF)
For j = 1 To StringSegmentCount (sDati, LF); scorre i dati passati tramite parametro
Let sDato = StringSegment (sDati, LF, j); estrae il singolo dato
If StringLength (sDato) > 1 Then; se il dato estratto è più lungo di un carattere,
If !IsScriptKey (sDato) Then; se non è riconosciuto come un tasto utilizzato da qualche script,
; scorre i frammenti eventualmente divisi dal segno di congiunzione
For k = 1 To StringSegmentCount (sDato, SEGNO_PIU)
Let s = StringSegment (sDato, SEGNO_PIU, k); estrae il singolo frammento tra segni Più
If StringLength (s) > 1 Then; se il frammento è più lungo di un carattere,
If !StringSegmentIndex (sValidi, PIPE, StringLower (s), TRUE) Then; infine, se il frammento non è tra i tasti validi,
; aggiorna l'elenco dei tasti o frammenti non riconosciuti
Let sErrori = CambiaCampo (sErrori, s, ULTIMA, BELL)
EndIf; fine controllo tasti validi
EndIf; fine controllo lunghezza frammento
EndFor; fine scansione frammenti
EndIf; fine controllo tasti script
EndIf; fine controllo lunghezza dato
EndFor; fine scansione dati
If !sErrori Then; se i tasti sono stati tutti riconosciuti,
Return TRUE; restituisce l'esito positivo
Else; altrimenti, se vi sono dei tasti non riconosciuti,
; formatta il titolo, inserendo l'elenco degli errori riscontrati
Let sTitolo = FormatString (ttlArchiviaTasti, StringReplaceSubstrings (sErrori, PIPE, VIRGOLA_SPAZIO))
If ChiedeConferma (sTitolo, msgOkDati, FALSE, SECONDA) Then; se si confermano i dati immessi,
For x = 1 To StringSegmentCount (sErrori, BELL); scorre gli errori rilevati,
; e aggiorna l'archivio dei termini validi
ScriveNumerico (PS_FILE, ARCHIVIO + TASTI, StringSegment (sErrori, BELL, x), TRUE)
EndFor; fine scansione errori
Return TRUE; restituisce l'esito positivo
Else; altrimenti, se si annulla l'aggiornamento,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo conferma
EndIf; fine controllo presenza errori
EndFunction

12.3.15. Le stringhe registrate.

Le restanti quattro funzioni della sezione si occupano di controllare che vi siano delle stringhe registrate per la procedura richiamata. Tra queste, da rilevare quella che scrive sugli archivi modificando il singolo campo di un record, e soprattutto quella che si occupa in generale dell'aggiornare il contenuto dei campi.

Quest'ultima, la più lunga del blocco con oltre cinquanta righe di codice, chiama a sua volta gran parte delle funzioni analizzate in questa sezione, oltre ad avere una serie di controlli al suo interno. L'elemento di codice più importante è tuttavia l'ultimo della sezione, che verifica la presenza dei dati necessari alle varie procedure, e che chiama anche la funzione di aggiornamento campi.

Esercizio 12.3.16. La funzione ChiaveGlobale.

FileScript. Default.JSS

Nome. ChiaveGlobale

Descrizione. Determina la chiave testuale, duplicando il dato registrato nella omonima variabile globale oppure, se questa è vuota, prendendo la prima dell'elenco memorizzato nella variabile globale riservata a questo tipo di dato.

Ritorni. Di tipo String. La chiave registrata, o la prima dell'elenco delle chiavi attive.

Novità.

1. La costante "UNO", che include il valore dell'omonimo numero.

Note.

1. Questa funzione serve solo per garantire che sia restituito un qualche valore, a prescindere da dove essa lo rilevi, grazie all'unica struttura di controllo che la compone. L'assenza di parametri sta ad indicare, anche in questo caso, l'utilizzo delle variabili globali per elaborare i dati.

Codice.

String Function ChiaveGlobale ()
If gsChiave Then; se un dato è registrato,
Return gsChiave; lo restituisce
ElIf gsElenco Then; se un elenco di chiavi è impostato,
Return StringSegment (gsElenco, PIPE, PRIMA); restituisce la prima chiave di tale elenco,
Else; altrimenti, se il dato è ancora da impostare,
Return UNO; restituisce il primo valore in forma testuale
EndIf; fine controllo chiave
EndFunction

Esercizio 12.3.17. La funzione ScriveCampo.

FileScript. Default.JSS

Nome. ScriveCampo

Descrizione. Scrive il dato passato come parametro nel campo indicato del record specificato.

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

Parametri.

1. sArchivio. Il nome, senza estensione, dell'archivio da elaborare. Di tipo String.

2. sSezione. La sezione dell'archivio in cui operare. Di tipo String.

3. sChiave. La chiave del record. Di tipo String.

4. sDato. Il dato testuale da inserire nel campo indicato. Di tipo String.

Fasi.

1. Come impostazioni iniziali, sono letti il record di dati e il numero del campo in cui scrivere.

2. Una prima struttura di controllo verifica se il campo nel record già esiste; se così non è, e si sta elaborando una procedura su più campi, si annota la situazione in una variabile globale.

3. Il dato da scrivere viene inserito nel record, e poi quest'ultimo viene trascritto nell'archivio; se la scrittura riesce, si restituisce l'esito positivo, altrimenti si azzera l'eventuale annotazione sul campo vuoto e si restituisce un risultato nullo.

Codice.

Int Function ScriveCampo (string sArchivio, string sSezione, string sChiave, string sDato)
Var String sRecord = LeggeRecord (sArchivio, sSezione, sChiave); dichiara e Legge i dati del record
Let gnCampo = CampoGlobale (); controlla l'impostazione del numero di campo
If !StringSegment (sRecord, PIPE, gnCampo) ; se il dato da scrivere non esiste,
&& gnTipo == TERZA Then; e se si sta operando su più campi,
Let gnSalta = TRUE; imposta di saltare la successiva schermata di scelta
EndIf; fine controllo presenza dato
Let sRecord = CambiaCampo (sRecord, sDato, gnCampo); aggiorna il record inserendovi il dato
If ScriveRecord (sArchivio, sSezione, sChiave, sRecord) Then; se la scrittura riesce,
Return TRUE; restituisce l'esito positivo
Else; altrimenti, se la scrittura fallisce,
Let gnSalta = FALSE; cancella l'eventuale indicatore di salto impostato,
Return FALSE; e restituisce un risultato nullo
EndIf; fine controllo scrittura
EndFunction

Esercizio 12.3.18. La funzione AggiornaCampo.

FileScript. Default.JSS

Nome. AggiornaCampo

Descrizione. Gestisce l'aggiornamento dei campi di un record.

Ritorni. Di tipo Int. L'esito dell'aggiornamento: TRUE per la riuscita, FALSE per il fallimento.

Parametri.

1. sNome. L'azione da compiere. Di tipo String.

2. sSezione. La sezione dell'archivio in cui scrivere. Di tipo String.

3. sChiave. La chiave del record da aggiornare. Di tipo String.

4. sDato. L'eventuale dato testuale da inserire nel campo indicato. Di tipo String. Parametro Opzionale.

Novità.

1. Le nostre funzioni "ComponeTermine ()", "CreaElenco ()","InserisceTesto ()", "ConfermaAzioni ()", "ChiaveGlobale ()" e "ScriveCampo ()".

Fasi.

1. Nelle impostazioni iniziali, dapprima si definisce il titolo della finestra di dialogo, servendosi anche della nostra funzione "ComponeTermine ()", e poi eventualmente si crea un elenco di termini da non inserire., utilizzando la nostra "CreaElenco ()".

2. Si entra poi in un ciclo dove viene chiamata la nostra funzione "InserisceTesto ()"; se dopo l'immissione tale testo è vuoto, o se si è confermata l'uscita dalla fase, il flusso s'interrompe restituendo un risultato nullo.

3. Se invece del testo è stato immesso, se si stanno elaborando le azioni che devono compiere gli script a gestione personale, si controlla se i termini immessi siano validi, grazie alla nostra "ConfermaAzioni ()"; se così è, si esce dal ciclo, altrimenti viene proposta una conferma tramite la quale si possono aggiungere i termini non riconosciuti all'elenco di quelli validi, oppure si può tornare all'inserimento.

4. Una volta usciti dal ciclo, dopo aver controllato l'impostazione di una chiave del dato tramite la nostra funzione "ChiaveGlobale ()", si tenta di salvarlo con la nostra "ScriveCampo ()". Se l'azione fallisce, viene restituito un risultato nullo, altrimenti sono aggiornati sia il dato della chiave, sia quello sull'ultima voce elaborata, restituendo poi l'esito positivo.

Note.

1. Come dimostra il gran numero delle nostre funzioni tra le novità, questo elemento di codice è il vero fulcro del blocco. Per questo motivo, al suo interno sono state inserite due situazioni particolari, che si verificano solo con gli script a gestione personale, e più precisamente:

- nel primo campo, la creazione dell'elenco dei termini vietati;
- Nel quarto campo, il controllo sulla validità di quelli immessi come azioni degli script.

Codice.

Int Function AggiornaCampo (string sNome, string sSezione, string sChiave, string sDato)
Var
String sPrefisso, ; stringa che nel messaggio precede l'oggetto
String sSuffisso, ; stringa che segue l'oggetto
String sTitolo, ; titolo per la finestra di input
String sVideo, ; elenco delle voci a video
String sVietati, ; lista di termini da non inserire
Int iModifica, ; valore per l'uscita dal ciclo
String sTesto; variabile temporanea

; determina il prefisso del messaggio, sulla base del tipo di procedura e del campo attivi
Let sPrefisso = StringSegment (lstPrefissiTesto, PIPE, gnTipo + (gnCampo - 1))
; imposta anche il suffisso, con il criterio precedente, formattandovi il termine attivo
Let sSuffisso = FormatString (StringSegment (lstSuffissiTesto, PIPE, gnTipo + (gnCampo -1)), ComponeTermine ())
; crea il titolo della finestra d'inserimento testo
Let sTitolo = FormatString (ttlInputDato, sNome, sPrefisso, gsTermine, sSuffisso)
Let sTesto = sDato; duplica il testo inserito per il successivo confronto
If gnCampo == PRIMA Then; se si è nella schermata iniziale,
Let sVideo = StringLower (CreaElenco (gsArchivio, sSezione)); rileva le voci da non immettere,
Let sVietati = CambiaCampo (sVideo, StringLower (sDato), FALSE, BELL); e vi toglie il dato
EndIf; fine controllo campo
While !iModifica; continua finché il valore rimane a zero
Let sTesto = InserisceTesto (sTitolo, sTesto, gnMultiple, sVietati); memorizza il dato eventualmente immesso
SpeechOff (); spegne comunque la sintesi,
Let gnStato = TRUE; e ne imposta la riattivazione programmata
If !sTesto ; se nessun dato è presente,
|| sTesto == sDato Then; oppure, se il dato non è stato modificato,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo presenza dato
Let iModifica = TRUE; imposta il valore per l'uscita dal ciclo
If gsCategoria == SCRIPTS ; se si stanno elaborando gli script personali,
&& gnCampo == QUARTA Then; e si stanno modificando le azioni da compiere,
If !ConfermaAzioni (sTesto) Then; se i dati inseriti non sono stati riconosciuti,
Let iModifica = FALSE; annulla il valore per tornare all'inserimento
EndIf; fine controllo tasti validi
EndIf; fine controllo campo
EndWhile; fine ciclo modifica
If !sChiave Then; se una chiave non è stata specificata,
Let sChiave = ChiaveGlobale (); prende il valore dall'eventuale variabile, o dalla prima chiave nell'elenco
EndIf; fine controllo chiave
If !ScriveCampo (gsArchivio, sSezione, sChiave, sTesto) Then; se la scrittura fallisce,
Return FALSE; restituisce un risultato nullo
Else; altrimenti, se il dato è trascritto,
If gnCampo == PRIMA Then; se si è nella schermata iniziale,
Let gsChiave = sChiave; allinea il dato utilizzato
ScriveRecord (gsArchivio, sSezione, ZERO, gsChiave); aggiorna anche il puntatore dell'ultima voce elaborata
EndIf; fine controllo campo
Return TRUE; restituisce l'esito positivo
EndIf; fine controllo scrittura
EndFunction

Collaudo.

1. Se la compilazione va a buon fine, c'è da rendere opzionale l'ultimo parametro dei quattro.

Esercizio 12.3.19. La funzione CercaVoci.

FileScript. Default.JSS

Nome. CercaVoci

Descrizione. Rileva le voci di dati registrate nella sezione e nell'archivio della categoria specificata, consentendo di avviare l'inserimento della prima voce, qualora non ve ne siano ancora di presenti.

Ritorni. Di tipo Int. TRUE, per una rilevazione corretta dei dati; FALSE, per un qualsiasi errore riscontrato.

Parametri.

1. sSezione. La sezione dell'archivio dove elaborare i dati. Di tipo String.

2. sSuffisso. Il suffisso numerico in forma testuale. Di tipo String.

Novità.

1. Le nostre funzioni "ProsegueFlusso ()" e "AggiornaCampo ()".

2. Le costanti "ALTO" e "CATTURA", entrambe equivalenti al valore 1, che rappresentano, nell'ordine, la posizione superiore e la fase di acquisizione dei tasti premuti.

3. La costante "RITARDA", che equivale al valore 4, ed indica i decimi di secondo da attendere dopo l'emissione di un suono.

4. La costante "AGGIUNGE", che invece equivale all'omonimo termine.

Fasi.

1. Si tenta dapprima di rilevare le chiavi dei dati attivi registrati; se dei dati non esistono, oppure se manca la chiave Zero, si tenta di scrivere almeno quest'ultima; se tale scrittura fallisce, il flusso s'interrompe restituendo un risultato nullo.

2. Sono poi eseguiti impostazioni e controlli sempre sulla chiave e sul campo attivi, dopo dei quali si tenta di leggere il dato; se questo già esiste, o ci si trova nell'ultimo campo degli script a gestione personale, il flusso s'interrompe restituendo un risultato positivo.

3. Se ancora si stanno elaborando gli script personali, e ci si trova nel secondo campo, si attiva l'attesa dei tasti e si interrompe il flusso con un risultato nullo.

4. In tutti gli altri casi in cui il dato non esista, si avvia l'immissione di un nuovo dato, casomai chiedendone conferma; se questo inserimento è valido, sono aggiornati gli elenchi delle voci ed il contatore delle stesse, restituendo poi l'esito positivo; se invece l'immissione è annullata, viene restituito un risultato nullo.

Note.

1. Se quello precedente era lo strumento attivo principale, questa funzione è quella che gestisce i controlli e l'eventuale inserimento di nuovi dati; essa è chiamata sia nelle fasi di utilizzo dei dati inseriti tramite le procedure, sia durante gli aggiornamenti delle procedure stesse: proprio per questo, si riuscirà a comprenderne il reale funzionamento solo più avanti, quando avremo realizzato le procedure che inseriscono ed aggiornano le stringhe di cui la funzione controlla l'esistenza.

Codice.

Int Function CercaVoci (string sSezione, string sSuffisso)
Var
String sChiavi, ; elenco delle chiavi rilevate
String sChiave; dato temporaneo

Let sChiavi = ChiaviUtente (gsArchivio, sSezione); rileva i dati registrati
If !sChiavi ; se nessuna chiave è ancora registrata nella sezione,
|| !StringSegmentIndex (sChiavi, PIPE, ZERO, TRUE) Then; oppure, se non lo è la chiave Zero,
If !ScriveNumerico (gsArchivio, sSezione, ZERO, FALSE) Then; se la scrittura fallisce,
SayFormattedMessage (OT_ERROR, hlpErroreDato, SALVA); formatta e pronuncia l'avviso,
Return; e interrompe il flusso
EndIf; fine controllo scrittura chiave Zero
EndIf; fine controllo chiavi
Let gsElenco = CambiaCampo (sChiavi, ZERO); rende globale l'elenco delle chiavi, senza la zero
Let gnTotali = StringSegmentCount (gsElenco, PIPE); conta i campi ancora presenti
Let sChiave = ChiaveGlobale (); imposta l'eventuale dato registrato
Let gnCampo = CampoGlobale (); controlla l'impostazione del numero di campo
If LeggeCampo (gsArchivio, sSezione, sChiave) ; se esiste un dato per il campo,
|| (gsCategoria == SCRIPTS ; oppure, se si stanno elaborando gli script personali,
&& gnCampo == gnMaxCampi) Then; e ci si trova nell'ultimo campo,
Return TRUE; restituisce l'esito positivo
ElIf gsCategoria == SCRIPTS; se si stanno solo elaborando gli script Personali,
&& gnCampo == SECONDA Then; ma si è nel secondo campo,
Suona (Nota (gnCampo - 1), RITARDA); emette una nota ascendente,
Let gnFerma = CATTURA; imposta il valore per l'attesa dei tasti,
Return FALSE; e torna alla funzione chiamante
Else; altrimenti, negli altri casi in cui manca il dato,
If gnTipo != TERZA ; se non si stanno elaborando più campi,
|| gnCampo == PRIMA Then; oppure, se si è in ogni caso al primo campo,
If !ProsegueFlusso (gsCategoria, sSuffisso) ; se non si vuole proseguire,
Return FALSE; interrompe il flusso, restituendo un risultato nullo
EndIf; fine controllo conclusione
EndIf; fine controllo campo valido
Suona (Nota (gnCampo - 1), RITARDA); emette una nota ascendente
If AggiornaCampo (AGGIUNGE, sSezione, sChiave, NULLO); se l'aggiornamento riesce,
; rileva nuovamente i dati registrati, rimuovendo la chiave zero
Let gsElenco = CambiaCampo (ChiaviUtente (gsArchivio, sSezione), ZERO)
Let gnTotali = StringSegmentCount (gsElenco, PIPE); quindi, riconta i campi dell'elenco,
Return TRUE; e restituisce l'esito positivo
EndIf; fine controllo aggiornamento
EndIf; fine controllo dato
Return FALSE; se nessun altro controllo ha interrotto il flusso, restituisce un risultato nullo
EndFunction

12.4. Muoversi di caratteri o pixel.

Questa breve sezione è composta da una coppia di funzioni, le quali hanno come effetto lo spostarsi del cursore di un carattere avanti o indietro. Il loro compito è però anche quello di valutare come Jaws riesca a leggere la posizione del cursore, ed in particolare se sulla base del numero di caratteri, di pixel, oppure in nessun modo.

Per fare questo, Jaws utilizza Le funzioni "GetCursorRow ()" e "GetCursorCol ()", che se ricordate servono a rilevare, nell'ordine, il valore della posizione di riga e colonna. Se a tali funzioni non si indicano parametri, in primo luogo esse tenteranno di rilevare la posizione nel numero di caratteri e solo dopo, se il primo tentativo fallisce, restituiranno il valore in pixel.

Il problema è che la posizione di riga e di colonna, se espressa in caratteri, può avere nel documento un valore assoluto, mentre i pixel indicano sempre e solo la posizione relativa del cursore nello schermo.

Se volete capire meglio la differenza tra i due sistemi, seguite questa rapida prova:

1. Aprite il file script Predefinito, "Default.JSS", e portatevi alla fine del file.

2. Eseguite il nostro script per leggere il numero della riga corrente, premendo i tasti "Control+J", e sarà pronunciato un numero di righe ben superiore alle 20000.

3. Ora uscite dall'Editor di Script, e portatevi nella cartella delle impostazioni per l'Utente. Qui selezionate il file script di prima "Default.JSS", ma non cliccatevi sopra con Invio, bensì agite sul comando "Apri con..." del menu contestuale.

4. Qui selezionate il Blocco Note e, una volta apertosi il file, andate ancora alla sua fine. Se agite ora sulla combinazione "Control+J", vi sarà letto un valore variabile, dell'ordine di qualche centinaia, che rappresenta appunto i pixel della posizione relativa del cursore nello schermo.

Questo succede perché nel Blocco Note, con documenti di grandi dimensioni, Jaws non riesce più a rilevare la posizione in caratteri, per righe e colonne, e passa appunto a restituirli per pixel. In questi particolari casi, tuttavia, possiamo tornare ad usare la lettura tramite la Bara di Stato, che, a patto abbiate ancora disponibili le impostazioni predisposte nel nono capitolo, può fornirci i dati a noi necessari.

A tal fine, la nostra funzione farà un piccolo test, cercando di leggere la posizione con questo sistema. Se ci riesce, imposta il valore 1 ad una variabile globale, indicando così agli altri elementi di codice di prelevare i dati tramite la nostra funzione "InfoStato ()".

Se per far agire questa funzione servisse reimpostare il separatore dei dati, che ricordiamo essere nel Blocco Note il carattere Virgola, la procedura consentirà di inserirlo direttamente. Se in ogni caso i dati non fossero configurati, o non consentissero di leggere riga e colonna tramite la Barra di Stato, la situazione sarebbe annotata sempre sulla stessa variabile globale, ponendovi il valore 2.

Importante notare che, anche nel caso fosse impossibile rilevare i dati precisi sulla posizione del cursore, la procedura riuscirà comunque a funzionare. Essa, infatti, si muove come faremmo noi con le frecce, in alto ed in basso, o a destra e sinistra, e l'unico dato che serve veramente è sapere, quando si trova un elemento cercato, se ci si trovi o meno ad inizio riga.

Di questo si occupa in particolare il primo elemento di codice del blocco, sfruttando il risultato della funzione nativa "GetPriorCharacter", (OttieniCaratterePrecedente). Tale funzione di Jaws, infatti, non restituisce sempre il solo carattere che precede il cursore, come starebbe ad indicare la traduzione, bensì a volte anche una vera e propria stringa; tale stringa testuale, in alcuni applicativi contiene anche uno spazio, oltre al carattere che precede, oppure i caratteri di controllo per il Ritorno a Capo o la Nuova Linea, quando si è posizionati nella prima colonna.

E proprio questa sarà la caratteristica che andremo ad utilizzare di tale funzione, la quale avrebbe anche un parametro facoltativo, ma che non serve specificare. Essa, dunque, qui di seguito sarà inserita in una struttura con alcuni controlli, i quali restituiscono un valore positivo quando si è ad inizio riga, ed un risultato nullo in tutti gli altri casi.

Esercizio 12.4.1. La funzione InizioRiga.

FileScript. Default.JSS

Nome. InizioRiga

Descrizione. Determina se il cursore attivo si trova all'inizio della riga corrente.

Ritorni. Di tipo Int. TRUE, per il cursore attivo posto a inizio riga; FALSE, per qualsiasi altra posizione del cursore.

Novità.

1. La funzione integrata "GetPriorCharacter ()", già illustrata nella premessa.

Codice.

Int Function InizioRiga ()
Var String s; singolo carattere

; rileva il carattere iniziale della stringa, ottenuta controllando quello precedente
Let s = StringLeft (GetPriorCharacter (), PRIMA)
If !s ; se il carattere è vuoto,
|| s == CR; oppure, è un Ritorno a Capo,
|| s == LF Then; o, infine, un carattere di Nuova Linea,
Return TRUE; restituisce l'esito positivo
Else; altrimenti,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo posizione cursore
EndFunction

Esercizio 12.4.2. La funzione MisuraMovimento.

FileScript. Default.JSS

Nome. MisuraMovimento

Descrizione. Muove il cursore in avanti o indietro di un carattere, sulla base del valore indicato nel primo parametro, determinando se nel documento corrente la procedura riesce a rilevare la posizione del cursore come colonne e righe.

Ritorni. Di tipo Int. TRUE, per un movimento sulla base di colonne e righe; FALSE, per la rilevazione in un'altra unità di misura, o per l'arrivo agli estremi di un documento.

Parametri.

1. iVerso. La direzione del movimento del cursore: 1, per AVANTI; 2, per INDIETRO. Di tipo Int.

2. x. Per Riferimento. La posizione orizzontale del cursore dopo lo spostamento. Di tipo Int.

Novità.

1. La costante "AVANTI", di valore 1, che indica lo spostamento del cursore verso destra.

Fasi.

1. Come impostazioni iniziali, si spegne la sintesi, e si rilevano i valori di riga e colonna di partenza.

2. Una prima struttura di controllo sposta il cursore di un carattere avanti o indietro, a seconda del valore specificato come parametro.

3. Dopo aver resettato la schermata , si rilevano nuovamente i valori di riga e colonna, e si riattiva la sintesi vocale.

4. Una seconda struttura confronta i valori memorizzati, sulla base della direzione del movimento; in particolare, si controlla se il cursore risulta essersi mosso di una sola unità, oppure, se così non è, se si riescano a leggere i dati dalla Barra di Stato, impostando in una variabile globale il valore che indichi l'esito del controllo.

5. Sempre nel caso di movimento del cursore, si controlla se ci si trovi sulla prima colonna, tramite la nostra funzione "InizioRiga ()", casomai trasmettendo per riferimento il valore 1, come colonna di partenza della successiva ricerca, a prescindere dal tipo di rilevazione dei caratteri effettuata; al termine del controllo, viene comunque restituito un valore positivo.

6. Se il cursore invece non si è mosso, si pronuncia l'avviso di aver raggiunto uno dei due limiti del documento, restituendo poi un risultato nullo.

Codice.

Int Function MisuraMovimento (int iVerso, int ByRef x)
Var
Int iStato, ; stato di attivazione della sintesi
Int c, ; prima rilevazione colonna
Int r, ; prima rilevazione riga
Int y, ; seconda rilevazione riga
String s; primo carattere della stringa ottenuta rilevando quello precedente

Let iStato = ControllaSintesi (FALSE); spegne la sintesi, memorizzandone lo stato
Let c = ValoreColonna (); registra il numero della colonna di partenza
Let r = ValoreRiga (); memorizza anche il numero di riga
If iVerso == AVANTI Then; Se ci si deve muovere in avanti,
NextCharacter (); chiama la funzione nativa
Else; altrimenti, per muoversi all'indietro,
PriorCharacter (); chiama l'altra funzione originale
EndIf; fine controllo direzione
Refresh (); resetta la schermata
Let x = ValoreColonna (); registra la nuova posizione orizzontale
Let y = ValoreRiga (); memorizza anche la nuova posizione verticale
ControllaSintesi (iStato); ripristina lo stato di attivazione precedente
If x != c ; se il cursore si è mosso in orizzontale,
|| y != r Then; oppure, se ha soltanto cambiato riga,
If (r == y && (x == (c +1) || x == (c - 1))) ; se la riga non è cambiata, e la colonna è diversa d 1,
|| (x == c && (r == (y + 1) || r == (y - 1))) Then; o invariata è la colonna, e la riga è spostata di 1,
Let gnRilevamento = FALSE; azzera il valore sulle modalità di rilevazione
ElIf InfoStato (RIGA, TRUE) Then; se invece i dati si possono rilevare dalla Barra di Stato,
Let gnRilevamento = PRIMA; annota di usare tale metodo
Else; altrimenti, se non si può rilevare la posizione orizzontale,
Let gnRilevamento = SECONDA; imposta di portare comunque il cursore ad inizio riga
EndIf; fine controllo modalità rilevazione
If InizioRiga (); se ci si trova nella prima colonna,
Let x = 1; omologa la posizione di partenza, a prescindere dalla modalità di rilevazione
EndIf; fine controllo carattere precedente
Return TRUE; in ogni caso, restituisce l'esito positivo
Else; altrimenti, se il cursore non si è mosso,
Suona (ERRORE1); emette un segnale acustico
If iVerso == AVANTI Then; se ci si doveva spostare in avanti,
SayMessage (OT_ERROR, hlpFineFile, hlpFineFile_corto); pronuncia l'avviso,
Else; altrimenti, se ci si doveva muovere all'indietro,
SayMessage (OT_ERROR, hlpInizioFile, hlpInizioFile_corto); pronuncia l'avviso,
EndIf; fine controllo direzione
Return FALSE; in ogni caso, restituisce un risultato nullo
EndIf; fine controllo movimento cursore
EndFunction

12.5. La ricerca e l'avvio programmato delle funzioni.

Giunti alla penultima sezione del capitolo, affrontiamo ora il cuore della procedura, quello che si occupa di scorrere il documento e, su ciascuna riga, di cercare le stringhe impostate.

Le ricerche successive, che si susseguono una dopo l'altra finché un elemento non sia stato trovato, sono rese possibili da un "avvio programmato" delle funzioni. Questo sistema consente di definire dopo quanti decimi di secondo ciascun elemento di codice deve essere chiamato, sospendendo così il solito schema delle istruzioni eseguite l'una dopo l'altra.

Nel nostro caso, noi iniziamo lanciando la ricerca delle stringhe, stabilendo un tempo limite di tre secondi. Trascorso questo tempo, se nessuna stringa è stata trovata, la funzione di ricerca viene riavviata, e così via, sino al verificarsi di uno di questi tre possibili eventi:

- Il ritrovamento di una stringa.
- La pressione del tasto Escape per interrompere la ricerca.
- L'arrivo ad uno degli estremi del documento.

Le funzioni che regolano questo sistema sono due:

1. "ScheduleFunction", (ProgrammaFunzione).

2. "UnScheduleFunction", (DeProgrammaFunzione).

Come si può capire dalle traduzioni, la prima serve ad impostare la programmazione, la seconda a cancellarla.

Nel dettaglio, "ScheduleFunction ()" restituisce un valore progressivo con il quale Jaws identifica quel tipo di programmazione. Per questo, di solito il risultato della funzione va assegnato ad una variabile numerica, la quale viene poi usata per identificare l'avvio programmato da cancellare. Per programmare un avvio, alla funzione si devono specificare due parametri:

1. Il nome della funzione da avviare, che va inserito come un testo tra virgolette, oppure tramite costanti o variabili, usando il solo nome senza specificare eventuali parentesi.

2. Il numero dei decimi di secondo dopo i quali si vuole che l'a funzione sia avviata.

Nelle ultime versioni di Jaws la funzione avrebbe anche un terzo parametro opzionale , che consente di interrompere la programmazione al verificarsi di alcuni eventi o premendo un tasto. Pur essendo un aspetto che dovremo implementare nel nostro sistema, eviteremo di usare questo ulteriore parametro al fine di rendere la riga di codice compatibile anche con versioni di Jaws meno recenti.

Per quel che riguarda "UnScheduleFunction ()", invece, essa ha come unico parametro proprio il valore numerico che identifica la programmazione da cancellare. Per evitare che ci possano essere degli avvii inopportuni della funzione, la prassi consiglia di usare sempre una struttura di controllo con tale funzione prima di impostare l'avvio vero e proprio, usando il seguente schema:

If ValoreIdentificativo Then; se un avvio programmato è attivo,
UnScheduleFunction (ValoreIdentificativo); cancella la precedente impostazione
EndIf; fine controllo avvii programmati
; imposta il nome della funzione ed il tempo dopo il quale avviarla
Let ValoreIdentificativo = ScheduleFunction (NOME_FUNZIONE, NUMERO_DECIMI)

Quindi, solitamente, prima ci si accerta di cancellare eventuali avvii programmati di un certo tipo, poi casomai si impostano, o reimpostano, tali avvii.

Ovviamente, nel caso si debba soltanto cancellare una programmazione, si potrà usare la sola "UnScheduleFunction ()", avendo cura di porvi come parametro il valore che la identifica.

12.5.1. Il motore della ricerca.

Così come si accennava, nelle prossime funzioni sono raccolte il vero cuore operativo della procedura e, quindi, dell'intero capitolo. In particolare, l'ultima di queste sarà la funzione programmata, quella che viene avviata da "ScheduleFunction ()", al servizio della quale operano tutte le altre.

A tal proposito, la struttura di controllo, che nell'esempio di prima coinvolgeva "UnScheduleFunction ()", l'abbiamo racchiusa in una funzione a sé stante, sia per semplificare il codice, sia per potercene servire anche in ulteriori utilizzi dell'avvio programmato in altre procedure. Per favorire il dialogo tra gli elementi, senza l'uso di parametri, abbiamo usato una variabile globale per memorizzare il valore che identifica l'eventuale avvio programmato.

Per quanto riguarda le altre funzioni, la prima serve soltanto a gestire la pronuncia dei messaggi durante la ricerca, che può essere la percentuale del documento o il numero di righe. La seconda di questo blocco, invece, è il vero e proprio strumento di ricerca, che controlla le singole righe di testo, passate alla funzione come parametro, se contengano o meno le stringhe da trovare.

Esercizio 12.5.2. La funzione PosizioneDocumento.

FileScript. Default.JSS

Nome. PosizioneDocumento

Descrizione. Pronuncia lo stato di avanzamento della ricerca, leggendo la percentuale elaborata del documento corrente, se rilevabile, oppure il numero della riga sul cursore.

Ritorni. Di tipo Void. Nessuno.

Fasi.

1. Dopo aver spento comunque la sintesi, controlla che ci si trovi al primo passaggio; se così è, viene pronunciato un avviso che indica di poter fermare la ricerca premendo il tasto Escape, valorizzando poi la variabile globale che ne impedisce la rilettura.

2. Dal secondo passaggio in poi, si tenta di rilevare la percentuale della posizione del cursore rispetto al documento; se un valore è stato rilevato, lo si pronuncia, altrimenti sarà letto il numero della riga sul cursore.

Codice.

Void Function PosizioneDocumento ()
Var Int iPosiz; percentuale nel documento corrente

SpeechOn (); riattiva la sintesi
If !gnPrimo Then; se si è al primo passaggio,
SayMessage (OT_ERROR, hlpPremiEsc); avvisa di fermare la ricerca premendo il tasto Escape,
Let gnPrimo = TRUE; e imposta il valore per impedirne la rilettura
Else; altrimenti,
Let iPosiz = GetDocumentPercentage (); rileva la posizione in percentuale rispetto al documento
If iPosiz Then; se una percentuale è stata rilevata,
; formatta e pronuncia il valore rilevato
SayFormattedMessage (OT_ERROR, msgPercento, NULLO, iPosiz)
Else; altrimenti,
; formatta e pronuncia il numero della riga corrente
SayFormattedMessage (OT_ERROR, msg1, NULLO, gnValore)
EndIf; fine controllo percentuale
EndIf; fine controllo avvisi
SpeechOff (); spegne la sintesi
EndFunction

Esercizio 12.5.3. La funzione CercaElementi.

FileScript. Default.JSS

Nome. CercaElementi

Descrizione. Scorre gli elementi da cercare, restituendo il primo elemento trovato nel testo passato come parametro.

Ritorni. Di tipo String. L'elemento di ricerca trovato.

Parametri.

1. sTesto. Il testo in cui cercare. Di tipo String.

2. iPartenza. Se valorizzato, indica la colonna da cui è partita la ricerca, nel caso non sia la prima. Di tipo Int.

Novità.

1. La costante "RICERCA_INTERNA", dove è memorizzato un carattere speciale per indicare le stringhe che devono essere cercate all'interno del testo, non dal suo inizio, che nel nostro caso è il carattere E Commerciale.

2. Le costanti "INIZIO" e "INTERNO", equivalenti a dei valori numerici, rispettivamente 3 e 4.

Fasi.

1. Un ciclo scorre le stringhe da cercare, memorizzate in una variabile globale.

2. La singola stringa, o elemento di ricerca, viene analizzato per impostare il tipo di ricerca da effettuare, valutando se si tratti di un testo da cercare a partire dall'inizio della riga, oppure se vada trovato al suo interno; in quest'ultimo caso, oltre ad impostare il tipo, viene ripulito anche l'elemento di ricerca dal carattere indicatore.

3. Una seconda struttura di controllo effettua materialmente le ricerche, sfruttando le funzioni native di Jaws, sulla base del tipo impostato; quando un elemento viene trovato, il flusso s'interrompe, restituendolo.

4. Se il ciclo si conclude senza aver individuato alcun elemento, viene restituito un risultato nullo.

Codice.

String Function CercaElementi (string sTesto, int iPartenza)
Var
Int i, ; contatore del ciclo
String sElemento, ; stringa da cercare
Int iTipo; modalità di ricerca

For i = 1 To gnTotali; scorre gli elementi rilevati
Let sElemento = StringSegment (gsElenco, BELL, i); estrae il singolo termine da cercare
; controlla che il primo carattere dell'elemento non sia quello che indica di cercare dentro alla riga
If !StringStartsWith (sElemento, RICERCA_INTERNA) Then; se tale carattere non è,
Let iTipo = INIZIO; imposta di cercare ad inizio riga
Else; altrimenti, se il carattere segnalatore è presente,
Let iTipo = INTERNO; imposta il valore per la ricerca all'interno,
Let sElemento = StringChopLeft (sElemento, StringLength (RICERCA_INTERNA)); e lo rimuove
EndIf; fine controllo tipo ricerca
If iPartenza <= PRIMA ; se la ricerca può partire dalla prima colonna,
&& iTipo == INIZIO Then; ed è da lì che bisogna cercare,
If StringStartsWith (sTesto, sElemento) Then; se il termine è coincide,
Return sElemento; restituisce l'elemento trovato
EndIf; fine controllo presenza all'inizio
ElIf iTipo == INTERNO Then; se l'elemento va cercato invece dentro alla riga,
If StringContains (sTesto, sElemento) Then; se l'elemento è stato trovato,
Return sElemento; lo restituisce
EndIf; fine controllo ritrovamento interno
EndIf; fine controllo ritrovamenti
EndFor; fine scansione elementi
Return NULLO; se nessun altro controllo è intervenuto, restituisce una stringa vuota
EndFunction

Per ulteriori spiegazioni, scrivere a: Abramo Volpato, oppure, a: Nunziante Esposito



Torna alla pagina iniziale della consultazione delle riviste

Oppure effettua una ricerca per:


Scelta Rapida