Example #1
0
static void
sayScreenRegion (int left, int top, int width, int height, int track, SayMode mode) {
  size_t count = width * height;
  ScreenCharacter characters[count];

  if (mode == sayImmediate) muteSpeech(__func__);
  readScreen(left, top, width, height, characters);
  spk.track.isActive = track;
  spk.track.screenNumber = scr.number;
  spk.track.firstLine = top;
  spk.track.speechLocation = SPK_LOC_NONE;
  sayScreenCharacters(characters, count, 0);
}
Example #2
0
void
speakCharacters (const ScreenCharacter *characters, size_t count, int spell) {
  int immediate = 1;

  if (isAllSpaceCharacters(characters, count)) {
    switch (prefs.whitespaceIndicator) {
      default:
      case wsNone:
        if (immediate) muteSpeech("white space");
        break;

      case wsSaySpace: {
        wchar_t buffer[0X100];
        size_t length = convertTextToWchars(buffer, gettext("space"), ARRAY_COUNT(buffer));

        sayWideCharacters(buffer, NULL, length, immediate);
        break;
      }
    }
  } else if (count == 1) {
    wchar_t character = characters[0].text;
    const char *prefix = NULL;
    int restorePitch = 0;
    int restorePunctuation = 0;

    if (iswupper(character)) {
      switch (prefs.uppercaseIndicator) {
        default:
        case ucNone:
          break;

        case ucSayCap:
          // "cap" here, used during speech output, is short for "capital".
          // It is spoken just before an uppercase letter, e.g. "cap A".
          prefix = gettext("cap");
          break;

        case ucRaisePitch:
          if (canSetSpeechPitch()) {
            unsigned char pitch = prefs.speechPitch + 7;
            if (pitch > SPK_PITCH_MAXIMUM) pitch = SPK_PITCH_MAXIMUM;

            if (pitch != prefs.speechPitch) {
              setSpeechPitch(pitch, 0);
              restorePitch = 1;
            }
          }
          break;
      }
    }

    if (canSetSpeechPunctuation()) {
      unsigned char punctuation = SPK_PUNCTUATION_ALL;

      if (punctuation != prefs.speechPunctuation) {
        setSpeechPunctuation(punctuation, 0);
        restorePunctuation = 1;
      }
    }

    if (prefix) {
      wchar_t buffer[0X100];
      size_t length = convertTextToWchars(buffer, prefix, ARRAY_COUNT(buffer));
      buffer[length++] = WC_C(' ');
      buffer[length++] = character;
      sayWideCharacters(buffer, NULL, length, immediate);
    } else {
      sayWideCharacters(&character, NULL, 1, immediate);
    }

    if (restorePunctuation) setSpeechPunctuation(prefs.speechPunctuation, 0);
    if (restorePitch) setSpeechPitch(prefs.speechPitch, 0);
  } else if (spell) {
    wchar_t string[count * 2];
    size_t length = 0;
    unsigned int index = 0;

    while (index < count) {
      string[length++] = characters[index++].text;
      string[length++] = WC_C(' ');
    }

    string[length] = WC_C('\0');
    sayWideCharacters(string, NULL, length, immediate);
  } else {
    sayScreenCharacters(characters, count, immediate);
  }
}
Example #3
0
int
handleSpeechCommand (int command, void *datga) {
  switch (command & BRL_MSK_CMD) {
    case BRL_CMD_RESTARTSPEECH:
      restartSpeechDriver();
      break;
    case BRL_CMD_SPKHOME:
      if (scr.number == spk.track.screenNumber) {
        trackSpeech();
      } else {
        playTune(&tune_command_rejected);
      }
      break;
    case BRL_CMD_AUTOSPEAK:
      toggleFeatureSetting(&prefs.autospeak, command);
      break;

    case BRL_CMD_ASPK_SEL_LINE:
      toggleFeatureSetting(&prefs.autospeakSelectedLine, command);
      break;

    case BRL_CMD_ASPK_SEL_CHAR:
      toggleFeatureSetting(&prefs.autospeakSelectedCharacter, command);
      break;

    case BRL_CMD_ASPK_INS_CHARS:
      toggleFeatureSetting(&prefs.autospeakInsertedCharacters, command);
      break;

    case BRL_CMD_ASPK_DEL_CHARS:
      toggleFeatureSetting(&prefs.autospeakDeletedCharacters, command);
      break;

    case BRL_CMD_ASPK_REP_CHARS:
      toggleFeatureSetting(&prefs.autospeakReplacedCharacters, command);
      break;

    case BRL_CMD_ASPK_CMP_WORDS:
      toggleFeatureSetting(&prefs.autospeakCompletedWords, command);
      break;

    case BRL_CMD_MUTE:
      muteSpeech("command");
      break;

    case BRL_CMD_SAY_LINE:
      sayScreenLines(ses->winy, 1, 0, prefs.sayLineMode);
      break;
    case BRL_CMD_SAY_ABOVE:
      sayScreenLines(0, ses->winy+1, 1, sayImmediate);
      break;
    case BRL_CMD_SAY_BELOW:
      sayScreenLines(ses->winy, scr.rows-ses->winy, 1, sayImmediate);
      break;

    case BRL_CMD_SAY_SLOWER:
      if (!canSetSpeechRate()) {
        playTune(&tune_command_rejected);
      } else if (prefs.speechRate > 0) {
        setSpeechRate(--prefs.speechRate, 1);
      } else {
        playTune(&tune_no_change);
      }
      break;

    case BRL_CMD_SAY_FASTER:
      if (!canSetSpeechRate()) {
        playTune(&tune_command_rejected);
      } else if (prefs.speechRate < SPK_RATE_MAXIMUM) {
        setSpeechRate(++prefs.speechRate, 1);
      } else {
        playTune(&tune_no_change);
      }
      break;

    case BRL_CMD_SAY_SOFTER:
      if (!canSetSpeechVolume()) {
        playTune(&tune_command_rejected);
      } else if (prefs.speechVolume > 0) {
        setSpeechVolume(--prefs.speechVolume, 1);
      } else {
        playTune(&tune_no_change);
      }
      break;

    case BRL_CMD_SAY_LOUDER:
      if (!canSetSpeechVolume()) {
        playTune(&tune_command_rejected);
      } else if (prefs.speechVolume < SPK_VOLUME_MAXIMUM) {
        setSpeechVolume(++prefs.speechVolume, 1);
      } else {
        playTune(&tune_no_change);
      }
      break;

    case BRL_CMD_SPEAK_CURR_CHAR:
      speakCurrentCharacter();
      break;

    case BRL_CMD_SPEAK_PREV_CHAR:
      if (ses->spkx > 0) {
        ses->spkx -= 1;
        speakCurrentCharacter();
      } else if (ses->spky > 0) {
        ses->spky -= 1;
        ses->spkx = scr.cols - 1;
        playTune(&tune_wrap_up);
        speakCurrentCharacter();
      } else {
        playTune(&tune_bounce);
      }
      break;

    case BRL_CMD_SPEAK_NEXT_CHAR:
      if (ses->spkx < (scr.cols - 1)) {
        ses->spkx += 1;
        speakCurrentCharacter();
      } else if (ses->spky < (scr.rows - 1)) {
        ses->spky += 1;
        ses->spkx = 0;
        playTune(&tune_wrap_down);
        speakCurrentCharacter();
      } else {
        playTune(&tune_bounce);
      }
      break;

    case BRL_CMD_SPEAK_FRST_CHAR: {
      ScreenCharacter characters[scr.cols];
      int column;

      readScreen(0, ses->spky, scr.cols, 1, characters);
      if ((column = findFirstNonSpaceCharacter(characters, scr.cols)) >= 0) {
        ses->spkx = column;
        speakDone(characters, column, 1, 0);
      } else {
        playTune(&tune_command_rejected);
      }

      break;
    }

    case BRL_CMD_SPEAK_LAST_CHAR: {
      ScreenCharacter characters[scr.cols];
      int column;

      readScreen(0, ses->spky, scr.cols, 1, characters);
      if ((column = findLastNonSpaceCharacter(characters, scr.cols)) >= 0) {
        ses->spkx = column;
        speakDone(characters, column, 1, 0);
      } else {
        playTune(&tune_command_rejected);
      }

      break;
    }

    {
      int direction;
      int spell;

    case BRL_CMD_SPEAK_PREV_WORD:
      direction = -1;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPEAK_NEXT_WORD:
      direction = 1;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPEAK_CURR_WORD:
      direction = 0;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPELL_CURR_WORD:
      direction = 0;
      spell = 1;
      goto speakWord;

    speakWord:
      {
        int row = ses->spky;
        int column = ses->spkx;

        ScreenCharacter characters[scr.cols];
        ScreenCharacterType type;
        int onCurrentWord;

        int from = column;
        int to = from + 1;

      findWord:
        readScreen(0, row, scr.cols, 1, characters);
        type = (row == ses->spky)? getScreenCharacterType(&characters[column]): SCT_SPACE;
        onCurrentWord = type != SCT_SPACE;

        if (direction < 0) {
          while (1) {
            if (column == 0) {
              if ((type != SCT_SPACE) && !onCurrentWord) {
                ses->spkx = from = column;
                ses->spky = row;
                break;
              }

              if (row == 0) goto noWord;
              if (row-- == ses->spky) playTune(&tune_wrap_up);
              column = scr.cols;
              goto findWord;
            }

            {
              ScreenCharacterType newType = getScreenCharacterType(&characters[--column]);

              if (newType != type) {
                if (onCurrentWord) {
                  onCurrentWord = 0;
                } else if (type != SCT_SPACE) {
                  ses->spkx = from = column + 1;
                  ses->spky = row;
                  break;
                }

                if (newType != SCT_SPACE) to = column + 1;
                type = newType;
              }
            }
          }
        } else if (direction > 0) {
          while (1) {
            if (++column == scr.cols) {
              if ((type != SCT_SPACE) && !onCurrentWord) {
                to = column;
                ses->spkx = from;
                ses->spky = row;
                break;
              }

              if (row == (scr.rows - 1)) goto noWord;
              if (row++ == ses->spky) playTune(&tune_wrap_down);
              column = -1;
              goto findWord;
            }

            {
              ScreenCharacterType newType = getScreenCharacterType(&characters[column]);

              if (newType != type) {
                if (onCurrentWord) {
                  onCurrentWord = 0;
                } else if (type != SCT_SPACE) {
                  to = column;
                  ses->spkx = from;
                  ses->spky = row;
                  break;
                }

                if (newType != SCT_SPACE) from = column;
                type = newType;
              }
            }
          }
        } else if (type != SCT_SPACE) {
          while (from > 0) {
            if (getScreenCharacterType(&characters[--from]) != type) {
              from += 1;
              break;
            }
          }

          while (to < scr.cols) {
            if (getScreenCharacterType(&characters[to]) != type) break;
            to += 1;
          }
        }

        speakDone(characters, from, to-from, spell);
        break;
      }

    noWord:
      playTune(&tune_bounce);
      break;
    }

    case BRL_CMD_SPEAK_CURR_LINE:
      speakCurrentLine();
      break;

    {
      int increment;
      int limit;

    case BRL_CMD_SPEAK_PREV_LINE:
      increment = -1;
      limit = 0;
      goto speakLine;

    case BRL_CMD_SPEAK_NEXT_LINE:
      increment = 1;
      limit = scr.rows - 1;
      goto speakLine;

    speakLine:
      if (ses->spky == limit) {
        playTune(&tune_bounce);
      } else {
        if (prefs.skipIdenticalLines) {
          ScreenCharacter original[scr.cols];
          ScreenCharacter current[scr.cols];
          int count = 0;

          readScreen(0, ses->spky, scr.cols, 1, original);

          do {
            readScreen(0, ses->spky+=increment, scr.cols, 1, current);
            if (!isSameRow(original, current, scr.cols, isSameText)) break;

            if (!count) {
              playTune(&tune_skip_first);
            } else if (count < 4) {
              playTune(&tune_skip);
            } else if (!(count % 4)) {
              playTune(&tune_skip_more);
            }

            count += 1;
          } while (ses->spky != limit);
        } else {
          ses->spky += increment;
        }

        speakCurrentLine();
      }

      break;
    }

    case BRL_CMD_SPEAK_FRST_LINE: {
      ScreenCharacter characters[scr.cols];
      int row = 0;

      while (row < scr.rows) {
        readScreen(0, row, scr.cols, 1, characters);
        if (!isAllSpaceCharacters(characters, scr.cols)) break;
        row += 1;
      }

      if (row < scr.rows) {
        ses->spky = row;
        ses->spkx = 0;
        speakCurrentLine();
      } else {
        playTune(&tune_command_rejected);
      }

      break;
    }

    case BRL_CMD_SPEAK_LAST_LINE: {
      ScreenCharacter characters[scr.cols];
      int row = scr.rows - 1;

      while (row >= 0) {
        readScreen(0, row, scr.cols, 1, characters);
        if (!isAllSpaceCharacters(characters, scr.cols)) break;
        row -= 1;
      }

      if (row >= 0) {
        ses->spky = row;
        ses->spkx = 0;
        speakCurrentLine();
      } else {
        playTune(&tune_command_rejected);
      }

      break;
    }

    case BRL_CMD_DESC_CURR_CHAR: {
      char description[0X50];
      formatCharacterDescription(description, sizeof(description), ses->spkx, ses->spky);
      sayString(description, 1);
      break;
    }

    case BRL_CMD_ROUTE_CURR_LOCN:
      if (routeCursor(ses->spkx, ses->spky, scr.number)) {
        playTune(&tune_routing_started);
      } else {
        playTune(&tune_command_rejected);
      }
      break;

    case BRL_CMD_SPEAK_CURR_LOCN: {
      char buffer[0X50];
      snprintf(buffer, sizeof(buffer), "%s %d, %s %d",
               gettext("line"), ses->spky+1,
               gettext("column"), ses->spkx+1);
      sayString(buffer, 1);
      break;
    }

    case BRL_CMD_SHOW_CURR_LOCN:
      toggleFeatureSetting(&prefs.showSpeechCursor, command);
      break;

    default:
      return 0;
  }

  return 1;
}
Example #4
0
static int
handleSpeechCommands (int command, void *data) {
  switch (command & BRL_MSK_CMD) {
    case BRL_CMD_RESTARTSPEECH:
      restartSpeechDriver();
      break;

    case BRL_CMD_SPKHOME:
      if (scr.number == spk.track.screenNumber) {
        trackSpeech();
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }
      break;

    case BRL_CMD_MUTE:
      muteSpeech(&spk, "command");
      break;

    case BRL_CMD_SAY_LINE:
      sayScreenLines(ses->winy, 1, 0, prefs.sayLineMode);
      break;
    case BRL_CMD_SAY_ABOVE:
      sayScreenLines(0, ses->winy+1, 1, sayImmediate);
      break;
    case BRL_CMD_SAY_BELOW:
      sayScreenLines(ses->winy, scr.rows-ses->winy, 1, sayImmediate);
      break;

    case BRL_CMD_SAY_SLOWER:
      if (!canSetSpeechRate(&spk)) {
        alert(ALERT_COMMAND_REJECTED);
      } else if (prefs.speechRate > 0) {
        setSpeechRate(&spk, --prefs.speechRate, 1);
      } else {
        alert(ALERT_NO_CHANGE);
      }
      break;

    case BRL_CMD_SAY_FASTER:
      if (!canSetSpeechRate(&spk)) {
        alert(ALERT_COMMAND_REJECTED);
      } else if (prefs.speechRate < SPK_RATE_MAXIMUM) {
        setSpeechRate(&spk, ++prefs.speechRate, 1);
      } else {
        alert(ALERT_NO_CHANGE);
      }
      break;

    case BRL_CMD_SAY_SOFTER:
      if (!canSetSpeechVolume(&spk)) {
        alert(ALERT_COMMAND_REJECTED);
      } else if (prefs.speechVolume > 0) {
        setSpeechVolume(&spk, --prefs.speechVolume, 1);
      } else {
        alert(ALERT_NO_CHANGE);
      }
      break;

    case BRL_CMD_SAY_LOUDER:
      if (!canSetSpeechVolume(&spk)) {
        alert(ALERT_COMMAND_REJECTED);
      } else if (prefs.speechVolume < SPK_VOLUME_MAXIMUM) {
        setSpeechVolume(&spk, ++prefs.speechVolume, 1);
      } else {
        alert(ALERT_NO_CHANGE);
      }
      break;

    case BRL_CMD_SPEAK_CURR_CHAR:
      speakCurrentCharacter();
      break;

    case BRL_CMD_SPEAK_PREV_CHAR:
      if (ses->spkx > 0) {
        ses->spkx -= 1;
        speakCurrentCharacter();
      } else if (ses->spky > 0) {
        ses->spky -= 1;
        ses->spkx = scr.cols - 1;
        alert(ALERT_WRAP_UP);
        speakCurrentCharacter();
      } else {
        alert(ALERT_BOUNCE);
      }
      break;

    case BRL_CMD_SPEAK_NEXT_CHAR:
      if (ses->spkx < (scr.cols - 1)) {
        ses->spkx += 1;
        speakCurrentCharacter();
      } else if (ses->spky < (scr.rows - 1)) {
        ses->spky += 1;
        ses->spkx = 0;
        alert(ALERT_WRAP_DOWN);
        speakCurrentCharacter();
      } else {
        alert(ALERT_BOUNCE);
      }
      break;

    case BRL_CMD_SPEAK_FRST_CHAR: {
      ScreenCharacter characters[scr.cols];
      int column;

      readScreen(0, ses->spky, scr.cols, 1, characters);
      if ((column = findFirstNonSpaceCharacter(characters, scr.cols)) >= 0) {
        ses->spkx = column;
        speakDone(characters, column, 1, 0);
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }

      break;
    }

    case BRL_CMD_SPEAK_LAST_CHAR: {
      ScreenCharacter characters[scr.cols];
      int column;

      readScreen(0, ses->spky, scr.cols, 1, characters);
      if ((column = findLastNonSpaceCharacter(characters, scr.cols)) >= 0) {
        ses->spkx = column;
        speakDone(characters, column, 1, 0);
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }

      break;
    }

    {
      int direction;
      int spell;

    case BRL_CMD_SPEAK_PREV_WORD:
      direction = -1;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPEAK_NEXT_WORD:
      direction = 1;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPEAK_CURR_WORD:
      direction = 0;
      spell = 0;
      goto speakWord;

    case BRL_CMD_SPELL_CURR_WORD:
      direction = 0;
      spell = 1;
      goto speakWord;

    speakWord:
      {
        int row = ses->spky;
        int column = ses->spkx;

        ScreenCharacter characters[scr.cols];
        ScreenCharacterType type;
        int onCurrentWord;

        int from = column;
        int to = from + 1;

      findWord:
        readScreen(0, row, scr.cols, 1, characters);
        type = (row == ses->spky)? getScreenCharacterType(&characters[column]): SCT_SPACE;
        onCurrentWord = type != SCT_SPACE;

        if (direction < 0) {
          while (1) {
            if (column == 0) {
              if ((type != SCT_SPACE) && !onCurrentWord) {
                ses->spkx = from = column;
                ses->spky = row;
                break;
              }

              if (row == 0) goto noWord;
              if (row-- == ses->spky) alert(ALERT_WRAP_UP);
              column = scr.cols;
              goto findWord;
            }

            {
              ScreenCharacterType newType = getScreenCharacterType(&characters[--column]);

              if (newType != type) {
                if (onCurrentWord) {
                  onCurrentWord = 0;
                } else if (type != SCT_SPACE) {
                  ses->spkx = from = column + 1;
                  ses->spky = row;
                  break;
                }

                if (newType != SCT_SPACE) to = column + 1;
                type = newType;
              }
            }
          }
        } else if (direction > 0) {
          while (1) {
            if (++column == scr.cols) {
              if ((type != SCT_SPACE) && !onCurrentWord) {
                to = column;
                ses->spkx = from;
                ses->spky = row;
                break;
              }

              if (row == (scr.rows - 1)) goto noWord;
              if (row++ == ses->spky) alert(ALERT_WRAP_DOWN);
              column = -1;
              goto findWord;
            }

            {
              ScreenCharacterType newType = getScreenCharacterType(&characters[column]);

              if (newType != type) {
                if (onCurrentWord) {
                  onCurrentWord = 0;
                } else if (type != SCT_SPACE) {
                  to = column;
                  ses->spkx = from;
                  ses->spky = row;
                  break;
                }

                if (newType != SCT_SPACE) from = column;
                type = newType;
              }
            }
          }
        } else if (type != SCT_SPACE) {
          while (from > 0) {
            if (getScreenCharacterType(&characters[--from]) != type) {
              from += 1;
              break;
            }
          }

          while (to < scr.cols) {
            if (getScreenCharacterType(&characters[to]) != type) break;
            to += 1;
          }
        }

        speakDone(characters, from, to-from, spell);
        break;
      }

    noWord:
      alert(ALERT_BOUNCE);
      break;
    }

    case BRL_CMD_SPEAK_CURR_LINE:
      speakCurrentLine();
      break;

    {
      int increment;
      int limit;

    case BRL_CMD_SPEAK_PREV_LINE:
      increment = -1;
      limit = 0;
      goto speakLine;

    case BRL_CMD_SPEAK_NEXT_LINE:
      increment = 1;
      limit = scr.rows - 1;
      goto speakLine;

    speakLine:
      if (ses->spky == limit) {
        alert(ALERT_BOUNCE);
      } else {
        if (prefs.skipIdenticalLines) {
          ScreenCharacter original[scr.cols];
          ScreenCharacter current[scr.cols];
          int count = 0;

          readScreen(0, ses->spky, scr.cols, 1, original);

          do {
            readScreen(0, ses->spky+=increment, scr.cols, 1, current);
            if (!isSameRow(original, current, scr.cols, isSameText)) break;

            if (!count) {
              alert(ALERT_SKIP_FIRST);
            } else if (count < 4) {
              alert(ALERT_SKIP);
            } else if (!(count % 4)) {
              alert(ALERT_SKIP_MORE);
            }

            count += 1;
          } while (ses->spky != limit);
        } else {
          ses->spky += increment;
        }

        speakCurrentLine();
      }

      break;
    }

    case BRL_CMD_SPEAK_FRST_LINE: {
      ScreenCharacter characters[scr.cols];
      int row = 0;

      while (row < scr.rows) {
        readScreen(0, row, scr.cols, 1, characters);
        if (!isAllSpaceCharacters(characters, scr.cols)) break;
        row += 1;
      }

      if (row < scr.rows) {
        ses->spky = row;
        ses->spkx = 0;
        speakCurrentLine();
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }

      break;
    }

    case BRL_CMD_SPEAK_LAST_LINE: {
      ScreenCharacter characters[scr.cols];
      int row = scr.rows - 1;

      while (row >= 0) {
        readScreen(0, row, scr.cols, 1, characters);
        if (!isAllSpaceCharacters(characters, scr.cols)) break;
        row -= 1;
      }

      if (row >= 0) {
        ses->spky = row;
        ses->spkx = 0;
        speakCurrentLine();
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }

      break;
    }

    case BRL_CMD_DESC_CURR_CHAR: {
      char description[0X50];
      formatCharacterDescription(description, sizeof(description), ses->spkx, ses->spky);
      sayString(&spk, description, SAY_OPT_MUTE_FIRST);
      break;
    }

    case BRL_CMD_ROUTE_CURR_LOCN:
      if (routeCursor(ses->spkx, ses->spky, scr.number)) {
        alert(ALERT_ROUTING_STARTED);
      } else {
        alert(ALERT_COMMAND_REJECTED);
      }
      break;

    case BRL_CMD_SPEAK_CURR_LOCN: {
      char buffer[0X50];
      snprintf(buffer, sizeof(buffer), "%s %d, %s %d",
               gettext("line"), ses->spky+1,
               gettext("column"), ses->spkx+1);
      sayString(&spk, buffer, SAY_OPT_MUTE_FIRST);
      break;
    }

    default:
      return 0;
  }

  return 1;
}