从 https://github.com/PierceNg/fpwebview 下载 fpwebview-master.zip 简单易用。
先请看 \fpwebview-master\README.md
cd \lazarus\projects\fpwebview-master\demo\js_bidir
学习 js_bidir.lpr ,编写 js_bind_speak.lpr 如下,通过JSBridge调用本机TTS。
program js_bind_speak;
{$linklib libwebview}
{$mode objfpc}{$H+}
uses
{$ifdef unix}cthreads,{$endif}
Classes,Process,SysUtils,StrUtils,
Variants,ComObj, math,
webview;
var
w: PWebView;
sapi: Variant;
url: String;
txt: String;
procedure speak(const seq: PAnsiChar; const req: PAnsiChar; arg: Pointer); cdecl;
var
s: String;
begin
if req <> nil then
begin
s := strPas(req);
writeln('speak:'+s);
try
sapi.Speak(s);
Sleep(1000)
except
writeln(' OLE Error ')
end;
end
else
writeln(' req is nil');
//webview_return(w, seq, WebView_Return_Ok, '{result: "?"}');
end;
begin
if Assigned(InitProc) then
TProcedure(InitProc);
{ Set math masks. libwebview throws at least one of these from somewhere deep inside. }
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
try
sapi := CreateOleObject('SAPI.SpVoice')
except
writeln(' OLE Error ')
end;
url := 'http://localhost/';
if ParamCount =1 then
begin
if Length(ParamStr(1))<6 then
url := 'http://localhost:' + ParamStr(1)
else
begin
if AnsiStartsStr('http', ParamStr(1)) then url := ParamStr(1)
else if AnsiStartsStr('192.', ParamStr(1)) then url := 'http://' + ParamStr(1)
else url := 'https://' + ParamStr(1);
end;
end
else
url := ParamStr(1);
writeln(url);
w := webview_create(WebView_DevTools, nil);
webview_set_size(w, 1024, 768, WebView_Hint_None);
webview_set_title(w, PAnsiChar('WebView - Pascal Javascript Bridge'));
webview_bind(w, PAnsiChar('sapi_speak'), @speak, PAnsiChar(txt));
webview_navigate(w, PAnsiChar(url));
webview_run(w);
webview_destroy(w);
end.
注意这一句:webview_bind(w, PAnsiChar('sapi_speak'), @speak, PAnsiChar(txt));
编写 编译批命令:winbuild.bat 如下
@echo off
echo Set up FPC executable path.
set fpcexe=D:\lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.exe
if not exist "%fpcexe%" (
echo ERROR: Edit this batch file to set up location of fpc.exe
exit /b 1
)
echo "%fpcexe%"
echo Building...
copy "..\..\dll\x86_64\libwebview.a" .
copy "..\..\dll\x86_64\webview.dll" .
copy "..\..\dll\x86_64\WebView2Loader.dll" .
"%fpcexe%" -Fu..\..\src -Fl. js_bind_speak.lpr
编写 运行批命令:winrun.bat 如下
@echo off
@echo js_bind_speak.exe
js_bind_speak.exe %1
前端 js 代码:index6.html 如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>查询英汉词典</title>
<script src="jquery-3.2.1.min.js"></script>
<style>
/* portrait 判断为竖屏 */
@media only screen and (orientation: portrait){
#lab1 {display:none;}
}
/* landscape 判断为横屏 */
@media only screen and (orientation: landscape){
#lab1 {display: ;}
}
</style>
</head>
<body>
<form name="form" id="form" action="trans" method="POST" target="iframe">
<label id="lab1">请输入:</label>
<input type="text" name="txt" id='txt' size="30" placeholder="请输入 a word">
<input type="submit" name="eng_han" value="英译汉">
<input type="button" name="btn1" id="btn1" value="前缀查询">
<input type="button" name="btn2" id="btn2" value="TTS读音" onclick="tts2()">
</form>
<p></p>
<div style="float:left; width:100%;">
<div id="result" style="float:left; width:80%; height:400; border:2px;">
<iframe name="iframe" id="iframe" width="100%" height="400"> </iframe>
</div>
<div id="alist" style="float:right; width:20%; height:400; border:2px;">
</div>
</div>
<script type="text/javascript">
$(function(){
$("#btn1").click(function(){
$.getJSON("/prefix?txt="+$("#txt").val(), function(data){
$('#alist').empty();
var items = [];
$.each(data, function(i, item){
if (i<=20){
items[i] = '<a href="/trans?txt=' +item+ '" target="iframe">' +item+ "</a><br>";
}
});
var a = items.join('\n');
if (a) $('#alist').html(a);
})
})
});
//定义对象 customHost,方便js函数调用
//var hostObj = window.chrome.webview.hostObjects.customHost;
// pascal TTS
function tts() {
var txt = document.getElementById('txt').value;
if (txt.length >1) {
(async ()=>{
await sapi_speak(txt);
})();
}
}
// 屏幕双击取词, pascal TTS
function tts2() {
// 获取iframe里的选择内容
var select = window.frames['iframe'].getSelection();
var txt = select.toString();
txt = txt.trim();
if (txt.length >1) { // alert(txt);
(async ()=>{
await sapi_speak(txt);
})();
} else {
tts();
}
}
// 页面加载添加:监听iframe网页点击事件
$(document).ready(function(){
var listener = window.addEventListener('blur', function(){
if (document.activeElement === document.getElementById('iframe')){
$('iframe').contents().find('a.fayin').click(function(event){
event.preventDefault();
var a = $(this);
if (a){
var addr = a.attr('href');
if (addr.indexOf('sound://')==0){
var url = "/data" + addr.substring(7);
var mp3 = new Audio(url);
mp3.addEventListener("canplaythrough", (event)=> {
mp3.play();
});
} else {
alert('href='+addr);
}
}
})
}
});
});
</script>
</body>
</html>
web 服务程序请参考:python:mdict + bottle = web 查询英汉词典
记得修改一句:def server_static(filepath="index6.html"):
先运行 web 服务程序:python mdict_bottle.py
再执行编译:winbuild.bat
最后运行:winrun.bat 8086
访问 http://localhost:8086/