News | Articles | Libraries | Developer Tools | Books | Forum Links | Search   
Sections:
 

Input Method

By Vassili Philippov, December 21, 2001.
Print version

Introduction

SIP (Soft Input Panel) technology is based on input methods (IMs). Each IM is a way to enter characters like keyboard, letter recognizer, block recognizer. You can create your own input method. This paper describes creating a custom input method and gives working sample.

What you need

What we create

We will create a very simple IM that will give you possibility to enter only three symbols: 1, A and 3. Of course no one will use this input method :) But you can learn the main ideas of the input method implementation.
Our target input method

Step by step

The next 10 sections describe creating your own input method step by step. Let's start with a short overview of these sections:

  1. Create a new project. We will use ATL with MFC support.
  2. Create a COM object that will implement our input method functionality.
  3. Implement IInputMethod. Now all methods are blank. We will implement them later.
  4. We have to change registry settings to register our COM as an input method.
  5. We will change an icon that is used in SIP button for our input method.
  6. We can avoid using dvoraksip.tlb.
  7. Now we will create a panel that implements all business logic.
  8. The systen gives us callback interface that should be called to generate symbols.
  9. Our panel handles mouse event to generate symbols when needed and ...
  10. Input method works!

Step 1. Create new project


Create new project using "WCE ATL COM AppWizard". Set "Support MFC" at the second step of the wizard because we want to use MFC classes. Now an empty project is created. ATL wizard does not create any COM objects we have to do it ourselves.

Step 2. Create a new COM object


Create new ATL Object. "Simple Object" is the most suitable template for our purposes. Let's call the object BitmapIM. Close the workspace and open it again. I do not know if you have this bug but my eMbedded Visual Studio does not show created class in the ClassView and I have to close and re-open the project.

Step 3. Implement IInputMethod


Now we have to implement IInputMethod interface. It is easy if you have a .tlb file that contains this interface. You can fint such file in Pocket PC 2002 SDK. After installing this SDK look at <Windows CE Tools>\wce300\Pocket PC 2002\samples\ATL\dvoraksip\dvoraksip.tlb or your can download this file dvoraksip.tlb (6 Kb). Right-click on the class name, add this template library and choose IInputMethod interface.

Step 4. Change registry settings


Now we have empty Input Method. Pocket PC uses registry to detect that some COM is an input method. There should be a special key 'IsSIPInputMethod' with value '1' in class section. Open .rgs file and add the following line just after VersionIndependentProgID value:

IsSIPInputMethod = s '1'


Now we have an input method that can be registered but does nothing. This input method is shown in the SIP menu as 'BitmapIM Class'. We can change the input method name (how it is called in a menu shown after the SIP button is pressed) by changing the class name in registry. Change the name in .rgs file in the line that contains "ForceRemove" string.

Step 5. Change icon

Let's change icon shown in the SIP button. We have to rewrite GetInfo method for that. In this method we have to fill the given structure and add image list handles. Here is code for that:

STDMETHOD(GetInfo)(_tagImInfo * pimi) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) if (pimi == NULL) return E_POINTER; pimi->hImageNarrow = (HIMAGELIST)m_imageList1; pimi->iNarrow = 0; pimi->hImageWide = (HIMAGELIST)m_imageList2; pimi->iWide = 0; return S_OK; }

Also we have to add two class members (m_imageList2 and m_imageList1) and initialize them. Here is a code that defines these members:

CImageList m_imageList1; CImageList m_imageList2;

Then you have to initialize these two image lists. I suggest doing it in FinalConstruct method:

HRESULT CBitmapIM::FinalConstruct() { AFX_MANAGE_STATE(AfxGetStaticModuleState()) m_imageList1.Create(IDB_LIST1, 16, 1, RGB(0,255,0)); m_imageList2.Create(IDB_LIST2, 32, 1, RGB(0,255,0)); return S_OK; }

Do not forget to add:

AFX_MANAGE_STATE(AfxGetStaticModuleState())

in the begining of each method where you use resources and MFC.

Step 6. Avoid using dvoraksip.tlb

Now we can remove #import of dvoraksip.tlb. But we should #include of sip.h and make 3 defines:

#include <Sip.h> extern "C" const GUID __declspec(selectany) IID_IIMCallback = {0x42429669,0xae04,0x11d0,{0xa4,0xf8,0x00,0xaa,0x00,0xa7,0x49,0xb9}}; extern "C" const GUID __declspec(selectany) IID_IInputMethod = {0x42429666,0xae04,0x11d0,{0xa4,0xf8,0x00,0xaa,0x00,0xa7,0x49,0xb9}}; extern "C" const GUID __declspec(selectany) CLSID_CMSDvorakIm = {0x42429695,0xae04,0x11d0,{0xa4,0xf8,0x00,0xaa,0x00,0xa7,0x49,0xb9}};

Several errors will appear because the same types have different names in sip.h and in the header file generated by #import. You will have the following compiler error

(77) : error C2061: syntax error : identifier '_tagSipInfo'

just change _tagSipInfo to SIPINFO in the header file.

Then you have to change wireHWND to HWND. Now you can compile your code. To make the input method better we will change all E_NOTIMPL return values to S_OK. Let's upload our input method and see how it works now (it is still dummy and does not contail business logic). Pocket PC should be soft-reset before the upload because the system uses the .dll file.

Step 7. Create panel object

Now we have created a dummy input method. In the next sections we will implement business logic. The main idea is having a bitmap with some zones. Each zone corresponds to a character.

We will create a class derived from CWnd implementing necessary behaviour. It will show the bitmap and control mouse clicks. Then we will insert the object in our SIP.

Create a bitmap resource 240x80 - it will be our SIP. Create a new class CSipPanel derived from CWnd.

Override OnPain method (WM_PAINT message) and draw the bitmap in this method:

void CSipPanel::OnPaint() { CPaintDC dc(this); // device context for painting CDC memDc; if (!memDc.CreateCompatibleDC(&dc)) return; m_bmpNormal.LoadBitmap(IDB_SIP_NORMAL); HBITMAP m_hOldBitmap = (HBITMAP)::SelectObject(memDc.GetSafeHdc(), m_bmpNormal); dc.BitBlt(0, 0, 240, 80, &memDc, 0, 0, SRCCOPY); ::SelectObject(memDc.GetSafeHdc(), m_hOldBitmap); memDc.DeleteDC(); m_bmpNormal.DeleteObject(); }

Add CSipPanel member in our input method. We will create it in Select method and destroy in Deselect.

STDMETHOD(Select)(HWND hwndSip) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) m_pSipPanel = new CSipPanel(); m_pSipPanel->CreateEx(0, NULL, _T("SampleSipPanel"), WS_VISIBLE, 0,0, 240, 80, hwndSip, NULL); return S_OK; }

Step 8. Using callback to generate character

If we want to work as a keyboard we have to put characters in the input queue. IIMCallback interface is used for that. The system gives us this interface by calling RegisterCallback method. We have to save given pointer into a member variable.

STDMETHOD(RegisterCallback)(IIMCallback * lpIMCallback) { m_callback = lpIMCallback; return S_OK; }

In my implementation I have to give callback interface to a panel. I have created RegisterCallback method in CSipPanel for that and call it when necessary from IInputMethod implementation.

Step 9. Handle mouse events

Now let's add mouse handlers. We will handle WM_LBUTTONUP event and call SendString method of the call back interface. My implementation is very simple:

void CSipPanel::OnLButtonUp(UINT nFlags, CPoint point) { if (m_callback==NULL) return; if (point.x<80) { TCHAR* s = _T("1"); m_callback->SendString(s, 1); return; } if (point.x<160) { TCHAR* s = _T("A"); m_callback->SendString(s, 1); return; } if (point.x<240) { TCHAR* s = _T("3"); m_callback->SendString(s, 1); return; } }

I think yours will contain a lot of business login, additional classes, additional bitmaps and much more.

Step 10. Input method works!

Now we have a working IM.

Related resources:

Discuss

Discuss this article. Here you can write your comments and read comments of other developers.
Rate this article:     Poor Excellent    
 12345 
© 2001-2005 Pocket PC Developer Network, a division of Spb Software House