Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: Riccardo Ferrari - Aprile 10, 2022, 03:30:02 pm

Titolo: Suoni
Inserito da: Riccardo Ferrari - Aprile 10, 2022, 03:30:02 pm
Ho l’esigenza che il PC mi avvisi in corrispondenza di un determinato evento che non spiego per non dilungarmi troppo, se interessa farò un altro post.

Una procedura ciclica scrive a video il risultato, se è ZERO (la maggior parte delle volte) non devo fare nulla, se è maggiore di ZERO mi devo attivare per altro. Ciò comporta che devo guardare lo schermo. Ho quindi pensato di associare un suono al risultato maggiore di zero.

Come ho letto qui sul forum, neanch’io riesco ad ottenere risultati né con la funzione Beep dell’unit SysUtils, né con le funzioni Sound(x) e Delay(y) dell’unit Crt, ne con la funzione MessageBeep(z) dell’unit Windows. Nulla: nemmeno errore, linea di codice semplicemente ignorata, una specie di NOP.
 
Maggior fortuna (nei limiti che vedremo) l’ho ottenuta con l’unit MMSystem e con le sue funzioni “sndPlaySound” e “PlaySound”, avrò studiato poco ma non ho capito la differenza tra le due.

Accettano molteplici argomenti, che poi sono numeri. A me funzionano solo in modo sincrono con argomento SND_SYNC (cioè 0), il modo asincrono con l’argomento SND_ASYNC (cioè 1) non funziona, come i precedenti delle altre Unit, cioè non dà errore ma nemmeno suona

Per quello che ho capito il modo sincrono suona e al termine restituisce il controllo, il modo asincrono inizia a suonare e restituisce immediatamente il controllo. A me il controllo lo restituisce subito, ma non suona.

Entrambe le funzioni “sndPlaySound” e “PlaySound” richiedono un file da suonare. Se è WAV lo suonano, se non è WAV ma OGG o MP3 oppure il file indicato non esiste il comportamento è lo stesso, suonano una musichetta di windows senza avvisare dell’errore, una specie di “BLONG”

Non ho ancora modificato il programma in cui volevo inserire l’avviso acustico, farò un brevissimo WAV di un suono qualunque e gli faccio leggere quello, oppure metto un nome di file inesistente e mi gli faccio suonare il “BLONG” che tira fuori quando non sa fare altro.

Ho ascoltato tutti gli WAV che ho trovato, il “BLONG” corrisponde al file “C:\Windows\Media\Windows Background.wav” size: 213.624 md5: 47E241309A6B0F25B3F140A22FBD1DAF

Mi sarei accontentato del “Beep” dell’unit Sysutil. Perché non funziona?
Titolo: Re:Suoni
Inserito da: DragoRosso - Aprile 10, 2022, 03:49:10 pm
Ciao,
inanzitutto la funzione Beep è l'incapsulamento di una API di Windows, e in particolare di una API di sistema.

Con Beep non sai se e cosa verrà emesso perchè dipende dai settaggi dell'ambiente utente di Windows (che varia da versione a versione).

Il metodo consigliato da Microsoft è "PlaySound", mentr eè sconsigliato sndPlaySOund (che è un subset di PlaySound) (https://docs.microsoft.com/it-it/windows/win32/multimedia/the-playsound-function (https://docs.microsoft.com/it-it/windows/win32/multimedia/the-playsound-function)

PlaySound è una funzione di vecchia data (esiste penso già da Win95) ed è per questo che "funziona" solo con il file in formato WAV.

Il bello però di questa funzione è che non necessita di un file fisico presente su disco, ma può usare un file presente nelle RISORSE dell'eseguibile. Io è da sempre che lo uso, inserendo i mie file WAV nelle risorse, togliendomi da tutte le pesti del caso.

Puoi usare la seguente forma:

PlaySound('Suono', HINSTANCE, SND_RESOURCE OR SND_ASYNC);

Dove "Suono" è una risorsa "compilata" nell'eseguibile di questo tipo:

Suono  WAVE "Allarme.wav"

Su Lazarus puoi inserire il file WAV nelle risorse defininendolo come tipo WAVE e nome "Suono" (o qualsiasi altro nome che ti sconfifera).

Se hai ulteriori dubbi rimaniamo in "ascolto".

Ciao
Titolo: Re:Suoni
Inserito da: DragoRosso - Aprile 10, 2022, 04:28:37 pm
Aggiungo una ulteriore info all'argomento.
Qui si và un pò oltre a quello che è il "topic", ma comunque è in qualche modo collegato.

In Windows, è possibile dare alla tua applicazione una funzionalità "avanzata" in maniera molto semplice usando le API di sistema "SAPI". Sono presenti in tutti i SO Windows e consentono di generare molto facilmente un TextToSpeech. Ovvio che non è un TTS professionale ma è di qualità sufficiente per fare alcune simpatiche cose:

"Avvio applicazione, attendere pergo"

"E' stato generato un errore durante l'esecuzione del programma"

"Il sistema è in attesa di una conferma da parte di un operatore"

etc ......

In un ambiente dove l'operatore potrebbe non essere davanti allo schermo tali "feature" hanno una utilità ben apprezzata.

Ed è pure disponibile in più lingue (Inglese sempre + la localizzazione in Italiano ad esempio).

Se sei interessato fai un cenno e pubblico qualcosa (magari cercando nel forum qualcosa c'è già).

EDIT: link al forum ufficiale di Lazarus https://wiki.lazarus.freepascal.org/SAPI (https://wiki.lazarus.freepascal.org/SAPI)

Ciao
Titolo: Re:Suoni
Inserito da: Riccardo Ferrari - Aprile 10, 2022, 05:15:43 pm
Puoi usare la seguente forma:
PlaySound('Suono', HINSTANCE, SND_RESOURCE OR SND_ASYNC);
Dove "Suono" è una risorsa "compilata" nell'eseguibile di questo tipo:
Suono  WAVE "Allarme.wav"

Grazie, userò il metodo che mi hai indicato.

Ho fatto un paio di prove e funziona. Solo un programma di un paio di linee giusto per prova, non l’ho ancora inserito nel programma principale.
A questo punto spiego di cosa si tratta. Hai visto mai che mi trovate la soluzione per evitare anche il suono?

Un sito che devo consultare periodicamente fornisce una gran quantità di dati a video che mi servono. Però solo a video: non riesco a salvarli.
Salvando la pagina html rimangono dentro solo quelli a video, non quelli delle pagine già scorse ed uscite dallo schermo

Mi sono accorto che i dati vengono salvati nella cache cancellando quelli precedenti, per cui se leggo la cache dopo aver scorso tutte le pagine perdo la maggior parte dei dati.

Ho fatto quindi un programma che legge la cache, salva i dati, e mi dice se ci sono dei cambiamenti, se non ci sono cambiamenti il risultato è lo ZERO del post precedente.

Se ci sono dei cambiamenti faccio page-down quindi il suono mi serve per attirare l’attenzione senza fissare lo schermo.

Potrei evitare il suono se un risultato maggiore di ZERO invece di suonare facesse automaticamente page-down nel browser.

La difficoltà che ho incontrato in questo approccio è che la finestra attiva (quella cioè che sente i comandi della tastiera) è quella del browser,
mentre il mio programma lavora in background e sullo schermo vedo scorrere i risultati dell’analisi della cache.

Quando vedo il risultato diverso da zero schiaccio page-down e il browser scorre. Ma è possibile farlo automaticamente?
Cioè un programma che gira in back-ground faccia “qualcosa” che equivalga a page-down nella finestra attiva?
Non ne ho idea.
Titolo: Re:Suoni
Inserito da: DragoRosso - Aprile 10, 2022, 07:12:06 pm
In genere quando feci anni fà cose simili ho usato un tool tipo SPY di Microsoft con cui mi identificavo i controlli e le istanze andando a cercare qualcosa di caratteristico (titolo, nome dei controlli, classi, etc ..) poi mi segnavo la catena dei child e replicavo in codice con la funzione FindHandle di Windows. Un bordello insomma.

Poi non mi è più servita quella tecnica, fortunatamente.

Il problema è che devi identificare non solo l'applicazione (il browser) che sarebbe facilissimo, ma anche la "pagina" e il controllo specifico per inviare il "tasto" simulato PGDown.

Ma invece di accedere ai dati del Browser, non puoi accedere direttamente alla fonte dei dati ?

In alternativa, qualcuno altro della comunity potrebbe esserti utile con la sua esperienza.

Ciao
Titolo: Re:Suoni
Inserito da: Riccardo Ferrari - Aprile 11, 2022, 11:39:54 am
[...] Un bordello insomma.

[...] per inviare il "tasto" simulato PGDown.

[...] accedere direttamente alla fonte dei dati ?


Se la ricerca è un “bordello” (immagino di sì) lasciamola un da parte per il momento.
Apparirebbe più facile la fine, cioè inviare il tasto simulato PGDown.
Ammesso di aver fatto bene tutto il resto, come si simula il PGDown?
Variante complicata: come si simula il PGDown in un’altra finestra?

Quanto all’accesso diretto ai dati, non è possibile (o quanto meno non ne sono capace) devo passare necessariamente dal browser.
Devo dire che tutto sommato il sistema che mi sono inventato funziona.
C'è la scocciatura di dover premere PGDown ogni volta che a video appare un risultato diverso da zero.
Ovvero, per meglio dire, c’era. Quando avrò messo la modifica del suono basterà premere il tasto dopo il fischio del PC.
Se riuscissi a fare PGDown automatico …

Grazie per l’attenzione
Titolo: Re:Suoni
Inserito da: bonmario - Aprile 11, 2022, 12:01:04 pm
Ammesso di aver fatto bene tutto il resto, come si simula il PGDown?
Variante complicata: come si simula il PGDown in un’altra finestra?

Quando mi è capitato di dover fare qualcosa di simile, ho suddiviso il problema in 2 parti:
- prima portavo in primo piano l'applicativo,
- poi lanciavo la sequenza di tasti che mi serviva

Ti posso però assicurare che era una di quelle cose che devi tenere continuamente in manutenzione: da un momento all'altro smetteva di funzionare, e bisognava cercare un modo per aggirare il problema.

Nel tuo caso, potresti provare un altro approccio, come già consigliato da @DragoRosso: scaricare periodicamente la pagina che ti interessa, e fare i ragionamenti su quello.

Ciao, Mario
Titolo: Re:Suoni
Inserito da: Stilgar - Aprile 11, 2022, 01:13:41 pm
Ciao.
Lo sceen scrabbing della pagina su che url deve essere fatto?
Magari la pagina carica i dati attraverso un json, quindi ti basterebbe leggere quello direttamente.
Ipotesi.
Se è una paginetta di vecchia concezione, basta leggere il contenuto dell'html.
A seconda della pagina in questione si possono mettere in campo varie strategie per leggere i dati.
Tutto dipende dalla pagina però :)
(Con tasto F12 del browser vedi subito se nel tab rete ci sono chiamate a sorgenti dati e come vengono eseguite - ordine- basterebbe replicare quelle, se va bene e di lusso)
Stilgar
Titolo: Re:Suoni
Inserito da: Riccardo Ferrari - Aprile 11, 2022, 02:28:56 pm
Grazie a tutti per le risposte.

Per ora mi va bene così: come da impianto di base aggiungendo un avviso sonoro il cui inserimento è stato possibile dopo aver letto questo forum, quindi: grazie ancora

Saluti, alla prossima
Titolo: Re:Suoni
Inserito da: DragoRosso - Aprile 11, 2022, 06:55:32 pm
Questo "funzione" simula la pressione di un tasto (di qualsiasi tipo) della tastiera.

EDIT: funziona solo in Windows e dovete aggiungere la Unit Windows fra le Uses  ::)

Agisce come la tastiera sul controllo che ha il focus (ATTENZIONE: CONTROLLO DI UNA QUALSIASI APPLICAZIONE, NON E' LEGATA A QUESTA).

Se create un progetto, vi aggiungete un Timer a 5 secondi e lo "agganciate" all'evento in coda, avrete una pressione del tasto PgDown ogni 5 secondi sull'applicazione attiva in quel momento (sia esso un browser che un'altra app).

Uso questo codice da vent'anni o giù di lì (o meglio lo usavo perchè è da molto che non lo rispolveravo). Dovrebbe probabilmente trovarsi ancora su qualche forum su Internet.

Codice: [Seleziona]
procedure SimulaPressioneTasto(key: Word; const shift: TShiftState; specialkey: Boolean);
type
  TShiftKeyInfo = record
    shift: Byte;
    vkey: Byte;
  end;
  byteset = set of 0..7;
const
  shiftkeys: array [1..3] of TShiftKeyInfo =
   ((shift: Ord(ssCtrl); vkey: VK_CONTROL),
    (shift: Ord(ssShift); vkey: VK_SHIFT),
    (shift: Ord(ssAlt); vkey: VK_MENU));
var
  flag: DWORD;
  bShift: ByteSet absolute shift;
  i: Integer;
begin
  for i := 1 to 3 do
    begin
      if shiftkeys[i].shift in bShift then
        keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
    end;
  if specialkey then
    flag := KEYEVENTF_EXTENDEDKEY
  else
    flag := 0;
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  flag := flag or KEYEVENTF_KEYUP;
  keybd_event(key, MapvirtualKey(key, 0), flag, 0);
  for i := 3 downto 1 do
    begin
      if shiftkeys[i].shift in bShift then
        keybd_event(shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0),
          KEYEVENTF_KEYUP, 0);
    end;
end;

// Per eseguire la simulazione:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  SimulaPressioneTasto(VK_NEXT, [], False);
end;

Ciao ciao
Titolo: Re:Suoni
Inserito da: Riccardo Ferrari - Aprile 12, 2022, 07:55:08 am
Questo "funzione" simula la pressione di un tasto (di qualsiasi tipo) della tastiera.
[...]

Ti ringrazio per il codice di simulazione della pressione di un tasto.

Ho fatto la modifica del suono e funziona meglio del previsto.

Nel senso che funziona, dal punto di vista informatico, come doveva funzionare: cioè suona al momento giusto.
Funziona meglio del previsto dal punto di visto “umano”: non dover essere costretto a fissare lo schermo in attesa di un risultato diverso da zero è stata una liberazione più grande di quella che mi aspettassi.

Purtroppo in questo momento non ho il tempo per approfondire l’ulteriore modifica conseguente alla pressione virtuale di un tasto.
Se ho capito bene la parte “difficile” (cioè individuare la finestra attiva) è già risolta perché il tuo codice agisce sull’applicazione attiva.
Le premesse quindi sono buone, ma per ora ho già dedicato troppo tempo alla questione. Più avanti ci proverò senz’altro.
Poi faccio sapere, se volete.

Per ora quindi saluti e grazie ancora.