August 27, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Managing the Software Input Panel in Your Applications

  • February 8, 2006
  • By Alex Gusev
  • Send Email »
  • More Articles »

Software Input Panel: Two Sides of a Development

The Software Input Panel (SIP)is presented on every mobile platform powered by Windows CE (for example, the Windows Mobile family or CE.NET). This is one of the methods the user can use to enter the data the on PDA. I'm probably not the only one, but I believe it's the most useful way for many applications. Hence, in talking about SIP, you usually mean two different things: the SIP itself, and how to manage it from within the application.

SIP is just a COM object implementing IInputMethod or IInputMethod2 interfaces. It should be loaded by the OS, so you can't develop SIP in C#. C or C++ are your helpful languages here. Because SIP is just another COM object, ATL makes all the development process significantly easier. I won't discuss SIP development in this article. The SDK samples contain a perfect example located under ...SamplesATLDvoraksip, so please refer to that sample for more info.

What I would like to talk about is how to manage SIP from within your own application. The task may look trivial, but if you want to make your application smarter and more convenient for the user because of the lack of screen, SIP management becomes a more than important issue. In addition, if you have developed different SIPs suitable for different areas (for example, multilingual, numeric, or whatever else), you might want to use a specific SIP in a specific case. Such capability allows you to achive many goals; you can show a big numeric keyboard when the user has to enter numbers only, thus allowing him to work with his fingers instead of a stylus. You probably have your own ideas. This said, see what a developer can do here.

Win32 API Details

The SIP API is pretty simple. There are less than a dozen functions (taken from 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 *);

I have placed this material first because it is supported on both Windows Mobile and CE.NET platforms. If you are an adept of Windows Mobile powered devices, the aygshell.h header file provides more SIP-related functions that partially duplicate those noted above. Which set to use depends on your requirements. The situation with SIP on Windows Mobile is even nicer. If you take several devices with the same OS version (for example, Windows Mobile SE version 4.21.XXXX) but with different build numbers, you can easily get a slightly different SIP behavior. Hence, one strategy just doesn't always work on every PDA as you might intend. Sounds optimistic, doesn't it?

Enumerating Available SIPs

The very first step to know the enemy is to enumerate SIPs. To accomplish this task, look at the following code snippet:

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);
   }
}

All it does is fill in the global map, which contains "SIP name"/CLSID pairs. This and the other following samples use MFC, but you can do exactly the same with Win32 API or any other framework you've gotten used to. As a result, my old buddy Dell Axim x50 shows the following:

How to Select, Show, and Hide Specific SIPs

Once you know a CLSID of desired SIP, you can select it by demand. And vice versa, at any point currently selected SIP may be obtained:

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());
   }
}

Here, you see slightly modified sample (CSIPDemoDlg::OnButtonEnum()), which detects which SIP is active and selects the appropriate line in the listbox. Other sample dialogs' methods select SIP and show/hide it. Note that, in order to get SipGetInfo or SipSetInfo working, you have to initialize SIPINFO.cbSize to sizeof(SIPINFO) value, so the OS will act correctly. This is trivial and a usual Win32 approach, but the following it helps you avoid wasting your time in attempts to understand why it doesn't work.

SipGetInfo gives us also visible desktop and SIP sizes that you can use to reposition SIP if needed. In turn, SipSetInfo doesn't change SIP dimentions. If you need to move SIP, use SipSetDefaultRect. I will give you some example of SIP repositioning later in this article.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel