CE開發相關:在Win CE程式開發中使用軟體輸入面板

來源:互聯網
上載者:User

簡介

  軟體輸入面板(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 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);

 }

}

  代碼所作的就是填充一個全域的map,它包含了"SIP名"/CLSID對。這個例子和其他的都用到了MFC,當然你也可以使用熟悉的Win32 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位置

  下面談談如何移動SIP到螢幕上的某個位置。SipSetDefaultRect將會改變預設的SIP的舉行,但是它不會立即生效,除非你重新選擇IME: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);

 }

}

  上面的代碼告訴你如何在螢幕上移動SIP的位置。這在你想在螢幕低端放置一些控制項的時候會非常有用。當然這樣不符合微軟的Pocket PC的GUI設計標準,但是有些時候你也沒有其他的選擇。

  如果你可以擷取視窗的控制代碼來控制視窗的樣式,比如:long lStyle=GetWindowLong(hwndSIP,GWL_STYLE);

lStyle |= WS_CAPTION|WS_SYSMENU;

SetWindowLong(hwndSIP,GWL_STYLE,lStyle);

  結束語

  我們已經討論了在WindowsCE作業系統上對SIP進行管理的若干方面,希望這些能夠協助你的程式成為使用者眼裡的贏家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.