diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f2cb90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.build/default.main.aardio +.build/default.Manifest.xml +dist/ \ No newline at end of file diff --git a/README.md b/README.md index bbcdb69..e7dd2ff 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # wubi-lex-tool -Win10自带的微软五笔码表安装、管理工具。 -不需要重启操作系统就可以切换词库,例如在五笔86、五笔98词库间自由切换。 -支持导入、导出、安装二进制格式、文本格式的码表,支持字根反查。 +Win10自带的微软五笔码表安装、管理工具。 +支持导入、导出、安装二进制格式、文本格式的码表, 不需要重启操作系统就可以切换词库。 +可在五笔86、五笔98词库间自由切换,可自动识别并显示系统码表是五笔96、98、还是新世纪。 +支持字根反查,可显示五笔98版字根拆分图示(不仅支持单字,也可以支持词组)。 +支持直接编辑五笔短语词库(实时生效,不需要点击很多步骤到设置面板去导入)。 -![Screenshot](https://raw.githubusercontent.com/aardio/wubi-lex-tool/master/screenshots/1.png) -![Screenshot](https://raw.githubusercontent.com/aardio/wubi-lex-tool/master/screenshots/2.png) \ No newline at end of file +![Screenshot](http://ide.update.aardio.com/log/wubilex1.png) + +![Screenshot](http://ide.update.aardio.com/log/wubilex2.png) \ No newline at end of file diff --git a/app.ico b/app.ico index 35f36bb..83a9d88 100644 Binary files a/app.ico and b/app.ico differ diff --git a/default.aproj b/default.aproj index 0924d7d..80e07a2 100644 --- a/default.aproj +++ b/default.aproj @@ -1,7 +1,7 @@  - + - + @@ -9,5 +9,6 @@ + diff --git a/dlg/help.aardio b/dlg/help.aardio index 9b334b4..7ff6ecd 100644 --- a/dlg/help.aardio +++ b/dlg/help.aardio @@ -26,23 +26,23 @@ winform.keyboardShortcuts.text = /* */ winform.lnkGitHub.skin( - color = { - hover = 0xFFFF0000; - active = 0xFF00FF00; - } - border = { - hover = {bottom=1;color=0xFFFF0000} - } + color = { + hover = 0xFFFF0000; + active = 0xFF00FF00; + } + border = { + hover = {bottom=1;color=0xFFFF0000} + } ) winform.lnkWebSite.skin( - color = { - hover = 0xFFFF0000; - active = 0xFF00FF00; - } - border = { - hover = {bottom=1;color=0xFFFF0000} - } + color = { + hover = 0xFFFF0000; + active = 0xFF00FF00; + } + border = { + hover = {bottom=1;color=0xFFFF0000} + } ) import process; diff --git a/dlg/lex.aardio b/dlg/lex.aardio index 7df951f..1b24461 100644 --- a/dlg/lex.aardio +++ b/dlg/lex.aardio @@ -1,12 +1,12 @@ - +//RUNAS// import fonts.fontAwesome; import win.ui; /*DSG{{*/ var winform = win.form(text="五笔码表管理工具";right=1040;bottom=600;bgcolor=16777215) winform.add( bkplus={cls="bkplus";left=0;top=304;right=1041;bottom=600;bgcolor=16777215;db=1;dl=1;dr=1;forecolor=15780518;linearGradient=90;z=3}; -btnAddFile={cls="plus";text='\uF271 添加码表文件';left=26;top=17;right=187;bottom=53;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=1}; -btnCopyToSystem={cls="plus";text='\uF0C7 安装到系统词库';left=196;top=17;right=389;bottom=53;disabled=1;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=2}; +btnAddFile={cls="plus";text='\uF271 添加码表文件';left=26;top=17;right=187;bottom=53;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;tabstop=1;z=1}; +btnCopyToSystem={cls="plus";text='\uF0C7 安装到系统词库';left=196;top=17;right=389;bottom=53;disabled=1;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');tabstop=1;z=2}; lbTip={cls="plus";left=465;top=27;right=1009;bottom=61;color=2960685;font=LOGFONT(h=-16;name='FontAwesome');z=6}; listbox={cls="listbox";left=28;top=79;right=398;bottom=594;db=1;dl=1;dt=1;edge=1;font=LOGFONT(h=-16);items={};vscroll=1;z=4}; richedit={cls="richedit";left=404;top=79;right=1012;bottom=579;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-19);hscroll=1;multiline=1;vscroll=1;z=5} @@ -20,304 +20,304 @@ import win.inputBox; import config; winform.btnAddFile.oncommand = function(id,event){ - var inputPath = fsys.dlg.open("二进制码表(*.lex);文本码表(*.txt)|*.lex;*.txt||",,,winform) - if(!inputPath){ - return; - } - - var lexName; - while(true){ - var inputBox = win.inputBox(winform) - inputBox.text = "五笔码表管理工具" - inputBox.info.text = "请为码表指定一个友好名称" - - lexName = inputBox.doModal() - if(!#lexName){ - return; - } - - if(!fsys.path.validName(lexName)){ - winform.msgboxErr(`名称不能包含空格、回车、换行、以及 / : * ? " < > ] 等字符`) - continue ; - } - - if(config.lex.files[lexName]){ - winform.msgboxErr(`此名称已经存在,请重新指定`) - continue ; - } - - break ; - } - - var lexPath = fsys.appdata("/aardio/std/wubi-lex-files/"+lexName+".lex"); - io.createDir(fsys.appdata("/aardio/std/wubi-lex-files/")) + var inputPath = fsys.dlg.open("二进制码表(*.lex);文本码表(*.txt)|*.lex;*.txt||",,,winform) + if(!inputPath){ + return; + } + + var lexName; + while(true){ + var inputBox = win.inputBox(winform) + inputBox.text = "五笔码表管理工具" + inputBox.info.text = "请为码表指定一个友好名称" + + lexName = inputBox.doModal() + if(!#lexName){ + return; + } + + if(!fsys.path.validName(lexName)){ + winform.msgboxErr(`名称不能包含空格、回车、换行、以及 / : * ? " < > ] 等字符`) + continue ; + } + + if(config.lex.files[lexName]){ + winform.msgboxErr(`此名称已经存在,请重新指定`) + continue ; + } + + break ; + } + + var lexPath = fsys.appdata("/aardio/std/wubi-lex-files/"+lexName+".lex"); + io.createDir(fsys.appdata("/aardio/std/wubi-lex-files/")) - if(string.endWith(inputPath,".txt",true)){ - var wubiLex = fsys.wubiLex(inputPath) - if(!wubiLex){ - winform.msgboxErr(`错误的码表文件`) - return; - } - wubiLex.saveLex(lexPath) - } - else { - var file = ..io.open(inputPath,"rb"); - if(!file){ - winform.msgboxErr(`错误的码表文件`) - return; - } - - if( file.read(#"imscwubi")!=="imscwubi"){ - winform.msgboxErr(`错误的码表文件`) - return; - } - - file.close() - - fsys.copy(inputPath,lexPath); - } - + if(string.endWith(inputPath,".txt",true)){ + var wubiLex = fsys.wubiLex(inputPath) + if(!wubiLex){ + winform.msgboxErr(`错误的码表文件`) + return; + } + wubiLex.saveLex(lexPath) + } + else { + var file = ..io.open(inputPath,"rb"); + if(!file){ + winform.msgboxErr(`错误的码表文件`) + return; + } + + if( file.read(#"imscwubi")!=="imscwubi"){ + winform.msgboxErr(`错误的码表文件`) + return; + } + + file.close() + + fsys.copy(inputPath,lexPath); + } + - config.lex.files[lexName] = lexPath; - table.push(config.lex.names,lexName); - config.saveAll(); - - winform.listbox.reloadLexList(); + config.lex.files[lexName] = lexPath; + table.push(config.lex.names,lexName); + config.saveAll(); + + winform.listbox.reloadLexList(); } if(!#config.lex.names){ - var path98 = fsys.appdata("/aardio/std/wubi-lex-files/五笔98.lex",string.load("\res\ChsWubi98.lex")) - var path86 = fsys.appdata("/aardio/std/wubi-lex-files/五笔86.lex",string.load("\res\ChsWubi86.lex")) - - config.lex.files["五笔98"] = path98; - table.push(config.lex.names,"五笔98"); - - config.lex.files["五笔86"] = path86; - table.push(config.lex.names,"五笔86"); - - config.saveAll(); + var path98 = fsys.appdata("/aardio/std/wubi-lex-files/五笔98.lex",string.load("\res\ChsWubi98.lex")) + var path86 = fsys.appdata("/aardio/std/wubi-lex-files/五笔86.lex",string.load("\res\ChsWubi86.lex")) + + config.lex.files["五笔98"] = path98; + table.push(config.lex.names,"五笔98"); + + config.lex.files["五笔86"] = path86; + table.push(config.lex.names,"五笔86"); + + config.saveAll(); } winform.listbox.oncommand = function(id,event){ - if( event == 0x1/*_LBN_SELCHANGE*/ ){ - winform.btnCopyToSystem.disabled = winform.listbox.selIndex<=1 - winform.lbTip.text = ""; - } + if( event == 0x1/*_LBN_SELCHANGE*/ ){ + winform.btnCopyToSystem.disabled = winform.listbox.selIndex<=1 + winform.lbTip.text = ""; + } } winform.listbox.wndproc = function(hwnd,message,wParam,lParam){ - select( message ) { - case 0x205/*_WM_RBUTTONUP*/{ - winform.lbTip.text = ""; - var x,y = win.getMessagePos(); - var item = winform.listbox.hitTest(x,y,true); - if( item ){ - winform.listbox.selIndex = item; - - winform.popmenu = win.ui.popmenu(winform); - if(item>1){ - winform.popmenu.add('删除',function(id){ - var selIndex = winform.listbox.selIndex; - winform.listbox.delete(selIndex) - - var lexName = config.lex.names[selIndex-1]; - if(lexName){ - var lexPath = config.lex.files[lexName]; - if(lexPath){ - io.remove(lexPath) - config.lex.files[lexName] = null; - } - table.remove(config.lex.names,selIndex-1) - } - } ) - - winform.popmenu.add('安装到系统词库',function(id){ - winform.btnCopyToSystem.oncommand(); - } ) - } - - winform.popmenu.add('导出文本格式词库',function(id){ - import process; - var outputPath = fsys.dlg.save("文本码表(*.txt)|*.txt||",,,winform) - if(!outputPath){ - return; - } - - winform.lbTip.text = "正在导出数据" - - if(item>1){ - var lexName = config.lex.names[winform.listbox.selIndex-1]; - if(lexName){ - var lexPath = config.lex.files[lexName]; - var wubiLex = fsys.wubiLex(lexPath) - - wubiLex.saveTxt(outputPath) - } - } - else { - var wubiLex = fsys.wubiLex() - wubiLex.saveTxt(outputPath) - } - - winform.lbTip.disabledText = null; - winform.lbTip.text = "已完成" - } ) + select( message ) { + case 0x205/*_WM_RBUTTONUP*/{ + winform.lbTip.text = ""; + var x,y = win.getMessagePos(); + var item = winform.listbox.hitTest(x,y,true); + if( item ){ + winform.listbox.selIndex = item; + + winform.popmenu = win.ui.popmenu(winform); + if(item>1){ + winform.popmenu.add('删除',function(id){ + var selIndex = winform.listbox.selIndex; + winform.listbox.delete(selIndex) + + var lexName = config.lex.names[selIndex-1]; + if(lexName){ + var lexPath = config.lex.files[lexName]; + if(lexPath){ + io.remove(lexPath) + config.lex.files[lexName] = null; + } + table.remove(config.lex.names,selIndex-1) + } + } ) + + winform.popmenu.add('安装到系统词库',function(id){ + winform.btnCopyToSystem.oncommand(); + } ) + } + + winform.popmenu.add('导出文本格式词库',function(id){ + import process; + var outputPath = fsys.dlg.save("文本码表(*.txt)|*.txt||",,,winform) + if(!outputPath){ + return; + } + + winform.lbTip.text = "正在导出数据" + + if(item>1){ + var lexName = config.lex.names[winform.listbox.selIndex-1]; + if(lexName){ + var lexPath = config.lex.files[lexName]; + var wubiLex = fsys.wubiLex(lexPath) + + wubiLex.saveTxt(outputPath) + } + } + else { + var wubiLex = fsys.wubiLex() + wubiLex.saveTxt(outputPath) + } + + winform.lbTip.disabledText = null; + winform.lbTip.text = "已完成" + } ) - winform.popmenu.add('浏览字库文件',function(id){ - import process; - if(item>1){ - var lexName = config.lex.names[winform.listbox.selIndex-1]; - if(lexName){ - var lexPath = config.lex.files[lexName]; - process.exploreSelect(lexPath) - } - } - else { - process.exploreSelect(fsys.wubiLex.path()) - } - } ) - winform.popmenu.popup(x,y,true) - } - } - } + winform.popmenu.add('浏览字库文件',function(id){ + import process; + if(item>1){ + var lexName = config.lex.names[winform.listbox.selIndex-1]; + if(lexName){ + var lexPath = config.lex.files[lexName]; + process.exploreSelect(lexPath) + } + } + else { + process.exploreSelect(fsys.wubiLex.path()) + } + } ) + winform.popmenu.popup(x,y,true) + } + } + } } winform.btnCopyToSystem.oncommand = function(id,event){ - var selIndex = winform.listbox.selIndex; - var lexName = config.lex.names[selIndex-1]; - if(lexName){ - var srcPath = config.lex.files[lexName]; - - winform.btnCopyToSystem.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} - var ok,err = win.invoke(copyToSystem,srcPath) - publish("wubi.system.lex.changed"); - - winform.lbTip.text = ok?'安装成功,如果不能输入,请按 \uF17A + 空格键切换一次输入法': string.concat( "安装失败:",err); - - import key; - key.combine("WIN","SPACE") - win.delay(500) - key.combine("WIN","SPACE") - - winform.btnCopyToSystem.disabledText = null; - } + var selIndex = winform.listbox.selIndex; + var lexName = config.lex.names[selIndex-1]; + if(lexName){ + var srcPath = config.lex.files[lexName]; + + winform.btnCopyToSystem.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + var ok,err = win.invoke(copyToSystem,srcPath) + publish("wubi.system.lex.changed"); + + winform.lbTip.text = ok?'安装成功,如果不能输入,请按 \uF17A + 空格键切换一次输入法': string.concat( "安装失败:",err); + + import key; + key.combine("WIN","SPACE") + win.delay(500) + key.combine("WIN","SPACE") + + winform.btnCopyToSystem.disabledText = null; + } } copyToSystem = function(srcPath){ import fsys; import service; - import process; - - var aclGrant = function(filePath,proc){ - import process.popen; - if(!..io.exist(filePath) ){ return proc() } - - var tempAclDir = io.tmpname(); - var tempAclPath = io.joinpath(tempAclDir,"acl.dat") - var ok,out,err = process.popen(,"takeown","/f",filePath).waitOne() - if(!ok) return false,err; - - var ok,out,err = process.popen(,"icacls",filePath,"/save",tempAclPath).wait() - if(!ok) return false,err; - - var ok,out,err = process.popen(,"icacls",filePath,"/grant","Administrators:(F)").wait() - if(!ok) return false,err; - - var ret = proc(filePath); - - var ok,out,err = process.popen(,"icacls",filePath,"/setowner","NT SERVICE\TrustedInstaller").wait() - if(!ok) return false,err; - - var ok,out,err = process.popen(,"icacls",filePath,"/restore",tempAclPath).wait() - if(!ok) return false,err; - - io.remove(tempAclPath); - io.remove(tempAclDir); - - return ret; - } - - return aclGrant(..fsys.getWinDir("\InputMethod\CHS\ChsWubiNew.lex"), - function(chsWubiNewPath){ - return aclGrant(..fsys.getWinDir("\InputMethod\CHS\ChsWubi.lex"), - function(chsWubiPath){ - var srvMgr = service.manager(); - srvMgr.startDisabled("TabletInputService"); - srvMgr.stop("TabletInputService") - - for(i=1;10;1){ - process.kill("ctfmom.exe") - process.kill("ChsIME.exe") - if(chsWubiNewPath)fsys.delete(chsWubiNewPath ) - if(chsWubiPath)fsys.delete(chsWubiPath ) - if((!io.exist(chsWubiNewPath)) && (!io.exist(chsWubiPath)) ){ break; } - sleep(1000) - } - - var lexData = string.load(srcPath); - if(chsWubiNewPath){ string.save(chsWubiNewPath,lexData); } - if(chsWubiPath){ string.save(chsWubiPath,lexData); } - - srvMgr.startManual("TabletInputService"); - srvMgr.start("TabletInputService"); - process("C:\Windows\System32\InputMethod\CHS\ChsIME.exe"); - - return true; - } - ); - } - ); + import process; + + var aclGrant = function(filePath,proc){ + import process.popen; + if(!..io.exist(filePath) ){ return proc() } + + var tempAclDir = io.tmpname(); + var tempAclPath = io.joinpath(tempAclDir,"acl.dat") + var ok,out,err = process.popen(,"takeown","/f",filePath).waitOne() + if(!ok) return false,err; + + var ok,out,err = process.popen(,"icacls",filePath,"/save",tempAclPath).wait() + if(!ok) return false,err; + + var ok,out,err = process.popen(,"icacls",filePath,"/grant","Administrators:(F)").wait() + if(!ok) return false,err; + + var ret = proc(filePath); + + var ok,out,err = process.popen(,"icacls",filePath,"/setowner","NT SERVICE\TrustedInstaller").wait() + if(!ok) return false,err; + + var ok,out,err = process.popen(,"icacls",filePath,"/restore",tempAclPath).wait() + if(!ok) return false,err; + + io.remove(tempAclPath); + io.remove(tempAclDir); + + return ret; + } + + return aclGrant(..fsys.getWinDir("\InputMethod\CHS\ChsWubiNew.lex"), + function(chsWubiNewPath){ + return aclGrant(..fsys.getWinDir("\InputMethod\CHS\ChsWubi.lex"), + function(chsWubiPath){ + var srvMgr = service.manager(); + srvMgr.startDisabled("TabletInputService"); + srvMgr.stop("TabletInputService") + + for(i=1;10;1){ + process.kill("ctfmom.exe") + process.kill("ChsIME.exe") + if(chsWubiNewPath)fsys.delete(chsWubiNewPath ) + if(chsWubiPath)fsys.delete(chsWubiPath ) + if((!io.exist(chsWubiNewPath)) && (!io.exist(chsWubiPath)) ){ break; } + sleep(1000) + } + + var lexData = string.load(srcPath); + if(chsWubiNewPath){ string.save(chsWubiNewPath,lexData); } + if(chsWubiPath){ string.save(chsWubiPath,lexData); } + + srvMgr.startManual("TabletInputService"); + srvMgr.start("TabletInputService"); + process(fsys.getWinDir("\System32\InputMethod\CHS\ChsIME.exe")); + + return true; + } + ); + } + ); } winform.btnAddFile.skin({ - background={ - default=0xFF8FB2B0; - hover=0xFF928BB3; - disabled=0xFFCCCCCC; - } + background={ + default=0xFF8FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } }) winform.btnCopyToSystem.skin({ - background={ - default=0xFF8FB2B0; - hover=0xFF928BB3; - disabled=0xFFCCCCCC; - } + background={ + default=0xFF8FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } }) winform.listbox.systemLexName = "系统码表"; winform.listbox.reloadLexList = function(){ - winform.listbox.clear(); - - winform.listbox.add(winform.listbox.systemLexName) - var lexNames = config.lex.names; - for(i=1;#lexNames;1){ - winform.listbox.add(lexNames[i]) - } + winform.listbox.clear(); + + winform.listbox.add(winform.listbox.systemLexName) + var lexNames = config.lex.names; + for(i=1;#lexNames;1){ + winform.listbox.add(lexNames[i]) + } } winform.listbox.reloadLexList() import win.debounce; var updateSystemLexVersion = function(){ winform.listbox.updateSystemLexVersion = function(ver){ - winform.listbox.systemLexName = "系统码表( " + ver + " )" - winform.listbox.reloadLexList(); + winform.listbox.systemLexName = "系统码表( " + ver + " )" + winform.listbox.reloadLexList(); } - thread.invoke( - function(winform){ - import fsys.wubiLex; - var wubiLex = fsys.wubiLex() - var ver = wubiLex.getVersion(); - ver = ({["98"]="98版";["86"]="86版";["06"]="新世纪版"})[ver]; - winform.listbox.updateSystemLexVersion(ver) - },winform - ) + thread.invoke( + function(winform){ + import fsys.wubiLex; + var wubiLex = fsys.wubiLex() + var ver = wubiLex.getVersion(); + ver = ({["98"]="98版";["86"]="86版";["06"]="新世纪版"})[ver]; + winform.listbox.updateSystemLexVersion(ver) + },winform + ) } updateSystemLexVersion(); subscribe("wubi.system.lex.changed",function(...){ - updateSystemLexVersion() + updateSystemLexVersion() } ) winform.show() diff --git a/dlg/phrase.aardio b/dlg/phrase.aardio new file mode 100644 index 0000000..5807c43 --- /dev/null +++ b/dlg/phrase.aardio @@ -0,0 +1,233 @@ +//RUNAS// +import fonts.fontAwesome; +import win.ui; +/*DSG{{*/ +var winform = win.form(text="五笔短语词库";right=938;bottom=597;acceptfiles=1;bgcolor=16777215) +winform.add( +btnLoad={cls="plus";text='\uF093 读取系统短语词库';left=507;top=548;right=704;bottom=584;db=1;dr=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;tabstop=1;z=3}; +btnSave={cls="plus";text='\uF019 更新短语词库到系统';left=707;top=548;right=909;bottom=584;db=1;dr=1;font=LOGFONT(h=-16;name='FontAwesome');notify=1;tabstop=1;z=4}; +edit={cls="edit";left=18;top=55;right=925;bottom=541;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-13);hscroll=1;multiline=1;vscroll=1;z=2}; +lbTip={cls="static";text="每行由3个部分组成,用于表示一个短语配置: +第一部分为小写字母组合表示按键,第二部分为不含空格的输出文本,第三部分为候选词排序位置(可省略)";left=20;top=10;right=897;bottom=67;font=LOGFONT(h=-13);transparent=1;z=1} +) +/*}}*/ + +var loadPhrases = function(wubiUdpPath,winform){ + import fsys; + var file = io.open(wubiUdpPath,"rb"); + + if(!file){ + winform.edit.text = "不支持当前版本的短语词库格式" + winform.btnLoad.disabledText = null; + return; + } + + if(!file.size()){ + winform.edit.text = "系统短语词库内容为空" + winform.btnLoad.disabledText = null; + file.close(); + return; + } + + if(file.read(8)!="mschxudp"){ + winform.edit.text = "不支持当前版本的短语词库格式" + winform.btnLoad.disabledText = null; + file.close(); + return; + } + + var header = file.read({ + int magic=0x00600002; + int version; + int phraseOffsetStart; + int phraseStart; + int phraseEnd; + int count; + int timestamp; + BYTE reserved[28]; + }) + + file.seek("set",header.phraseOffsetStart) + if(!header.count){ + winform.edit.text = "系统短语词库内容为空" + file.close() + winform.btnLoad.disabledText = null; + return; + } + + var phraseOffsets = file.read({int array[]={length=header.count}}).array; + table.push(phraseOffsets, header.phraseEnd - header.phraseStart); + + reduce(phraseOffsets,function(prevOffset,nextOffset){ + + var phrase = file.read({ + word cbSize = 16; + word cbSize2 = 16; + word offset; + byte candidate; + byte unknown = 6; + LONG reserved; + }) + + if(phrase.cbSize!==16){ + winform.edit.text = "不支持当前版本的短语词库格式" + file.close(); + return; + } + + var code = file.readUnicode( (phrase.offset-phrase.cbSize) / 2) + var text = file.readUnicode((nextOffset- prevOffset - phrase.offset)/2); + + winform.edit.print(code,text,phrase.candidate); + return nextOffset; + }) + + file.close(); + winform.btnLoad.disabledText = null; +} + +var savePhrases = function(phraseText,winform){ + import fsys; + var wubiUdpPath = fsys.getSpecial(0x1a /*_CSIDL_APPDATA*/,"\Microsoft\InputMethod\Chs\ChsWubiEUDPv2.lex") + + var updatePhraseFile = function(){ + var file = io.open(wubiUdpPath,"w+b"); + if(!file){ + winform.msgboxErr("写入系统短语词库失败") + return; + } + + var phraseArray = {} + var lineIndex = 0; + for line in string.lines(phraseText) { + lineIndex++; + if(!#line){continue;} + + var phrase = string.splitEx(line,"\s+"); + if(#phrase<2){ + winform.msgboxErr( "第" + lineIndex + '行格式错误' ) + file.close(); + return; + } + + table.push(phraseArray,phrase); + } + + var phraseStart = 64+4*#phraseArray; + file.write({ + BYTE proto[8] = "mschxudp"; + int magic=0x00600002; + int version=1; + int phraseOffsetStart=64; + int phraseStart=64+4*#phraseArray; + int phraseEnd; + int count=#phraseArray; + int timestamp=tonumber(..time()); + BYTE reserved[28]; + }) + + file.seek("cur", 4*#phraseArray) + var phraseOffsets = {} + + for(i=1;#phraseArray;1){ + table.push(phraseOffsets,file.seek()-phraseStart); + + var phrase = phraseArray[i]; + file.write({ + word cbSize = 16; + word cbSize2 = 16; + word offset = 16 + (#phrase[1]+1)*2; + byte candidate = phrase[3] ? tonumber(phrase[3]) : 1; + byte unknown = 6; + LONG reserved = 0; + }) + + file.write(..string.toUnicode(phrase[1])) + file.write('\0\0') + file.write(..string.toUnicode(phrase[2])) + file.write('\0\0') + } + + file.seek("set",64) + if(#phraseOffsets)file.write({int offsets[]=phraseOffsets}) + + file.seek("set",24) + file.write({int size=file.size()}) + + file.close(); + } + + import service; + import process; + + var srvMgr = service.manager(); + srvMgr.startDisabled("TabletInputService"); + srvMgr.stop("TabletInputService") + + for(i=1;10;1){ + process.kill("ctfmom.exe") + process.kill("ChsIME.exe") + + fsys.delete(wubiUdpPath) + if(!io.exist(wubiUdpPath)){ break; } + sleep(1000) + } + + updatePhraseFile() + + var wubiUdpPath1 = fsys.getSpecial(0x1a /*_CSIDL_APPDATA*/,"\Microsoft\InputMethod\Chs\ChsWubiEUDPv1.lex") + fsys.copy(wubiUdpPath,wubiUdpPath1); + + srvMgr.startManual("TabletInputService"); + srvMgr.start("TabletInputService"); + process(fsys.getWinDir("\System32\InputMethod\CHS\ChsIME.exe")); + + winform.btnSave.disabledText = null; +} + +import win.versionEx; +winform.btnLoad.oncommand = function(id,event){ + if( !win.version.isWin10ReleaseLater("1703") ){ + return winform.msgboxErr("仅支持 Win10 1703以上版本的五笔短语词库") + } + + winform.edit.text=""; + winform.btnLoad.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + var wubiUdpPath = ..io.exist( fsys.getSpecial(0x1a /*_CSIDL_APPDATA*/,"\Microsoft\InputMethod\Chs\ChsWubiEUDPv2.lex") ) + || ..io.exist( fsys.getSpecial(0x1a /*_CSIDL_APPDATA*/,"\Microsoft\InputMethod\Chs\ChsWubiEUDPv1.lex") ) + + if(!wubiUdpPath){ + winform.edit.text="系统短语词库为空"; + return; + } + thread.invoke( loadPhrases ,wubiUdpPath,winform) +} + +winform.btnSave.oncommand = function(id,event){ + if( !win.version.isWin10ReleaseLater("1703") ){ + return winform.msgboxErr("仅支持 Win10 1703以上版本的五笔短语词库") + } + + winform.btnSave.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} + thread.invoke( savePhrases,winform.edit.text,winform) +} + +winform.btnLoad.skin({ + background={ + default=0xFF8FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } +}) + +winform.btnSave.skin({ + background={ + default=0xFF8FB2B0; + hover=0xFF928BB3; + disabled=0xFFCCCCCC; + } +}) + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/dlg/spelling.aardio b/dlg/spelling.aardio index 72b3547..26aae97 100644 --- a/dlg/spelling.aardio +++ b/dlg/spelling.aardio @@ -5,7 +5,7 @@ import win.ui; /*DSG{{*/ var winform = win.form(text="五笔码表管理工具";right=1040;bottom=610;bgcolor=16777215) winform.add( -editSearch={cls="plus";left=292;top=191;right=717;bottom=226;border={bottom=1;color=-16744448};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-16);textPadding={top=6};z=2}; +editSearch={cls="plus";left=292;top=191;right=717;bottom=226;border={bottom=1;color=-16744448};dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-16);tabstop=1;textPadding={top=6};z=2}; plusCode={cls="plus";left=326;top=308;right=703;bottom=358;dl=1;dr=1;dt=1;font=LOGFONT(h=-37);z=3}; spelling={cls="plus";left=326;top=238;right=703;bottom=294;color=255;dl=1;dr=1;dt=1;font=LOGFONT(h=-26;name='98WB-2');z=1} ) @@ -17,10 +17,10 @@ import fsys.wubiSpelling98; var spelling98; var searchSpelling = win.debounce(function(word){ - if(!spelling98){ - spelling98 = fsys.wubiSpelling98(); - } - + if(!spelling98){ + spelling98 = fsys.wubiSpelling98(); + } + var code = winform.systemLex.find(word) winform.plusCode.text = code ? string.upper(code) : "缺少编码"; winform.spelling.text = spelling98.find(word); @@ -33,7 +33,7 @@ var searchSpelling = win.debounce(function(word){ if(as&&bs){ var as1,as2 = string.match(as,"〔\s*(\S+)\s+(\S+)") var bs1,bs2 = string.match(bs,"〔\s*(\S+)\s+(\S+)") - + if(as1&&as2&&bs1&&bs2){ winform.spelling.text = "〔 " + as1 +" "+ as2 +" "+ bs1 +" "+ bs2 + " 〕" } @@ -56,4 +56,5 @@ winform.editSearch.editBox.oncommand = function(id,event){ } } +winform.editSearch.editBox.setFocus() win.loopMessage(); \ No newline at end of file diff --git a/main.aardio b/main.aardio index ebbde04..0bafbd3 100644 --- a/main.aardio +++ b/main.aardio @@ -21,7 +21,7 @@ var tbs = win.ui.tabs( mainForm.nav1, mainForm.nav2, ); - + tbs.skin({ foreground={ active=0xFFFFFFFF; @@ -37,16 +37,82 @@ tbs.skin({ } }) +tbs.add({ + text="短语词库"; + iconText='\uF0AE'; +}) + tbs.add({ text="帮助"; iconText='\uF06A'; hasCloseButton = true; }) - + tbs.loadForm(1,"\dlg\lex.aardio" ); tbs.loadForm(2,"\dlg\spelling.aardio" ); -tbs.loadForm(3,"\dlg\help.aardio" ); +tbs.loadForm(3,"\dlg\phrase.aardio" ); +tbs.loadForm(4,"\dlg\help.aardio" ); tbs.selIndex = 1; +import win.util.tray; +mainForm.onMinimize = function(lParam){ + mainForm.tray = win.util.tray(mainForm) + mainForm.modifyStyleEx(0x40000/*_WS_EX_APPWINDOW*/,0x80/*_WS_EX_TOOLWINDOW*/) + mainForm.show(false); + return true; +} + +mainForm.onDestroy = function(){ + if(mainForm.tray){ + mainForm.tray.delete() + } +} + +import win.ui.menu; +mainForm.wndproc = { + [0xACCF/*_WM_TRAYMESSAGE*/ ] = function(hwnd,message,wParam,lParam){ + if( lParam = 0x205/*_WM_RBUTTONUP*/ ){ + win.setForeground(mainForm.hwnd) + mainForm.popmenu = win.ui.popmenu(mainForm);//创建弹出菜单 + mainForm.popmenu.add('切换词库',function(id){ + tbs.selIndex = 1; + mainForm.show(); + }); + mainForm.popmenu.add('管理短语',function(id){ + tbs.selIndex = 3; + mainForm.show(); + }); + mainForm.popmenu.add('字根反查',function(id){ + tbs.selIndex = 2; + mainForm.show(); + tbs.selForm.editSearch.editBox.setFocus(); + }); + mainForm.popmenu.add('打开本软件源代码',function(id){ + import process; + process.openUrl("https://github.com/aardio/wubi-lex-tool") + }); + mainForm.popmenu.add('下载最新版本',function(id){ + import process; + process.openUrl("https://github.com/aardio/wubi-lex-tool/releases") + }); + mainForm.popmenu.add('退出',function(id){ + mainForm.close() + }); + + var pt = ::POINT(); + ::User32.GetCursorPos(pt); + mainForm.popmenu.popup(pt.x,pt.y,true) + } + elseif( lParam = 0x202/*_WM_LBUTTONUP*/ ) { + mainForm.show(); + win.setForeground(mainForm.hwnd); + + if(tbs.selIndex = 2){ + tbs.selForm.editSearch.editBox.setFocus(); + } + } + } +} + mainForm.show(); return win.loopMessage(); diff --git a/screenshots/1.png b/screenshots/1.png index df58641..5b6feb4 100644 Binary files a/screenshots/1.png and b/screenshots/1.png differ diff --git a/screenshots/2.png b/screenshots/2.png index 9243318..fdd5678 100644 Binary files a/screenshots/2.png and b/screenshots/2.png differ