通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)
原文:通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)
从我在博客园写第一篇博客到现在已经有1年半了,我的第一篇博客写的就是手写识别,当时,客户需求在应用中加入手写输入功能,由于第三方的手写输入法都无法定制界面,所以领导决定自主开发,所以我就很简单地基于Tablet pc写了一个WPF控件,由于几个瓶颈问题,导致这个输入功能只能在我们的UI框架里使用,而无法做到像输入法那样可以输入到任意窗口。
时隔1年半,随着各种项目的磨练,知识的积累几个问题得以解决,于是就产生了这个手写输入法。
ICO:
UI:
符号识别:
识别率还是比较高的
界面风格是1年半前设计的,当时觉得《创世纪》的视觉效果挺牛X的。
因为是针对于触摸设备设计的,所以没有做退出按钮,由应用来控制关闭。PC上的话,在空白处左键可以拖动,点击右键关闭窗口。
一、瓶颈问题
由于本人C#出身,实在不想去研究什么IME等等底层的输入法机制,所以就写个exe实现输入法的功能。就面临下面几个问题:
1、如何向其他窗口发送输入消息呢?
2、如何知道当前键盘焦点所在窗口呢?
3、如何在操作输入法窗体的时候不让目标窗口丢失焦点呢?
这几个问题读起来就比较纠结......有句话说得好啊,“当做一件事时越来越难,就说明方向错了”。所以就绕开这几个问题呗。
二、解决问题
C#里有个模拟键盘按键的方法
模拟按键:
System.Windows.Forms.SendKeys.SendWait("{DEL}");
而且可以发送字符:
System.Windows.Forms.SendKeys.SendWait("你好,美女~!");
通过这个方法就模拟了键盘上的del键和发送字符串输入消息,而这个方法并没有需要窗口句柄,所以我猜想应该是模拟了底层的按键消息等等,而消息的去向肯定就是键盘焦点所在的窗口咯,这样就绕开了1、2两个问题。关于SendWait()参数的详细说明可以参看:http://msdn.microsoft.com/zh-cn/library/system.windows.forms.sendkeys.aspx
接下来就需要解决的就只有3号问题了。
一开始我很单纯的以为只要把窗口里面的所有控件都设置为不能获取焦点就行了
.Focusable = false;
但这只是第一步,当一个窗口被激活时所有焦点都会跑到新激活的窗体上,所以,还得寻找其他方法。无意中在逛codeproject的时候发现了一段代码:
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); [DllImport("user32.dll", SetLastError = true)]
public static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex); // style of window?
int GWL_EXSTYLE = (-);
// get - retrieves information about a specified window
GetWindowLong(HWND, GWL_EXSTYLE);
// set - changes the attribute of a specified window - I think this stops it being focused on
SetWindowLong(HWND, GWL_EXSTYLE, (IntPtr)(0x8000000));
Windows API的参数就是高端啊,完全看不懂是在干嘛,不过能达到目标就行。这样HWND窗口句柄对应的窗口就变得不会获取键盘焦点了。
这样就解决了3个瓶颈问题。
三、手写识别
已经实现了如何把字符串输出到其他窗口,剩下的就是识别手写墨迹了,核心在于InkAnalyzer这个类。通过WPF的InkCanvas控件来收集墨迹,然后通过theInkAnalyer.Analyze();方法就可以解析出来,十分方便。代码如下:(需要引用IACore.dll、IALoader.dll、IAWinFX.dll这3个动态库)
InkAnalyzer theInkAnalyer;
AnalysisHintNode hint;
private void Grid_Loaded(object sender, RoutedEventArgs e)
{// style of window?
int GWL_EXSTYLE = (-);
// get - retrieves information about a specified window
GetWindowLong(HWND, GWL_EXSTYLE);
// set - changes the attribute of a specified window - I think this stops it being focused on
SetWindowLong(HWND, GWL_EXSTYLE, (IntPtr)(0x8000000)); theInkAnalyer = new InkAnalyzer();
hint = theInkAnalyer.CreateAnalysisHint();
hint.Guide.Columns = ;
hint.Guide.Rows = ;
hint.WordMode = true;
hint.TopInkBreaksOnly = true; } private void inkCanvs_MouseUp(object sender, MouseButtonEventArgs e)
{
hint.Location.MakeInfinite();
theInkAnalyer.RemoveStrokes(inkCanvs.Strokes);
theInkAnalyer.AddStrokes(inkCanvs.Strokes);
theInkAnalyer.SetStrokesLanguageId(inkCanvs.Strokes, 0x0804); theInkAnalyer.SetStrokesType(inkCanvs.Strokes, StrokeType.Writing);
AnalysisStatus status = theInkAnalyer.Analyze();
if (status.Successful)
{
for (int i = ; i < theInkAnalyer.GetAlternates().Count; i++)
{
Button thisButton = this.FindName("b" + i.ToString()) as Button;
string resultStr = theInkAnalyer.GetAlternates()[i].RecognizedString;
if (resultStr.Length==)
{
thisButton.Content = resultStr;
} } }
else
{
//MessageBox.Show("识别失败");
}
}
最终效果
要在已安装了Tablet pc组件的Win7以上的系统才可以手写识别哦,win7完整版默认安装,但有的精简版把这个组件丢掉了,win8下完美运行。xp下的话得改一些系统文件,相关方法可以查看本人的第一篇博客 http://www.cnblogs.com/tong-tong/archive/2011/10/22/2220446.html
IACore等动态库下载:(包含XML注释文档)
http://files.cnblogs.com/tong-tong/IADLL.zip
demo下载:
http://files.cnblogs.com/tong-tong/TTHandwriting.zip
后记
最近各种事情还要出钱啊、各种副省长还来参观啊、各种项目还没结束啊......
通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)的更多相关文章
- 通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能
原文:通通WPF随笔(1)--基于lucene.NET让ComboBox拥有强大的下拉联想功能 我一直很疑惑百度.谷哥搜索框的下拉联想功能是怎么实现的?是不断地查询数据库吗?其实到现在我也不知道,他们 ...
- 通通WPF随笔(3)——艺术二维码素材生成器
原文:通通WPF随笔(3)--艺术二维码素材生成器 最近公司让我开发一个条形码的生成控件,花了半天时间搞定觉得不过瘾,什么年代了该用二维码了吧.于是wiki了一下二维码的资料. 比较常见的就是QR码( ...
- 通通WPF随笔(2)——自己制作轻量级asp.net网站服务
原文:通通WPF随笔(2)--自己制作轻量级asp.net网站服务 大学玩asp.net时就发现VS在Debug时会起一个web服务,这东西也太神奇了服务起得这么快,而相对于IIS又这么渺小. 前几个 ...
- c#基于Tablet pc实现的手写输入
需要安装Tablet pc,win7的话 直接在控制面板>程序和应用>添加组建里面勾选上添加 然后就是下面的程序了,看代码 设计文件 namespace 手写识别 { partial cl ...
- WPF随笔(九)--使用路径动画模拟管道流体流向
原文:WPF随笔(九)--使用路径动画模拟管道流体流向 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lordwish/article/detail ...
- wpf随笔
因项目需要查找wpf.DataGrid的Binding方法, 由于其属于Dev框架体系内,偏向于winform并无Binding 1.且线程外更改UI控件还需要委托或者action,而Wpf控件仅需要 ...
- 循环移位法和数据拼接法基于led
功能描述 让led每隔0.5s从两边向中间闪烁,然后在从中间向两边闪烁,不断循环 项目实现 开发板 晶振为50M,那么达到0.5s时计数器count1需要达到24_999_999这么多次数 计数器代码 ...
- 商米D1S一体机设置搜狗手写输入法图解
按照下图步骤,一步步设置即可,询问全新的时候需要点击允许. 商米应用市场搜索下载搜狗输入法,并安装 安装完成后,点击桌面搜狗输入法,选择启用搜狗输入法,如图 点击启用后,在虚拟键盘中选择搜狗输入法,并 ...
- iOS 手写输入法奔溃,替换隐藏键盘方法
{ UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:se ...
随机推荐
- [转载]Ocelot简易教程(二)之快速开始2
为什么这篇的标题叫“Ocelot简易教程(二)之快速开始2”呢,因为很多朋友跟我说上一篇“ Ocelot简易教程(二)之快速开始1”内容太少了,只是简单介绍Ocelot的一些简单配置,让Ocelot能 ...
- 【41.43%】【codeforces 560C】Gerald's Hexagon
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- MySQL key分区(五)
具体描写叙述总结请看MySQL分区(一) 样例:该样例为本人个人学习总结分享->具体说明-->有问题欢迎前来交流
- windows下 管理员身份启动java进程
http://blog.csdn.net/zhuyijian135757/article/details/38234757
- java线程池框架源代码分析
相关类Executor,Executors.AbstractExecutorService.ExecutorService Executor:整个线程池运行者框架的顶层接口. 定义了一个execute ...
- 自己动手写shell命令之ls
linux下ls命令(支持-R參数)的c语言实现: #include <stdio.h> #include <sys/types.h> #include <dirent. ...
- jQuery实现复选框的全选、反选、并且根据复选框的<checked属性>控制多个对应div的显示/隐藏
<!doctype html><html> <head> <meta charset="utf-8"> <title>j ...
- 12个被滥用的Android应用程序权限
Android应用程序须要权限才干正常运作,只是网络犯罪分子会将其用在个人私利上.来看看最常被要求的权限以及它们会怎样被滥用. .网络定位功能 这代表什么:同意应用程序通过网络定位(像是基地台或无线网 ...
- iOS开发 - OC - block的详解 - 深入篇
深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...
- 云主机CentOS 7新环境命令行搭建node工程步骤
1.用Node官网提供的命令安装node https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-d ...