WinCEプログラム開発におけるソフトウェア入力パネルの使用

18539 ワード

ソフトウェア入力パネル(Software Input Panel、略称SIP)は、WinCEシステムを搭載した各モバイルプラットフォームの基本機能である.ユーザがPDA上でデータ入力を行うための手段を提供する.SIPについて話すと、一般的に2つの点が考えられます.1つはSIP自体、2つはプログラムでSIPをどのように使用するかです.SIPはIInputMethodまたはIInputMethod 2インタフェースを実装したCOMオブジェクトである.システムに呼び出されるべきなので、C#でSIPの開発はできません.CあるいはC++はとても良い開発言語です.SIP自体も別のCOMオブジェクトであるため、ATLは開発プロセスを極めて簡単にする.ここではSIPの開発について議論したくないので、SDKパッケージにはATLDvoraksipという良いルーチンが含まれているので、このルーチンを勉強してより多くの情報を得ることができます.ここで私が議論したいのは、あなた自身のプログラムでSIPを管理する方法です.これは些細で簡単に見えますが、画面が足りないため、プログラムをより賢くしてユーザーが使いやすいようにしたい場合は、SIPの管理が重要な側面になります.また、多言語、数字、その他など、異なる場面で使用されるSIPを多く開発している場合は、ある場面で特定のSIPを使用したい場合があります.この能力により、ユーザーがデジタル入力を行うだけで、大きなデジタルキーボードを表示することができ、ペンではなく指で入力することができます.もちろんあなたも自分の考えを持ってもいいです.これはプログラマーが何をすべきかによって決まります.Win 32 APISIPの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動作が得られる可能性があります.したがって、1つの方法は、あなたが考えているようにすべてのPDAに適用されるとは限らない.利用可能なSIPを列挙する第1のステップは、利用可能なSIPをすべて列挙する方法を理解することである.次のコードを使用できます.
 1 CTypedPtrMap<CMapStringToPtr,CString,CLSID*> g_SipMap;
 2 int SipEnumIMProc(IMENUMINFO *pIMInfo)
 3 {
 4  CLSID* pCLSID = new CLSID;
 5  memcpy(pCLSID,&pIMInfo->clsid,sizeof(CLSID));
 6  g_SipMap.SetAt(CString(pIMInfo->szName),pCLSID);
 7  TRACE(_T("%sn"),CString(pIMInfo->szName));
 8  return 1;
 9 }
10 void CSIPDemoDlg::OnButtonEnum()
11 {
12  SipEnumIM(SipEnumIMProc);
13  CString sSipName;
14  CLSID *pCLSID = NULL;
15  for (POSITION pos = g_SipMap.GetStartPosition(); pos; )
16  {
17   g_SipMap.GetNextAssoc(pos,sSipName,pCLSID);
18   m_SipList.AddString(sSipName);
19  }
20 }

コードは、「SIP名」/LSIDペアを含むグローバルmapを埋め込むことである.この例と他の例はすべてMFCを使って、もちろんあなたも熟知しているWin 32 APIあるいはその他のフレームワークを使ってどのように選択することができて、特定のSIPを表示して隠すことができて、あなたがあるSIPのCLSIDを知っている時、あなたはそれを選択することができます.また、現在選択されているSIPは、以下のようにしてもよい.
 1 void CSIPDemoDlg::OnButtonEnum()
 2 {
 3  SipEnumIM(SipEnumIMProc);
 4  CLSID CurrSip;
 5  SipGetCurrentIM(&CurrSip);
 6  int nCurrSip = LB_ERR, nSipCount = 0;
 7  CString sSipName, sCurrSipName;
 8  CLSID *pCLSID = NULL;
 9  for (POSITION pos = g_SipMap.GetStartPosition(); pos; )
10  {
11   g_SipMap.GetNextAssoc(pos,sSipName,pCLSID);
12   m_SipList.AddString(sSipName);
13   if ( memcmp(&CurrSip,pCLSID,sizeof(CLSID)) == 0 )
14   {
15    nCurrSip = nSipCount;
16    sCurrSipName = sSipName;
17   }
18   nSipCount++;
19  }
20  m_SipList.SelectString(0,sCurrSipName);
21 }
22 void CSIPDemoDlg::OnButtonSelect()
23 {
24  int nSel = m_SipList.GetCurSel();
25  if ( LB_ERR == nSel )
26   return;
27  CString sSipName;
28  m_SipList.GetText(nSel,sSipName);
29  CLSID *pCLSID = NULL;
30  if ( !g_SipMap.Lookup(sSipName,pCLSID) )
31   return;
32  BOOL bRes = SipSetCurrentIM(pCLSID);
33  if ( !bRes )
34   TRACE(L"SipSetCurrentIM returned %lun",GetLastError());
35 }
36 void CSIPDemoDlg::OnButtonShowHide()
37 {
38  if ( !g_bShow )
39  {
40   SipShowIM(SIPF_ON);
41   g_bShow = TRUE;
42  }
43  else
44  {
45   SipShowIM(SIPF_OFF);
46   g_bShow = FALSE;
47  }
48 }
49 void CSIPDemoDlg::OnButtonShowHide2()
50 {
51  SIPINFO SipInfo;
52  memset(&SipInfo,0,sizeof(SipInfo));
53  SipInfo.cbSize=sizeof(SIPINFO);
54  BOOL bRes = SipGetInfo(&SipInfo);
55  if ( bRes )
56  {
57   if ( !g_bShow )
58   {
59    SipInfo.fdwFlags |= SIPF_ON;
60    g_bShow = TRUE;
61   }
62   else
63   {
64    SipInfo.fdwFlags = SIPF_OFF;
65    g_bShow = FALSE;
66   }
67   bRes = SipSetInfo(&SipInfo);
68  }
69  else
70  {
71   TRACE(L"SipGetInfo returned %lun",GetLastError());
72  }
73 }

ここで、どのSIPがアクティブになっているかを検出し、listboxの対応する行を選択する修正例(CSIPDemoDlg::OnButtonEnum())を見ることができます.他の例のダイアログメソッドはSIPを選択し、それを表示または非表示にする.SipGetInfoまたはSipSetInfoを動作させるには、オペレーティングシステムが正常に反応するようにsizeof(SIPINFO)の値でSIPINFO.cbSizeを初期化する必要があります.これはよく使われるWin 32の解決策です.SipGetInfoは、デスクトップとSIPのサイズを表示し、必要に応じてSIPの位置を再カスタマイズすることができます.一方、SipSetInfoはSIPの位置を変更しない.SIPを移動する必要がある場合は、SipSetDefaultRectを使用します.以下にいくつかの例を示して説明します.Shell関数を使用aygshellベースの関数を使用すると、SHSipPreferenceも似たようなタスクを完了します.SipShowIMと同様に、このAPIは入力パネルを表示および非表示にします.最後のパラメータは、入力パネルの表示または非表示を要求したり、オペレーティングシステムが通常の事例でタイマーを設定するため、すぐに非表示にしたり、すべての待機中の要求を放棄したりするために定義されています.SHSipInfoでは、SipXXX関数と同様の操作を行うことができます.通常、上記のすべてのAPIを使用してWM_に応答できます.SETTINGCHANGEまたはWM_CREATEメッセージ.ドキュメントによると、SHSipInfoを使用してWM_を処理するとSETTINGCHANGEメッセージの場合は特に注意してください.これにはいくつかの理由がある.第一に、SIPの変更はshellがWM_を送信することをもたらす可能性がある.SETTINGCHANGEメッセージなので、処理関数で呼び出すときは無限ループに注意してください.第二に,SHSipInfoはDevice.exeおよび入力パネルスレッドと相互作用するため,100 ms程度の時間を占める.これによりWM_SETTINGCHANGEメッセージは、実行中のすべてのプログラムに送信されるため、システムは応答をしばらく失うことになります.lParam値をWM_と同時にSETTINGCHANGE伝達はこのような遅延を回避する.shell関数といえば、Windows Mobileプラットフォームの関数が非常に役に立ち、頭が痛くなる可能性があります.これらには、SHInputDialog、SHFullScreenなどの呼び出しが含まれます.また、SHHandleWMActivateとSHHandleWMSettingChangeは、適切なメッセージハンドルのCDialogクラスとCFRameWndクラスで使用されるため、MFCプログラムでキーボードが自動的にポップアップされるのを十分に楽しむことができます.デフォルトの動作をしたくない場合は、OnActivateまたはOnSettings Changeハンドルを再ロードできます.カスタム制御インテリジェントな入力ボックスクラスの動作をサポートしたい場合は、入力するたびにキーボードが自動的にポップアップし、入力フォーカスが入力ボックスから離れた後にキーボードが非表示になるようにするには、WM_SETFOCUSとWM_KILLFOCUSで処理します.次のコードが役立ちます.
 1 void CSipEdit::OnSetFocus(CWnd* pOldWnd)
 2 {
 3  CEdit::OnSetFocus(pOldWnd);
 4  SHSipPreference(m_hWnd,SIP_UP);
 5 }
 6 void CSipEdit::OnKillFocus(CWnd* pNewWnd)
 7 {
 8  CEdit::OnKillFocus(pNewWnd);
 9  SHSipPreference(m_hWnd,SIP_FORCEDOWN);
10 }

SIP位置を設定して、画面上のある位置にSIPを移動する方法について説明します.SipSetDefaultRectはデフォルトのSIPの開催を変更しますが、入力方式を再選択しない限り、すぐには有効になりません.
 1 void CSIPDemoDlg::OnButtonMove()
 2 {
 3  SIPINFO SipInfo;
 4  memset(&SipInfo,0,sizeof(SipInfo));
 5  SipInfo.cbSize=sizeof(SIPINFO);
 6  BOOL bRes = SipGetInfo(&SipInfo);
 7  if ( bRes )
 8  {
 9   CRect rc(SipInfo.rcSipRect);
10   rc.OffsetRect(0,-20);
11   SipSetDefaultRect(&rc);
12   CLSID clsid;
13   if ( SipGetCurrentIM(&clsid) )
14   {
15    SipSetCurrentIM(&clsid);
16   }
17   SipShowIM(SIPF_ON);
18  }
19 }

上のコードは、画面上でSIPの位置を移動する方法を示しています.これは、画面の下端にコントロールを配置したいときに役立ちます.もちろんこれはマイクロソフトのPocket PCのGUI設計基準に合わないが、他に選択肢がない場合もある.ウィンドウのハンドルを取得して、ウィンドウのスタイルを制御できる場合は、次のようにします.
1 long lStyle=GetWindowLong(hwndSIP,GWL_STYLE);
2 lStyle |= WS_CAPTION|WS_SYSMENU;
3 SetWindowLong(hwndSIP,GWL_STYLE,lStyle);