Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript text to speech for different elements

I am trying to use text to speech to help the blind users to use my website as part of my project, it worked well with me for the input, select and button elements. But I want also to make voice for the other elements such label elements. I tried to use (for) instead of id and tried to use the event (mouseover) instead of ( Click) but it didn't work. Can you please help me with that or if there is any suggestions? this is my code:

<div class="all">

<form action="/action_page.php">
  <div class="container">
    <h1>Register</h1>
    Select Voice: <select id='voiceList'></select> <br><br>

    <p>Please fill in this form to create an account.</p>
    <hr>
    <input id='text1' type="text" placeholder="Enter Email" name="email" required>
    <label id="email" for="email"><b>Email</b></label>

<br/>
 <label for="email"><b>Name </b></label>
    <input id='text2' type="text" placeholder="Enter Name" name="email" required>
<br/>
    <label for="psw"><b>Password </b></label>
    <input id='text3' type="password" placeholder="Enter Password" name="psw" required>
<br/>
    <label for="psw-repeat"><b>Mobile </b></label>
    <input id='text4' type="password" placeholder="Mobile" name="psw-repeat" required>
    <br/>
        <label for="psw"><b>Gender </b></label>
   <select   id = "myList" style="font-size:15px;">
               <option >Male</option>
               <option >Female</option>

             </select>
             <hr>
    <button type="submit" class="registerbtn">Register</button>
  </div>

  <div class="container signin">
    <p>Already have an account? <a href="#">Sign in</a>.</p>
  </div>
</form>
</div>
<script>
        var txtInput1 = document.querySelector('#text1');
         var txtInput2 = document.querySelector('#email');

        var txtInput3 = document.querySelector('#text3');
        var txtInput4 = document.querySelector('#text4');

        var txtInput5 = document.querySelector('#myList');


        var voiceList = document.querySelector('#voiceList');
        var synth = window.speechSynthesis;
        var voices = [];

        //PopulateVoices();
        if(speechSynthesis !== undefined){
            speechSynthesis.onvoiceschanged = PopulateVoices; 
        }

        txtInput1.addEventListener('mouseover', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(txtInput1.value);
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });

         txtInput2.addEventListener('mouseover', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(txtInput2.value);
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });
txtInput3.addEventListener('click', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(txtInput3.value);
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });
txtInput4.addEventListener('click', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(txtInput4.value);
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });
        txtInput5.addEventListener('mouseover', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(txtInput5.value);
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });

        function PopulateVoices(){
            voices = synth.getVoices();
            var selectedIndex = voiceList.selectedIndex < 0 ? 0 : voiceList.selectedIndex;
            voiceList.innerHTML = '';
            voices.forEach((voice)=>{
                var listItem = document.createElement('option');
                listItem.textContent = voice.name;
                listItem.setAttribute('data-lang', voice.lang);
                listItem.setAttribute('data-name', voice.name);
                voiceList.appendChild(listItem);
            });

            voiceList.selectedIndex = selectedIndex;
        }
    </script>

</body>
like image 820
Saleh Refaai Avatar asked Jun 13 '20 00:06

Saleh Refaai


2 Answers

Chrome disables SpeechSynthesis without user activation. This answer by @Kaiido himself might be useful. Also refer to this discussion on the Google groups about the deprecation.

Briefly, we will only allow speak() to succeed if the current frame, or any of its ancestors, has ever had user activation.

Activation inputs are the following:

An activation triggering input event is any event whose isTrusted attribute is true and whose type is one of:

  • change
  • click
  • contextmenu
  • dblclick
  • mouseup
  • pointerup
  • reset
  • submit
  • touchend

So, I don't think mouseover event will count as a valid trigger.

If your purpose is to make the website more accessible, I'd recommend what @Kaiido mentioned above - to follow the WAI recommendations.

If you want to use SpeechSynthesis, maybe you can have a small button beside the label that the user might tab to and activate, to hear it?

I was also able to get SpeechSynthesis to work in this project here by having an initial screen that required the user to click to start - and that activation propagated through and allowed SpeechSynthesis usage for the rest of the app.

Do note that Web Speech API is an experimental API - and might not be suitable for production. The SpeechSynthesis part of it is reasonably supported across browsers. However, in my experience of using this API, I've found that the behaviour differs across devices, probably because it sometimes piggy backs on the device's native OS capabilities.

like image 164
iamaatoh Avatar answered Oct 29 '22 01:10

iamaatoh


Just an option you might want to consider is using HTML5 text to speech

basic example:

let msg = new SpeechSynthesisUtterance('Hello World')
window.speechSynthesis.speak(msg)

In your case, do something like this for label elements:

var labelTag = document.querySelector('#email');
labelTag.addEventListener('mouseover', ()=> {
            var toSpeak = new SpeechSynthesisUtterance(labelTag.getAttribute('for'));
            var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
            voices.forEach((voice)=>{
                if(voice.name === selectedVoiceName){
                    toSpeak.voice = voice;
                }
            });
            synth.speak(toSpeak);
        });

I suggest to use jQuery so you can easy bind an event to selected elements and can use "this" reference, that way you don't have to have many variables:

example:

<label for="email"><b>Email </b></label>
<label for="name"><b>Name </b></label>
<label for="password"><b>Password </b></label>

Then:

$('label').mouseover(function() {
   var toSpeak = new SpeechSynthesisUtterance($(this).attr('for'));
   var selectedVoiceName = voiceList.selectedOptions[0].getAttribute('data-name');
   voices.forEach((voice)=>{
      if(voice.name === selectedVoiceName){
          toSpeak.voice = voice;
       }
     });
     synth.speak(toSpeak);
})
like image 30
Karl L Avatar answered Oct 29 '22 00:10

Karl L