有没有类似“你写我读”的软件,打一个字读一个字的?

写东西时作为校对之用
【txt朗读很多了,需要的是边输入边读的】

excel

image

下面这个没用过,搜出来的.
image

excel就算了。。。
你写我读在64位win10下面不好用,或者根本不能用。

现在有个方案,利用其他阅读软件的自动朗读剪贴板功能来朗读新输入的字符。
但是不知道有什么办法可以自动将新输入的字符自动发送到粘贴板的办法。
autohotkey应该可以做到,但是我不会。

最新进展,已经通过autohotkey简单编码完成了这个功能。
第一步,安装朗读女,设置朗读剪贴板的快捷键为ctrl+R。
1
第二步,启用ahk,代码如下。

~1::
~2::
~3::
~4::
~5::
~6::
~7::
~8::
~9::
~space::
send , ^a
send , ^c
Clipboardold := Clipboardtemp
Clipboardtemp := Clipboard
num := StrLen(Clipboardold) - StrLen(Clipboardtemp)
if ((SubStr(Clipboardold,1,1)=SubStr(Clipboardtemp,1,1)) and (num < 0))
{
Clipboard := SubStr(Clipboard, 1+num)
send , ^r
}
else
{
send , ^r
}
send , {Right}
return

代码说明:

  1. 输入法选择备选词时,需要按下1~9或空格键,此时触发操作,将分析剪贴板前后变化,朗读新增字符。【通过小键盘数字键选字不会触发朗读】
  2. 存在的问题:①只能朗读向文末添加的字符,向一句中间插着写的读不了且有bug【建议这时通过小键盘选字】。②其他小问题若干,但不太影响使用。
  3. 优点:朗读女有很多的发音人可供选择,比“你写我读”的声音好听多了,哈哈。
  4. 期待大神帮忙改进。
1 Like

最新方案

借助autoahk论坛两位大神的作品,融在一起实现了这一目的。

  1. 自动对输入框截图
    以输入法候选框窗口截图代替文字上屏小案例 – AutoAHK
  2. ocr工具
    GitHub - telppa/PaddleOCR-AutoHotkey: PaddleOCR AutoHotkey Version.PaddleOCR AHK 版。

现在的方案是,每次按下123456或者空格(也就是选词的时候),自动对输入框有效区域进行截图ocr,根据按下的是123456或空格,通过正则提取出所输入的字符,并且通过tts朗读出来。

win10,64位可用,这个ocr工具32位不能用。
链接就不放了,有ahk基础的很容易就能用上面两个大神的项目复现了。

优点

  1. 比你写我读兼容性更强,无论什么不标准窗口,只要输入法界面能出来,就能识别。
  2. 可以加点代码,把你输入的所有中文英文都记录下来,自己给自己做字库,或者作为文字时光机使用。
  3. 可以调用其他朗读技术,不局限于微软tts,让声音更好听。

缺点

稍稍有一丢丢卡顿感,但是处于可接受范围之内。

喜欢这种一年以后更新的帖子

前段时间找输入法的时候看到了 https://soime.cn/
不过这输入法感觉并不好用,没深入尝试

1 Like

感谢,俺试试。
类似的方案还有影子输入法,基于ahk的,加几行代码也可以语音复读。
不过这些小众输入法词库一般都不太能打。

自己写了一个win11微软输入法输入同步朗读的,不同于之前截图ocr的方式,使用的是UIA——无障碍读取方式。
直接读取微软输入法新输入的汉字,然后朗读出来,所以快得多。

和这个小工具同样的原理和使用方法,快捷键ctrl shift n:

你叉叉(You Fa Fa)——输入法关键词屏蔽小工具,也网文作者好帮手~控制骂人情绪,从输入法做起 - 讨论分享 - 小众软件官方论坛 (appinn.net)

用的大神的UIA库 AutoHotkey 使用 UI Automation(UIA) 获取相关信息教程 - 火冷 - 博客园 (cnblogs.com)
autohotkey V2 代码

#include Class_UIA.ah2
#Warn All, Off
#SingleInstance force
global ID
global ifok
ifok := 0
return

~^+n::{
global ID
global ifok
if ifok = 0 {
MouseGetPos , , , &ID, 2
msgbox("已开启朗读模式")
ifok := 1
}else{
msgbox("已关闭朗读模式")
ifok := 0
}
return
}

#HotIf (ifok = 1)

$1:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "1")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}1"
return
}

$space:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "1")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{space}"
return
}

$2:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "2")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}2"
return
}

$3:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "3")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}3"
return
}

$4:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "4")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}4"
return
}

$5:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "5")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}5"
return
}

$6:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "6")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}6"
return
}

$7:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "7")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}7"
return
}

$8:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "8")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}8"
return
}

$9:: {
global ID
local n
try
{
   elWin := UIA.ElementFromHandle(ID)
   cond := UIA.CreatePropertyCondition("name", "9")
   Element := elWin.FindFirst(cond, 4)
   Element := Element.GetNext()
   itemName := Element.GetCurrentPropertyValue(30005)
}
catch
{
itemName :=""
}
run 'mshta vbscript:createobject(`"sapi.spvoice`").speak(`"' itemName '`")(window.close)'
Send "{Raw}9"
return
}