📄 adsapiph.pas
字号:
CurrentSection : TStringList;
var CurrentWord : Integer;
var MatchingKey : string) : Boolean;
var
List : TStringList;
i : Integer;
j : Integer;
Optional : Boolean;
RCode : Boolean;
OldCurrentWord : Integer;
begin
OldCurrentWord := CurrentWord;
Result := True;
Optional := False;
{ Tokenize the rule that is being analyzed }
List := TStringList.Create;
try
TokenizePhrase (CurrentRule, List);
i := 0;
while i < List.Count do begin
{ If the token is of the form <stuff> or (stuff), first check to see
if there is a section of that name. If there is then use RecurseRules
to analyze it. If there isn't a section with that name, then see
if there is one or more rules with that name in the current section.
If so, then analyze those rules. }
if (IsAnglePhrase (List[i])) or (IsParenPhrase (List[i])) then begin
if INIFile.SectionExists (List[i]) then begin
RCode := RecurseRules (Tokens, INIFile, List[i], CurrentWord,
MatchingKey);
if (not RCode) and (not Optional) then begin
Result := False;
CurrentWord := OldCurrentWord;
Exit;
end;
end else begin
RCode := False;
for j := 0 to CurrentSection.Count - 1 do
if GetKey (CurrentSection[j]) = List[i] then begin
if AnalyzeRule (Tokens, GetValue (CurrentSection[j]),
INIFile, CurrentSection, CurrentWord,
MatchingKey) then
RCode := True;
end;
if (not RCode) and (not Optional) then begin
Result := False;
CurrentWord := OldCurrentWord;
Exit;
end;
end;
Optional := False;
end else if List[i] = '[opt]' then begin
Optional := True;
end else if List[i] = '[1+]' then begin
end else if List[i] = '[0+]' then begin
Optional := True;
end else if IsQuoted (List[i]) then begin
case FStringHandler of
gshIgnore :
begin
{ do nothing }
end;
gshInsert :
begin
Tokens.Insert(CurrentWord, KillQuotes (List[i]));
Inc (CurrentWord);
end;
gshAutoReplace :
begin
if (i = 0) then begin
Tokens.Insert(0, KillQuotes (List[i]));
Inc (CurrentWord);
end else begin
if (IsAnglePhrase (List[i - 1])) or
(IsParenPhrase (List[i - 1])) or
(CurrentWord = 0) then begin
Tokens.Insert(0, KillQuotes (List[i]));
Inc (CurrentWord);
end else begin
if (i > 1) and (List[i - 2] = '[opt]') then begin
Tokens.Insert(0, KillQuotes (List[i]));
Inc (CurrentWord);
end else
Tokens[CurrentWord - 1] := KillQuotes (List[i]);
end;
end;
end;
end;
end else begin
if CurrentWord < Tokens.Count then begin
if List[i] = Tokens[CurrentWord] then begin
Inc (CurrentWord);
end else if not Optional then
Result := False;
end else if CurrentWord >= Tokens.Count then begin
Exit;
end;
Optional := False;
end;
Inc (i);
end;
finally
List.Free;
end;
end;
function TApdSapiAskForInfo.RecurseRules (Tokens : TStringList;
INIFile : TApdSapiGrammarList;
CurrentSection : string;
var CurrentWord : Integer;
var MatchingKey : string) : Boolean;
{ Recurse Rules loads a new section and then analyzes it }
var
i : Integer;
Value : string;
List : TStringList;
begin
Result := False;
List := TStringList.Create;
try
{ Does the section ask for exists as a section in the grammar }
if INIFile.SectionExists (CurrentSection) then begin
INIFile.ReadSectionValues (CurrentSection, List);
for i := 0 to List.Count - 1 do begin
Value := GetKey (List[i]);
if (Value = '') or (Value = CurrentSection) or
((not IsAnglePhrase (Value)) and
(not IsParenPhrase (Value))) then begin
Value := GetValue (List[i]);
{ Analyze the rule }
if AnalyzeRule (Tokens, Value, INIFile, List, CurrentWord,
MatchingKey) then begin
{ The rule matched. Exit successfully }
if (Value <> '') and
((MatchingKey = '') or (IsAnglePhrase (MatchingKey)) or
(IsParenPhrase (MatchingKey))) then
MatchingKey := GetKey (List[i]);
Result := True;
Exit;
end;
end;
end;
end;
finally
List.Free;
end;
end;
function TApdSapiAskForInfo.LocateRule (Tokens : TStringList) : string;
procedure PreparseGrammar (Grammar : TStringList);
var
i : Integer;
begin
for i := Grammar.Count - 1 downto 0 do begin
Grammar[i] := Trim (Grammar[i]);
if Grammar[i] = '' then
Grammar.Delete(i)
else if (Copy (Grammar[i], 1, 2) = '//') or
(Copy (Grammar[i], 1, 1) = ';') then
Grammar.Delete(i);
end;
end;
var
INIFile : TApdSapiGrammarList;
MatchingKey : string;
FWorkingGrammar : TStringList;
CurrentWord : Integer;
begin
Result := '';
CurrentWord := 0;
MatchingKey := '';
{ Create an INI file that will be used to work with the grammar }
INIFile := TApdSapiGrammarList.Create;
try
{ Create a work grammar and merge all the grammars into it }
FWorkingGrammar := TStringList.Create;
try
FWorkingGrammar.Text := FMainGrammar.Text + ^M^J + FAskForGrammar.Text;
PreparseGrammar (FWorkingGrammar);
INIFile.Assign (FWorkingGrammar);
finally
FWorkingGrammar.Free;
end;
{ Analyze the grammar - start with the <Start> rule }
RecurseRules (Tokens, INIFile, '<Start>', CurrentWord, MatchingKey);
Result := MatchingKey;
finally
INIFile.Free;
end;
end;
function TApdSapiAskForInfo.FindGrammarRule (var Phrase : string) : string;
var
Tokens : TStringList;
i : Integer;
begin
Result := '';
if Phrase = '' then
Exit;
Tokens := TStringList.Create;
try
{ Break the phrase down into its tokens }
TokenizePhrase (Phrase, Tokens);
{ Find the first rule that matches the phrase }
Result := LocateRule (Tokens);
Phrase := '';
for i := 0 to Tokens.Count - 1 do
if i < Tokens.Count - 1 then
Phrase := Phrase + Tokens[i] + ' '
else
Phrase := Phrase + Tokens[i];
finally
Tokens.Free;
end;
end;
procedure TApdSapiAskForInfo.InitializeMainGrammar;
begin
with FMainGrammar do begin
Clear;
Text := ApdDefaultPhoneGrammar;
end;
end;
procedure TApdSapiAskForInfo.SapiPhraseFinishHook (Sender : TObject;
Phrase : string;
Results : Integer);
var
PhraseType : TApdPhraseType;
PhraseRule : string;
StringData : PChar;
begin
PhraseType := DeterminePhraseTypeEx (Phrase, PhraseRule);
case PhraseType of
ptHelp :
FSapiEngine.Speak (Prompts.Help);
ptBack :
begin
if psCanGoBack in Options then begin
FSapiEngine.DeRegisterPhraseFinishHook (SapiPhraseFinishHook);
FSapiEngine.Speak (Prompts.GoingBack);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase, ApdSapiAskBack, 0);
end else
FSapiEngine.Speak (Prompts.CannotGoBack);
end;
ptOperator :
begin
if psEnableOperator in Options then begin
FSapiEngine.DeRegisterPhraseFinishHook (SapiPhraseFinishHook);
FSapiEngine.Speak (Prompts.Operator);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase, ApdSapiAskOperator, 0);
end else
FSapiEngine.Speak (Prompts.NoOperator);
end;
ptHangup :
begin
if psEnableAskHangup in Options then begin
FSapiEngine.DeRegisterPhraseFinishHook (SapiPhraseFinishHook);
FSapiEngine.Speak (Prompts.HangingUp);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase, ApdSapiAskHangup, 0);
end else
FSapiEngine.Speak (Prompts.CannotHangUp);
end;
ptWhere :
begin
FSapiEngine.Speak (Prompts.Where);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase, ApdSapiAskWhere, 0);
end;
ptRepeat :
begin
FSapiEngine.Speak (Prompts.Main2);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase, ApdSapiAskRepeat, 0);
end;
ptSpeakFaster :
begin
if psDisableSpeedChange in Options then begin
FSapiEngine.Speak (Prompts.NoSpeedChange);
end else begin
if FSapiEngine.DirectSS.Speed < FSapiEngine.DirectSS.MaxSpeed -
ApdSapiSpeedChange then begin
FSapiEngine.DirectSS.Speed := FSapiEngine.DirectSS.Speed +
ApdSapiSpeedChange;
FSapiEngine.Speak (Prompts.SpeakingFaster);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase,
ApdSapiAskSpeakFaster, 0);
end else
FSapiEngine.Speak (Prompts.MaxSpeed);
end;
end;
ptSpeakSlower :
begin
if psDisableSpeedChange in Options then begin
FSapiEngine.Speak (Prompts.NoSpeedChange);
end else begin
if FSapiEngine.DirectSS.Speed > FSapiEngine.DirectSS.MinSpeed +
ApdSapiSpeedChange then begin
FSapiEngine.DirectSS.Speed := FSapiEngine.DirectSS.Speed -
ApdSapiSpeedChange;
FSapiEngine.Speak (Prompts.SpeakingSlower);
if ReplyHandle <> 0 then
PostMessage (ReplyHandle, apw_SapiInfoPhrase,
ApdSapiAskSpeakSlower, 0);
end else
FSapiEngine.Speak (Prompts.MinSpeed);
end;
end;
ptNone :
begin
end;
ptUnknown :
begin
{ Parse unrecognized grammar rules here }
try
if ReplyHandle <> 0 then begin
StringData := StrAlloc (Length (Phrase) + 1);
StrPCopy (StringData, Phrase);
PostMessage (ReplyHandle, apw_SapiInfoPhrase,
StrToInt (PhraseRule), LongInt (StringData));
end;
except
on EConvertError do
FSapiEngine.Speak (Prompts.Unrecognized);
end;
end;
end;
end;
procedure TApdSapiAskForInfo.SetAskForGrammar (v : TStringList);
begin
FAskForGrammar.Assign (v);
end;
procedure TApdSapiAskForInfo.SetMainGrammar (v : TStringList);
begin
FMainGrammar.Assign (v);
end;
procedure TApdSapiAskForInfo.SetOptions (v : TApdSapiPhoneSettings);
begin
if v <> FOptions then
FOptions := v;
end;
procedure TApdSapiAskForInfo.SetReplyHandle (v : THandle);
begin
if v <> FReplyHandle then
FReplyHandle := v;
end;
{ TApdCustomSapiPhone }
constructor TApdCustomSapiPhone.Create (AOwner : TComponent);
begin
inherited Create (AOwner);
FSpellingEchoBack := True;
FInfo := TApdSapiAskForInfo.Create;
FPrompts := TApdSapiPhonePrompts.Create;
FList := TStringList.Create;
FSapiEngine := SearchSapiEngine (Owner);
end;
destructor TApdCustomSapiPhone.Destroy;
begin
AbortAskFor;
CancelCall;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -