现在的位置: 首页 > 综合 > 正文

在应用中使用输入面板的注意

2013年10月07日 ⁄ 综合 ⁄ 共 4448字 ⁄ 字号 评论关闭
[b]简介

[/b]  软件输入面板(Software Input Panel,简称SIP)是每个装备了WinCE系统的移动平台的一个基本功能。它提供给用户在PDA上进行数据输入的一种手段。当谈及SIP的时候,我们一般会想到两点:一是SIP本身,二是如何在程序中使用SIP。

  SIP是一个实现了IInputMethod或者IInputMethod2接口的COM对象。它应该被系统调入使用,所以你不能在[url=http://dev.21tx.com/dotnet/csharp/][color=#3366cc]C#[/color][/url]中进行SIP开发。C或者[url=http://dev.21tx.com/language/c/][color=#3366cc]C++[/color][/url]是很好的[url=http://dev.21tx.com/language/][color=#3366cc]开发语言[/color][/url]。因为SIP本身也只是另外一个COM对象,ATL使得开发过程变得极为简单。这里我不想讨论SIP开发,SDK包里包含了一个很好的例程ATLDvoraksip,所以你可以去学习这个例程以获取更多的信息。 这里我想讨论的是如何在你自己的程序里管理SIP。这看起来很琐碎简单,但是如果因为屏幕不太够用,而你又想使得你的程序更加聪明更加方便用户使用,那SIP的管理就变成很重要的一个方面了。另外,如果你开发了很多用于不同场合的SIP(比如多语言,数字或者其他等等),你可能想在某个场合使用某个特定的SIP。这种能力使得你可以完成很多不同的任务:当用户只需要进行数字输入的时候,你可以展示一个大的数字[url=http://diy.21tx.com/mouse/][color=#3366cc]键盘[/color][/url],这样他不用笔而只需要用手指就可以输入了。当然你也可以有自己的想法,这就看程序员该作些什么了。

  [b]Win32 API[/b]

  SIP的API函数很简单,从sipapi.h中只可以看到只有极少几个函数:

[table][tr][td]D[url=http://school.21tx.com/office/word/][color=#3366cc]Word[/color][/url] WINAPI SipStatus();
BOOL WINAPI SipSetDefaultRect(RECT *);
BOOL WINAPI SipRe[url=http://dev.21tx.com/corp/gis/][color=#3366cc]GIS[/color][/url]terNotification(HWND);
BOOL WINAPI SipShowIM(D[url=http://school.21tx.com/office/word/][color=#3366cc]Word[/color][/url]);
BOOL WINAPI SipGetInfo(SIPINFO *);
BOOL WINAPI SipSetInfo(SIPINFO *);
int WINAPI SipEnumIM(IMENUMPROC);
BOOL WINAPI SipGetCurrentIM(CLSID *);
BOOL WINAPI SipSetCurrentIM(CLSID *);[/td][/tr][/table]
  我把这些放在开始,是因为它同时支持[url=http://dev.21tx.com/os/windows/][color=#3366cc]Windows[/color][/url] Mobile和CE[url=http://dev.21tx.com/dotnet/][color=#3366cc].net[/color][/url]平台。如果你对[url=http://dev.21tx.com/os/windows/][color=#3366cc]Windows[/color][/url] Mobile设备编程,那么aygshell.h文件提供给你更多的和SIP有关的函数供使用。当然选择哪个来使用就依赖于你自己的需求了,使用[url=http://dev.21tx.com/mobile/wince/][color=#3366cc]Windows Mobile[/color][/url]上的SIP会使得工作更加完美一些。如果你使用了相同的OS版本,但是不同的build版本的时候,你可能会获得稍微不同的SIP行为。所以,一种方法并不一定像你所想的那样在所有的PDA上都会适用。

  [b]列举可用的SIP[/b]

  第一步就是了解如何列举所有可用的SIP。可以使用如下的代码:

[table][tr][td]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);
 }
}[/td][/tr][/table]
  代码所作的就是填充一个全局的map,它包含了"SIP名"/CLSID对。这个例子和其他的都用到了MFC,当然你也可以使用熟悉的Win32 API或者其他的框架。以下是我的Dell Axim x50上的显示效果:

[table=90%][tr][td][align=center][img]http://image.21tx.com/image/20060602/15903.gif[/img][/align][/td][/tr][/table]
  [b]如何选择,显示和隐藏特定的SIP[/b]

  当你知道某个SIP的CLSID,你可以选择它。同时,当前选择的SIP也可以被获得:

[table][tr][td]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());
 }
}[/td][/tr][/table]
  这里,你可以看到修改的例子(CSIPDemoDlg::OnButtonEnum()),它检测哪个SIP是被激活的并且选择listbox里相应的行。其他例子的对话框方法选择SIP并且显示或者隐藏它。注意,为了使得SipGetInfo或者SipSetInfo工作,你必须用sizeof(SIPINFO)的值初始化SIPINFO.cbSize,这样[url=http://dev.21tx.com/os/][color=#3366cc]操作系统[/color][/url]才能正常反应。这是一个很常用的Win32的解决方式。

  SipGetInfo给你可视的桌面和SIP大小,这样你可以在需要的时候重新定制SIP的位置。而SipSetInfo不会改变SIP的位置。如果你需要移动SIP,使用SipSetDefaultRect。下面会给出一些例子来说明的。 

抱歉!评论已关闭.