在WinCE程序开发中使用软件输入面板
2010-04-12 11:11
435 查看
简介
软件输入面板(Software Input Panel,简称SIP)是每个装备了WinCE系统的移动平台的一个基本功能。它提供给用户在PDA上进行数据输入的一种手段。当谈及SIP的时候,我们一般会想到两点:一是SIP本身,二是如何在程序中使用SIP。
SIP
是一个实现了IInputMethod或者IInputMethod2接口的COM对象。它应该被系统调入使用,所以你不能在C#中进行SIP开发。C或
者C++是很好的开发语言。因为SIP本身也只是另外一个COM对象,ATL使得开发过程变得极为简单。这里我不想讨论SIP开发,SDK包里包含了一个
很好的例程
ATLDvoraksip,所以你可以去学习这个例程以获取更多的信息。这里我想讨论的是如何在你自己的程序里管理SIP。这看起来很琐碎简单,但是如果
因为屏幕不太够用,而你又想使得你的程序更加聪明更加方便用户使用,那
SIP的管理就变成很重要的一个方面了。另外,如果你开发了很多用于不同场合的SIP(比如多语言,数字或者其他等等),你可能想在某个场合使用某个特定
的SIP。这种能力使得你可以完成很多不同的任务:当用户只需要进行数字输入的时候,你可以展示一个大的数字键盘,这样他不用笔而只需要用手指就可以输入
了。当然你也可以有自己的想法,这就看程序员该作些什么了。
Win32 API
SIP的API函数很简单,从sipapi.h中只可以看到只有极少几个函数:
我
把这些放在开始,是因为它同时支持Windows Mobile和CE.net平台。如果你对Windows
Mobile设备编程,那么aygshell.h文件提供给你更多的和SIP有关的函数供使用。当然选择哪个来使用就依赖于你自己的需求了,使用
Windows
Mobile上的SIP会使得工作更加完美一些。如果你使用了相同的OS版本,但是不同的build版本的时候,你可能会获得稍微不同的SIP行为。所
以,一种方法并不一定像你所想的那样在所有的PDA上都会适用。
列举可用的SIP
第一步就是了解如何列举所有可用的SIP。可以使用如下的代码:
代码所作的就是填充一个全局的map,它包含了"SIP名"/CLSID对。这个例子和其他的都用到了MFC,当然你也可以使用熟悉的Win32
API或者其他的框架。以下是我的Dell Axim x50上的显示效果:
如何选择,显示和隐藏特定的SIP
当你知道某个SIP的CLSID,你可以选择它。同时,当前选择的SIP也可以被获得:
这
里,你可以看到修改的例子(CSIPDemoDlg::OnButtonEnum()),它检测哪个SIP是被激活的并且选择listbox里相应的行。
其他例子的对话框方法选择SIP并且显示或者隐藏它。注意,为了使得SipGetInfo或者SipSetInfo工作,你必须用sizeof
(SIPINFO)的值初始化SIPINFO.cbSize,这样操作系统才能正常反应。这是一个很常用的Win32的解决方式。
SipGetInfo给你可视的桌面和SIP大小,这样你可以在需要的时候重新定制SIP的位置。而SipSetInfo不会改变SIP的位置。如果你需要移动SIP,使用SipSetDefaultRect。下面会给出一些例子来说明的。
使用Shell函数
如
果你决定使用基于aygshell的函数,SHSipPreference也会为你完成相似的任务。和SipShowIM一样,这个API将会显示和隐藏
输入面板。它的最后一个参数定义了作什么,可以请求显示或隐藏输入面板,马上隐藏(因为操作系统在一个常规事例里将会为此设置一个计时器)或者放弃所有的
等待中的请求。SHSipInfo允许你作和SipXXX函数一样的操作。
通常,你可以用以上所
有的API来响应WM_SETTINGCHAANGE或WM_CREATE消息。根据文档,当你使用SHSipInfo来处理
WM_SETTINGCHANGE消息的时候要特别小心。这有几个原因:第一,SIP的改变可能导致shell来发送WM_SETTINGCHANGE消
息,所以当你在你的处理函数里调用的时候要小心无限循环;第二,SHSipInfo将会和Device.exe以及输入面板线程相互作用,因此将会占据
100ms左右的时间。这将导致WM_SETTINGCHANGE消息发送给所有运行的程序,所以系统将会因此而失去响应一段时间。将lParam值同时
和WM_SETTINGCHANGE传递将会避免这样的延迟。
当
说到shell函数时,有些Windows
Mobile平台上的函数会非常有用也可能会变得让你头痛。这些包括SHInputDialog,SHFullScreen或者类似的调用。另外,
SHHandleWMActivate和SHHandleWMSettingChange会让你充分享受MFC程序中键盘自动弹出的乐趣,因为它们被用在
合适的消息句柄的CDialog和CFrameWnd类中。如果你不想拥有缺省的行为,你可以重载OnActivate或OnSettingChange
句柄。
自定义控制
如果你想支持一种智能化的输入框类的行为--每次进行输入时键盘自动弹出,然后当输入焦点从输入框移开后键盘隐藏,那么需要对WM_SETFOCUS和WM_KILLFOCUS进行处理。下面的代码可以帮助你:
设定SIP位置
下面谈谈如何移动SIP到屏幕上的某个位置。SipSetDefaultRect将会改变缺省的SIP的举行,但是它不会立即生效,除非你重新选择输入法:
上面的代码告诉你如何在屏幕上移动SIP的位置。这在你想在屏幕低端放置一些控件的时候会非常有用。当然这样不符合微软的Pocket
PC的GUI设计标准,但是有些时候你也没有其他的选择。
如果你可以获取窗口的句柄来控制窗口的样式,比如:
结束语
我们已经讨论了在WindowsCE操作系统上对SIP进行管理的若干方面,希望这些能够帮助你的程序成为用户眼里的赢家。
软件输入面板(Software Input Panel,简称SIP)是每个装备了WinCE系统的移动平台的一个基本功能。它提供给用户在PDA上进行数据输入的一种手段。当谈及SIP的时候,我们一般会想到两点:一是SIP本身,二是如何在程序中使用SIP。
SIP
是一个实现了IInputMethod或者IInputMethod2接口的COM对象。它应该被系统调入使用,所以你不能在C#中进行SIP开发。C或
者C++是很好的开发语言。因为SIP本身也只是另外一个COM对象,ATL使得开发过程变得极为简单。这里我不想讨论SIP开发,SDK包里包含了一个
很好的例程
ATLDvoraksip,所以你可以去学习这个例程以获取更多的信息。这里我想讨论的是如何在你自己的程序里管理SIP。这看起来很琐碎简单,但是如果
因为屏幕不太够用,而你又想使得你的程序更加聪明更加方便用户使用,那
SIP的管理就变成很重要的一个方面了。另外,如果你开发了很多用于不同场合的SIP(比如多语言,数字或者其他等等),你可能想在某个场合使用某个特定
的SIP。这种能力使得你可以完成很多不同的任务:当用户只需要进行数字输入的时候,你可以展示一个大的数字键盘,这样他不用笔而只需要用手指就可以输入
了。当然你也可以有自己的想法,这就看程序员该作些什么了。
Win32 API
SIP的API函数很简单,从sipapi.h中只可以看到只有极少几个函数:
DWORD WINAPI SipStatus(); BOOL WINAPI SipSetDefaultRect(RECT *); BOOL WINAPI SipReGISterNotification(HWND); BOOL WINAPI SipShowIM(DWORD); BOOL WINAPI SipGetInfo(SIPINFO *); BOOL WINAPI SipSetInfo(SIPINFO *); int WINAPI SipEnumIM(IMENUMPROC); BOOL WINAPI SipGetCurrentIM(CLSID *); BOOL WINAPI SipSetCurrentIM(CLSID *); |
把这些放在开始,是因为它同时支持Windows Mobile和CE.net平台。如果你对Windows
Mobile设备编程,那么aygshell.h文件提供给你更多的和SIP有关的函数供使用。当然选择哪个来使用就依赖于你自己的需求了,使用
Windows
Mobile上的SIP会使得工作更加完美一些。如果你使用了相同的OS版本,但是不同的build版本的时候,你可能会获得稍微不同的SIP行为。所
以,一种方法并不一定像你所想的那样在所有的PDA上都会适用。
列举可用的SIP
第一步就是了解如何列举所有可用的SIP。可以使用如下的代码:
CTypedPtrMap<CMapStringToPtr,CString,CLSID*> g_SipMap; int SipEnumIMProc(IMENUMINFO *pIMInfo) { CLSID* pCLSID = new CLSID; memcpy(pCLSID,&pIMInfo->clsid,sizeof(CLSID)); g_SipMap.SetAt(CString(pIMInfo->szName),pCLSID); TRACE(_T("%sn"),CString(pIMInfo->szName)); return 1; } void CSIPDemoDlg::OnButtonEnum() { SipEnumIM(SipEnumIMProc); CString sSipName; CLSID *pCLSID = NULL; for (POSITION pos = g_SipMap.GetStartPosition(); pos; ) { g_SipMap.GetNextAssoc(pos,sSipName,pCLSID); m_SipList.AddString(sSipName); } } |
API或者其他的框架。以下是我的Dell Axim x50上的显示效果:
如何选择,显示和隐藏特定的SIP
当你知道某个SIP的CLSID,你可以选择它。同时,当前选择的SIP也可以被获得:
void CSIPDemoDlg::OnButtonEnum() { SipEnumIM(SipEnumIMProc); CLSID CurrSip; SipGetCurrentIM(&CurrSip); int nCurrSip = LB_ERR, nSipCount = 0; CString sSipName, sCurrSipName; CLSID *pCLSID = NULL; for (POSITION pos = g_SipMap.GetStartPosition(); pos; ) { g_SipMap.GetNextAssoc(pos,sSipName,pCLSID); m_SipList.AddString(sSipName); if ( memcmp(&CurrSip,pCLSID,sizeof(CLSID)) == 0 ) { nCurrSip = nSipCount; sCurrSipName = sSipName; } nSipCount++; } m_SipList.SelectString(0,sCurrSipName); } void CSIPDemoDlg::OnButtonSelect() { int nSel = m_SipList.GetCurSel(); if ( LB_ERR == nSel ) return; CString sSipName; m_SipList.GetText(nSel,sSipName); CLSID *pCLSID = NULL; if ( !g_SipMap.Lookup(sSipName,pCLSID) ) return; BOOL bRes = SipSetCurrentIM(pCLSID); if ( !bRes ) TRACE(L"SipSetCurrentIM returned %lun",GetLastError()); } void CSIPDemoDlg::OnButtonShowHide() { if ( !g_bShow ) { SipShowIM(SIPF_ON); g_bShow = TRUE; } else { SipShowIM(SIPF_OFF); g_bShow = FALSE; } } void CSIPDemoDlg::OnButtonShowHide2() { SIPINFO SipInfo; memset(&SipInfo,0,sizeof(SipInfo)); SipInfo.cbSize=sizeof(SIPINFO); BOOL bRes = SipGetInfo(&SipInfo); if ( bRes ) { if ( !g_bShow ) { SipInfo.fdwFlags |= SIPF_ON; g_bShow = TRUE; } else { SipInfo.fdwFlags = SIPF_OFF; g_bShow = FALSE; } bRes = SipSetInfo(&SipInfo); } else { TRACE(L"SipGetInfo returned %lun",GetLastError()); } } |
里,你可以看到修改的例子(CSIPDemoDlg::OnButtonEnum()),它检测哪个SIP是被激活的并且选择listbox里相应的行。
其他例子的对话框方法选择SIP并且显示或者隐藏它。注意,为了使得SipGetInfo或者SipSetInfo工作,你必须用sizeof
(SIPINFO)的值初始化SIPINFO.cbSize,这样操作系统才能正常反应。这是一个很常用的Win32的解决方式。
SipGetInfo给你可视的桌面和SIP大小,这样你可以在需要的时候重新定制SIP的位置。而SipSetInfo不会改变SIP的位置。如果你需要移动SIP,使用SipSetDefaultRect。下面会给出一些例子来说明的。
使用Shell函数
如
果你决定使用基于aygshell的函数,SHSipPreference也会为你完成相似的任务。和SipShowIM一样,这个API将会显示和隐藏
输入面板。它的最后一个参数定义了作什么,可以请求显示或隐藏输入面板,马上隐藏(因为操作系统在一个常规事例里将会为此设置一个计时器)或者放弃所有的
等待中的请求。SHSipInfo允许你作和SipXXX函数一样的操作。
通常,你可以用以上所
有的API来响应WM_SETTINGCHAANGE或WM_CREATE消息。根据文档,当你使用SHSipInfo来处理
WM_SETTINGCHANGE消息的时候要特别小心。这有几个原因:第一,SIP的改变可能导致shell来发送WM_SETTINGCHANGE消
息,所以当你在你的处理函数里调用的时候要小心无限循环;第二,SHSipInfo将会和Device.exe以及输入面板线程相互作用,因此将会占据
100ms左右的时间。这将导致WM_SETTINGCHANGE消息发送给所有运行的程序,所以系统将会因此而失去响应一段时间。将lParam值同时
和WM_SETTINGCHANGE传递将会避免这样的延迟。
当
说到shell函数时,有些Windows
Mobile平台上的函数会非常有用也可能会变得让你头痛。这些包括SHInputDialog,SHFullScreen或者类似的调用。另外,
SHHandleWMActivate和SHHandleWMSettingChange会让你充分享受MFC程序中键盘自动弹出的乐趣,因为它们被用在
合适的消息句柄的CDialog和CFrameWnd类中。如果你不想拥有缺省的行为,你可以重载OnActivate或OnSettingChange
句柄。
自定义控制
如果你想支持一种智能化的输入框类的行为--每次进行输入时键盘自动弹出,然后当输入焦点从输入框移开后键盘隐藏,那么需要对WM_SETFOCUS和WM_KILLFOCUS进行处理。下面的代码可以帮助你:
void CSipEdit::OnSetFocus(CWnd* pOldWnd) { CEdit::OnSetFocus(pOldWnd); SHSipPreference(m_hWnd,SIP_UP); } void CSipEdit::OnKillFocus(CWnd* pNewWnd) { CEdit::OnKillFocus(pNewWnd); SHSipPreference(m_hWnd,SIP_FORCEDOWN); } |
下面谈谈如何移动SIP到屏幕上的某个位置。SipSetDefaultRect将会改变缺省的SIP的举行,但是它不会立即生效,除非你重新选择输入法:
void CSIPDemoDlg::OnButtonMove() { SIPINFO SipInfo; memset(&SipInfo,0,sizeof(SipInfo)); SipInfo.cbSize=sizeof(SIPINFO); BOOL bRes = SipGetInfo(&SipInfo); if ( bRes ) { CRect rc(SipInfo.rcSipRect); rc.OffsetRect(0,-20); SipSetDefaultRect(&rc); CLSID clsid; if ( SipGetCurrentIM(&clsid) ) { SipSetCurrentIM(&clsid); } SipShowIM(SIPF_ON); } } ; |
PC的GUI设计标准,但是有些时候你也没有其他的选择。
如果你可以获取窗口的句柄来控制窗口的样式,比如:
long lStyle=GetWindowLong(hwndSIP,GWL_STYLE); lStyle |= WS_CAPTION|WS_SYSMENU; SetWindowLong(hwndSIP,GWL_STYLE,lStyle); |
我们已经讨论了在WindowsCE操作系统上对SIP进行管理的若干方面,希望这些能够帮助你的程序成为用户眼里的赢家。
相关文章推荐
- [ZZ]在WinCE程序开发中使用软件输入面板
- 在WinCE程序开发中使用软件输入面板
- 在WinCE程序开发中使用软件输入面板
- 在WinCE程序开发中使用软件输入面板
- 在WinCE程序开发中使用软件输入面板
- 在WinCE程序开发中使用软件输入面板
- 在Win CE程序开发中使用软件输入面板
- 在Win CE程序开发中使用软件输入面板
- 在Win CE程序开发中使用软件输入面板
- 在Win CE程序开发中使用软件输入面板
- 笔记3-从毕业生到程序员:使用c#开发商业软件
- 10步开发一个QNX程序-QNX的软件程序开发,QNX开发环境开发工具使用
- Android 软件开发 使用Eclipse Debug调试程序 以及Eclipse快捷键操作详解
- Android 软件开发之如何使用Eclipse Debug调试程序详解(十二)
- 使用64位系统用vs2008开发软件,程序编译后无法连接ODBC的解决办法
- 在wince上使用Silverlight开发程序受关注的问题
- Android 软件开发之如何使用Eclipse Debug调试程序详解
- VS2008中开发wince windows mobile 手持终端程序(PDA软件)
- 在Windows Mobile和Wince(Windows Embedded CE)下如何使用.NET Compact Framework开发进程管理程序
- 笔记2-从毕业生到程序员:使用C#开发商业软件