Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4543 lines
113 KiB

/**************************************************************************\
* Module Name: softkbdc.cpp
*
* Copyright (c) 1985 - 2000, Microsoft Corporation
*
* Implementation of interface ISoftKbd
*
* History:
* 28-March-2000 weibz Created
\**************************************************************************/
#include "private.h"
#include "globals.h"
#include "SoftKbdc.h"
#include "softkbdui.h"
#define MAX_LABEL_LEN 20
/*******************************************************************************
*
* WstrToInt( )
*
* A utility function to convert a string to integer.
*
/********************************************************************************/
WORD WstrToInt(WCHAR *wszStr)
{
int ret, i;
if ( wszStr == NULL )
return 0;
ret = 0;
i = 0;
while ( wszStr[i] != L'\0' )
{
if ( (wszStr[i] < L'0') || (wszStr[i] > L'9') )
{
// this is not a legal string.
// just return back 0.
return 0;
}
ret = ret * 10 + (wszStr[i] - L'0');
i++;
}
return (WORD)ret;
}
/*******************************************************************************
*
* Constructor function:
*
* Initialize necessary data fields.
*
/********************************************************************************/
CSoftKbd::CSoftKbd( )
{
_lpCurKbdLayout = NULL;
_lpKbdLayoutDesList = NULL;
_wCurKbdLayoutID = NON_KEYBOARD;
_pSoftkbdUIWnd = NULL;
_hOwner = NULL;
_xReal = _yReal = _widthReal = _heightReal = 0;
_pDoc = NULL;
_pskbdwndes = NULL;
_TitleBar_Type = TITLEBAR_NONE;
_plfTextFont = NULL;
}
/*******************************************************************************
*
* Destructor
*
* Free all allocated memories.
*
/********************************************************************************/
CSoftKbd::~CSoftKbd( )
{
KBDLAYOUTDES *lpKbdLayoutDes;
KBDLAYOUTDES *lpLayoutDesTmp;
KEYMAP *lpKeyMapList;
int i, iState;
SafeRelease(_pDoc);
//
//
// Free Memory for soft keyboard layouts , and Label Text Mapping List
//
//
lpKbdLayoutDes = _lpKbdLayoutDesList;
while ( lpKbdLayoutDes != NULL )
{
KEYMAP *lpKeyMapListTmp;
lpKeyMapList = lpKbdLayoutDes->lpKeyMapList;
while ( lpKeyMapList != NULL )
{
for ( i=0; i<(int)(lpKeyMapList->wNumOfKeys); i++)
{
// free lppLabelText string for each state.
for ( iState=0; iState < lpKeyMapList->lpKeyLabels[i].wNumModComb; iState++)
{
if (lpKeyMapList->lpKeyLabels[i].lppLabelText[iState])
SysFreeString(lpKeyMapList->lpKeyLabels[i].lppLabelText[iState]);
}
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lpLabelDisp);
}
lpKeyMapListTmp = lpKeyMapList;
lpKeyMapList = lpKeyMapList->pNext;
SafeFreePointer(lpKeyMapListTmp);
}
lpLayoutDesTmp = lpKbdLayoutDes;
lpKbdLayoutDes = lpKbdLayoutDes->pNext;
SafeFreePointer(lpLayoutDesTmp);
}
if ( _plfTextFont )
SafeFreePointer(_plfTextFont);
// Destroy the window if the window is still active.
if ( _pSoftkbdUIWnd != NULL )
{
DestroySoftKeyboardWindow( );
_pSoftkbdUIWnd = NULL;
}
}
/*******************************************************************************
*
* Method function: _LoadDocumentSync( )
*
* Load an XML Document from the specified file or URL synchronously.
*
*
* fFileName is TRUE, means pBURL contains XML file path.
* fFilename is FALSE, means pBURL contains real XML content
*
/********************************************************************************/
HRESULT CSoftKbd::_LoadDocumentSync(BSTR pBURL, BOOL fFileName)
{
IXMLDOMParseError *pXMLError = NULL;
LONG errorCode = E_FAIL;
VARIANT vURL;
VARIANT_BOOL vb;
HRESULT hr;
if ( _pDoc == NULL ) {
return E_FAIL;
}
CHECKHR(_pDoc->put_async(VARIANT_FALSE));
// Load xml document from the given URL or file path
vURL.vt = VT_BSTR;
V_BSTR(&vURL) = pBURL;
if ( fFileName == TRUE )
{
CHECKHR(_pDoc->load(vURL, &vb));
}
else
{
CHECKHR(_pDoc->loadXML(pBURL, &vb) );
}
CHECKHR(_pDoc->get_parseError(&pXMLError));
CHECKHR(pXMLError->get_errorCode(&errorCode));
if (errorCode != 0)
{
hr = E_FAIL;
}
CleanUp:
SafeReleaseClear(pXMLError);
return hr;
}
/*******************************************************************************
*
* Method function: Initialize( )
*
* Initialize all necessary field for this class object.
* Generate Standard soft keyboard layouts.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::Initialize()
{
// initialize standard layouts
HRESULT hr = S_OK;
COLORTYPE crType;
// Initialize the different types of colors.
// Following types of colors are supported.
// bkcolor = 0 , for the window's back ground color
// UnSelForeColor = 1,
// UnSelTextColor = 2,
// SelForeColor = 3,
// SelTextColor = 4
crType = bkcolor;
_color[crType] = GetSysColor(COLOR_MENU);
crType = UnSelForeColor;
_color[crType] = GetSysColor(COLOR_MENU);
crType = UnSelTextColor;
_color[crType] = GetSysColor(COLOR_WINDOWTEXT);
crType = SelForeColor;
_color[crType] = GetSysColor(COLOR_MENU);
crType = SelTextColor;
_color[crType] = GetSysColor(COLOR_WINDOWTEXT);
CHECKHR(_CreateStandardSoftKbdLayout(SOFTKBD_US_STANDARD, L"IDSKD_STDUS101"));
CHECKHR(_CreateStandardSoftKbdLayout(SOFTKBD_EURO_STANDARD, L"IDSKD_STDEURO102"));
CHECKHR(_CreateStandardSoftKbdLayout(SOFTKBD_JPN_STANDARD, L"IDSKD_STDJPN106"));
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: _CreateStandardSoftKbdLayout( )
*
* Create standard soft keyboard layout.
*
* dwStdSoftKbdID, predefined Standard soft keyboard layout ID.
*
* wszStdResStr : Resource ID string for the created standard soft keyboard.
*
/********************************************************************************/
HRESULT CSoftKbd::_CreateStandardSoftKbdLayout(DWORD dwStdSoftKbdID, WCHAR *wszStdResStr )
{
KBDLAYOUTDES *pKbdLayout;
BYTE *lpszKeyboardDes;
WCHAR wszModuleFile[MAX_PATH];
CHAR szModuleFile[MAX_PATH];
CHAR szStdResStr[MAX_PATH]; // Ansi name of the Res Str ID
WCHAR wszInternalDesFileName[MAX_PATH];
HRESULT hr = S_OK;
HGLOBAL hResData = NULL;
HRSRC hRsRc = NULL;
DWORD dwFileLen;
DWORD dwResLen;
dwFileLen = GetModuleFileNameA(g_hInst, szModuleFile, MAX_PATH);
if ( dwFileLen == 0 )
{
hr = E_FAIL;
return hr;
}
MultiByteToWideChar(CP_ACP, 0, szModuleFile, -1,
wszModuleFile, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, wszStdResStr, -1,
szStdResStr, MAX_PATH, NULL, NULL );
hRsRc = FindResourceA(g_hInst,szStdResStr, "SKDFILE" );
if ( hRsRc == NULL ) return E_FAIL;
dwResLen = SizeofResource(g_hInst, hRsRc);
hResData = LoadResource(g_hInst, hRsRc);
if ( hResData == NULL ) return E_FAIL;
lpszKeyboardDes = (BYTE *)LockResource(hResData);
if ( lpszKeyboardDes == NULL ) return E_FAIL;
CHECKHR(_GenerateKeyboardLayoutFromSKD(lpszKeyboardDes, dwStdSoftKbdID, &pKbdLayout));
// Change the internal DesFile name as following format:
//
// SKDFILE: ResFileName : KBDResString to identify this layout's des file.
//
StringCchCopyW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), L"SKDFILE:");
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), wszModuleFile);
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), L":");
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), wszStdResStr );
StringCchCopyW(pKbdLayout->KbdLayoutDesFile, ARRAYSIZE(pKbdLayout->KbdLayoutDesFile), wszInternalDesFileName);
// link this new layout to the list.
if ( _lpKbdLayoutDesList == NULL ) {
_lpKbdLayoutDesList = pKbdLayout;
pKbdLayout->pNext = NULL;
}
else
{
pKbdLayout->pNext = _lpKbdLayoutDesList;
_lpKbdLayoutDesList = pKbdLayout;
}
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: EnumSoftKeyBoard( )
*
* Enumerate all possible soft keybaord layouts.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::EnumSoftKeyBoard(LANGID langid, DWORD *lpdwKeyboard)
{
/* The return value could be one of following:
SOFTKBD_US_STANDARD
SOFTKBD_US_ENHANCE
SOFTKBD_EURO_STANDARD
SOFTKBD_EURO_ENHANCE
SOFTKBD_JPN_STANDARD
SOFTKBD_JPN_ENHANCE
Any customized soft keyboard layout
SOFTKBD_NO_MORE.
*/
return S_OK;
}
/*******************************************************************************
*
* Method function: _GetXMLNodeValueWORD( )
*
* Get the WORD value for the specified Node.
*
*
/********************************************************************************/
HRESULT CSoftKbd::_GetXMLNodeValueWORD(IXMLDOMNode *pNode, WORD *lpWord)
{
HRESULT hr = S_OK;
IXMLDOMNode *pValueChild = NULL;
VARIANT value;
if ( (pNode == NULL) || (lpWord == NULL) )
{
hr = E_FAIL;
return hr;
}
CHECKHR(pNode->get_firstChild(&pValueChild));
CHECKHR(pValueChild->get_nodeValue(&value));
*lpWord = (WORD)WstrToInt(V_BSTR(&value));
VariantClear(&value);
CleanUp:
SafeRelease(pValueChild);
return hr;
}
/*******************************************************************************
*
* Method function: _ParseOneKeyInLayout( )
*
* Parse One Key in Layout Description, fill the data structure for
* the specified key.
*
*
/********************************************************************************/
HRESULT CSoftKbd::_ParseOneKeyInLayout(IXMLDOMNode *pNode, KEYDES *lpKeyDes)
{
HRESULT hr;
IXMLDOMNode *pAttrChild = NULL, *pKey = NULL, *pKeyNext = NULL;
BSTR nodeName=NULL;
IXMLDOMNamedNodeMap *pattrs=NULL;
BSTR name=NULL;
VARIANT value;
IXMLDOMNode *pValueChild=NULL;
hr = S_OK;
if ( (lpKeyDes == NULL) || (pNode == NULL) )
{
hr = E_FAIL;
return hr;
}
if (SUCCEEDED(pNode->get_attributes(&pattrs)) && pattrs != NULL)
{
CHECKHR(pattrs->nextNode(&pAttrChild));
while (pAttrChild)
{
CHECKHR(pAttrChild->get_nodeName(&name));
if ( wcscmp(name, xMODIFIER ) == 0 )
{
CHECKHR(pAttrChild->get_nodeValue(&value));
if (value.vt == VT_BSTR)
{
if ( wcscmp(V_BSTR(&value), xNONE) == 0 )
lpKeyDes->tModifier = none;
else if ( wcscmp(V_BSTR(&value), xCAPSLOCK) == 0 )
lpKeyDes->tModifier = CapsLock;
else if ( wcscmp(V_BSTR(&value), xSHIFT) == 0 )
lpKeyDes->tModifier = Shift;
else if ( wcscmp(V_BSTR(&value),xCTRL ) == 0 )
lpKeyDes->tModifier = Ctrl;
else if ( wcscmp(V_BSTR(&value), xATL) == 0 )
lpKeyDes->tModifier = Alt;
else if ( wcscmp(V_BSTR(&value), xALTGR) == 0 )
lpKeyDes->tModifier = AltGr;
else if ( wcscmp(V_BSTR(&value), xKANA) == 0 )
lpKeyDes->tModifier = Kana;
else if ( wcscmp(V_BSTR(&value), xNUMLOCK) == 0 )
lpKeyDes->tModifier = NumLock;
else
lpKeyDes->tModifier = none;
}
VariantClear(&value);
}
if ( name != NULL)
SysFreeString(name);
SafeReleaseClear(pAttrChild);
CHECKHR(pattrs->nextNode(&pAttrChild));
}
SafeReleaseClear(pattrs);
}
CHECKHR(pNode->get_firstChild(&pKey));
while ( pKey )
{
CHECKHR(pKey->get_nodeName(&nodeName));
CHECKHR(pKey->get_firstChild(&pValueChild));
CHECKHR(pValueChild->get_nodeValue(&value));
if ( wcscmp(nodeName, xKEYID ) == 0 )
{
lpKeyDes->keyId = WstrToInt(V_BSTR(&value));
}
else if ( wcscmp(nodeName,xLEFT ) == 0 )
{
lpKeyDes->wLeft = (WORD)WstrToInt(V_BSTR(&value));
}
else if ( wcscmp(nodeName, xTOP) == 0 )
{
lpKeyDes->wTop = WstrToInt(V_BSTR(&value));
}
else if ( wcscmp(nodeName, xWIDTH) == 0 )
{
lpKeyDes->wWidth = WstrToInt(V_BSTR(&value));
}
else if ( wcscmp(nodeName, xHEIGHT) == 0 )
{
lpKeyDes->wHeight = WstrToInt(V_BSTR(&value));
}
VariantClear(&value);
SafeReleaseClear(pValueChild);
if ( nodeName != NULL )
{
SysFreeString(nodeName);
nodeName = NULL;
}
CHECKHR(pKey->get_nextSibling(&pKeyNext));
SafeReleaseClear(pKey);
pKey = pKeyNext;
}
CleanUp:
if ( FAILED(hr) )
{
if ( nodeName != NULL )
{
SysFreeString(nodeName);
nodeName = NULL;
}
if ( pValueChild )
SafeReleaseClear(pValueChild);
if ( pKey )
SafeReleaseClear(pKey);
}
return hr;
}
/*******************************************************************************
*
* Method function: _ParseLayoutDescription( )
*
* Parse Layout description part in the XML file, and fill the internal
* Layout data structure.
*
/********************************************************************************/
HRESULT CSoftKbd::_ParseLayoutDescription(IXMLDOMNode *pLayoutChild, KBDLAYOUT *pLayout)
{
HRESULT hr = S_OK;
IXMLDOMNode *pNode = NULL;
IXMLDOMNode *pChild = NULL, *pNext = NULL, *pAttrChild=NULL;
BSTR nodeName=NULL;
IXMLDOMNamedNodeMap *pattrs=NULL;
BSTR name=NULL;
VARIANT value;
int iKey;
BSTR pBURL = NULL;
if ( (pLayoutChild == NULL) || (pLayout == NULL ) )
{
hr = E_FAIL;
return hr;
}
iKey = 0;
// Parse layout part.
if (SUCCEEDED(pLayoutChild->get_attributes(&pattrs)) && pattrs != NULL)
{
//
// Get the softkbe type attribute
//
CHECKHR(pattrs->nextNode(&pAttrChild));
while (pAttrChild)
{
CHECKHR(pAttrChild->get_nodeName(&name));
if ( wcscmp(name, xSOFTKBDTYPE) )
{
// this is not the right attribute.
if ( name != NULL)
{
SysFreeString(name);
name = NULL;
}
SafeReleaseClear(pAttrChild);
CHECKHR(pattrs->nextNode(&pAttrChild));
continue;
}
if ( name != NULL)
{
SysFreeString(name);
name = NULL;
}
CHECKHR(pAttrChild->get_nodeValue(&value));
if (value.vt == VT_BSTR)
{
if ( wcscmp(V_BSTR(&value), xTCUSTOMIZED) == 0 )
pLayout->fStandard = FALSE;
else
pLayout->fStandard = TRUE;
}
VariantClear(&value);
break;
}
SafeReleaseClear(pattrs);
}
CHECKHR(pLayoutChild->get_firstChild(&pChild));
pLayout->wLeft = 0;
pLayout->wTop = 0;
while ( pChild )
{
CHECKHR(pChild->get_nodeName(&nodeName));
if ( wcscmp(nodeName, xWIDTH) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(pLayout->wWidth) ));
}
else if ( wcscmp(nodeName, xHEIGHT) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(pLayout->wHeight) ));
}
else if ( wcscmp(nodeName, xMARGIN_WIDTH) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(pLayout->wMarginWidth )));
}
else if ( wcscmp(nodeName, xMARGIN_HEIGHT) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(pLayout->wMarginHeight) ));
}
else if ( wcscmp(nodeName, xKEYNUMBER) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(pLayout->wNumberOfKeys) ));
}
else if ( wcscmp(nodeName, xKEY) == 0 )
{
KEYDES *pKeyDes;
pKeyDes = &(pLayout->lpKeyDes[iKey]);
CHECKHR(_ParseOneKeyInLayout(pChild, pKeyDes) );
iKey++;
}
if (nodeName != NULL)
{
SysFreeString(nodeName);
nodeName = NULL;
}
CHECKHR(pChild->get_nextSibling(&pNext));
SafeReleaseClear(pChild);
pChild = pNext;
}
CleanUp:
if ( FAILED(hr) )
{
if (nodeName != NULL )
{
SysFreeString(nodeName);
nodeName = NULL;
}
if ( pChild )
SafeReleaseClear(pChild);
}
return hr;
}
/*******************************************************************************
*
* Method function: _ParseOneKeyInLabel( )
*
* Parse One Key in Label Description, fill the data structure for
* the specified key
*
*
/********************************************************************************/
HRESULT CSoftKbd::_ParseOneKeyInLabel(IXMLDOMNode *pNode, KEYLABELS *lpKeyLabels)
{
IXMLDOMNode *pValueChild = NULL;
HRESULT hr = S_OK;
IXMLDOMNode *pAttrChild = NULL, *pKey=NULL, *pKeyNext=NULL;
BSTR nodeName=NULL;
IXMLDOMNamedNodeMap *pattrs=NULL;
BSTR name=NULL;
VARIANT value;
int iState;
iState = 0;
if ( (pNode == NULL) || (lpKeyLabels == NULL) )
{
hr = E_FAIL;
return hr;
}
CHECKHR(pNode->get_firstChild(&pKey));
while ( pKey )
{
CHECKHR(pKey->get_nodeName(&nodeName));
CHECKHR(pKey->get_firstChild(&pValueChild));
CHECKHR(pValueChild->get_nodeValue(&value));
if ( wcscmp(nodeName, xKEYID) == 0 )
{
lpKeyLabels->keyId = WstrToInt(V_BSTR(&value));
}
else if ( wcscmp(nodeName, xVALIDSTATES) == 0 )
{
lpKeyLabels->wNumModComb = WstrToInt(V_BSTR(&value));
lpKeyLabels->lppLabelText = (BSTR *)cicMemAllocClear(
lpKeyLabels->wNumModComb * sizeof(BSTR) );
if ( lpKeyLabels->lppLabelText == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
lpKeyLabels->lpLabelType = (WORD *)cicMemAllocClear(
lpKeyLabels->wNumModComb * sizeof(WORD) );
if ( lpKeyLabels->lpLabelType == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
lpKeyLabels->lpLabelDisp = (WORD *)cicMemAllocClear(
lpKeyLabels->wNumModComb * sizeof(WORD) );
if ( lpKeyLabels->lpLabelDisp == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
}
else if ( wcscmp(nodeName, xLABELTEXT) == 0 )
{
if ( iState < lpKeyLabels->wNumModComb )
{
lpKeyLabels->lppLabelText[iState]=SysAllocString(V_BSTR(&value));
// set the default value for label type and label disp attribute.
lpKeyLabels->lpLabelType[iState] = LABEL_TEXT;
lpKeyLabels->lpLabelDisp[iState] = LABEL_DISP_ACTIVE;
// Get the label type: Text or Picture.
// if it is picture, the above string stands for path of bitmap file.
if (SUCCEEDED(pKey->get_attributes(&pattrs)) && pattrs != NULL)
{
CHECKHR(pattrs->nextNode(&pAttrChild));
while (pAttrChild)
{
CHECKHR(pAttrChild->get_nodeName(&name));
if ( wcscmp(name, xLABELTYPE) == 0 )
{
CHECKHR(pAttrChild->get_nodeValue(&value));
if (value.vt == VT_BSTR)
{
if ( wcscmp(V_BSTR(&value),xTEXT ) == 0 )
lpKeyLabels->lpLabelType[iState] = LABEL_TEXT;
else
lpKeyLabels->lpLabelType[iState] = LABEL_PICTURE;
}
VariantClear(&value);
}
else if ( wcscmp(name, xLABELDISP) == 0 )
{
CHECKHR(pAttrChild->get_nodeValue(&value));
if (value.vt == VT_BSTR)
{
if ( wcscmp(V_BSTR(&value),xGRAY ) == 0 )
lpKeyLabels->lpLabelDisp[iState] = LABEL_DISP_GRAY;
else
lpKeyLabels->lpLabelDisp[iState] = LABEL_DISP_ACTIVE;
}
VariantClear(&value);
}
if ( name != NULL)
{
SysFreeString(name);
name = NULL;
}
SafeReleaseClear(pAttrChild);
CHECKHR(pattrs->nextNode(&pAttrChild));
}
SafeReleaseClear(pattrs);
}
}
iState++;
}
VariantClear(&value);
SafeReleaseClear(pValueChild);
if ( nodeName != NULL)
{
SysFreeString(nodeName);
nodeName = NULL;
}
CHECKHR(pKey->get_nextSibling(&pKeyNext));
SafeRelease(pKey);
pKey = pKeyNext;
}
CleanUp:
if ( FAILED(hr) )
{
if ( pKey )
SafeReleaseClear(pKey);
if ( name != NULL)
{
SysFreeString(name);
name = NULL;
}
if ( pAttrChild )
SafeReleaseClear(pAttrChild);
if ( pValueChild )
SafeReleaseClear(pValueChild);
if ( lpKeyLabels->lppLabelText != NULL )
{
while ( iState >= 0 )
{
if ( lpKeyLabels->lppLabelText[iState] )
{
SysFreeString(lpKeyLabels->lppLabelText[iState]);
lpKeyLabels->lppLabelText[iState] = NULL;
}
iState --;
}
SafeFreePointer(lpKeyLabels->lppLabelText);
}
if ( lpKeyLabels->lpLabelType != NULL )
{
SafeFreePointer(lpKeyLabels->lpLabelType);
}
if ( lpKeyLabels->lpLabelDisp != NULL )
{
SafeFreePointer(lpKeyLabels->lpLabelDisp);
}
}
return hr;
}
/*******************************************************************************
*
* Method function: _ParseMappingDescription( )
*
* Parse Mapping description part in the XML file, and fill the internal
* Mapping Table structure.
*
/********************************************************************************/
HRESULT CSoftKbd::_ParseMappingDescription( IXMLDOMNode *pLabelChild, KEYMAP *lpKeyMapList )
{
HRESULT hr = S_OK;
IXMLDOMNode *pChild=NULL, *pNext=NULL;
BSTR nodeName=NULL;
int iKey;
BSTR pBURL = NULL;
// Parse for customized layout
if ( (pLabelChild == NULL) || (lpKeyMapList == NULL) )
{
hr = E_FAIL;
return hr;
}
iKey = 0;
CHECKHR(pLabelChild->get_firstChild(&pChild));
while ( pChild )
{
CHECKHR(pChild->get_nodeName(&nodeName));
if ( wcscmp(nodeName, xVALIDSTATES) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(lpKeyMapList->wNumModComb) ));
}
else if ( wcscmp(nodeName, xKEYNUMBER) == 0 )
{
CHECKHR(_GetXMLNodeValueWORD(pChild, &(lpKeyMapList->wNumOfKeys) ));
}
else if ( wcscmp(nodeName, xRESOURCEFILE) == 0 )
{
IXMLDOMNode *pValueChild;
VARIANT value;
CHECKHR(pChild->get_firstChild(&pValueChild));
if ( FAILED((pValueChild->get_nodeValue(&value))))
{
SafeRelease(pValueChild);
goto CleanUp;
}
StringCchCopyW(lpKeyMapList->wszResource, ARRAYSIZE(lpKeyMapList->wszResource), V_BSTR(&value) );
VariantClear(&value);
SafeRelease(pValueChild);
}
else if ( wcscmp(nodeName, xKEYLABEL) == 0 )
{
KEYLABELS *lpKeyLabels;
lpKeyLabels = &(lpKeyMapList->lpKeyLabels[iKey]);
CHECKHR(_ParseOneKeyInLabel(pChild, lpKeyLabels));
iKey++;
}
if ( nodeName != NULL)
{
SysFreeString(nodeName);
nodeName = NULL;
}
pChild->get_nextSibling(&pNext);
SafeReleaseClear(pChild);
pChild = pNext;
}
CleanUp:
if ( FAILED(hr) )
{
if ( nodeName != NULL)
{
SysFreeString(nodeName);
nodeName = NULL;
}
if ( pChild != NULL )
SafeReleaseClear(pChild);
if ( lpKeyMapList ) {
int i, iState;
for ( i=0; i<(int)(lpKeyMapList->wNumOfKeys); i++)
{
// free lppLabelText string for each state.
for ( iState=0; iState < lpKeyMapList->lpKeyLabels[i].wNumModComb; iState++)
{
if (lpKeyMapList->lpKeyLabels[i].lppLabelText[iState])
SysFreeString(lpKeyMapList->lpKeyLabels[i].lppLabelText[iState]);
}
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[i].lpLabelDisp);
}
}
}
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateMapDesFromSKD( )
*
* Generate Mapping description part in the KBD file, and fill the internal
* Mapping Table structure.
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateMapDesFromSKD(BYTE *pMapTable, KEYMAP *lpKeyMapList)
{
HRESULT hr = S_OK;
int iKey;
WORD wNumModComb;
WORD wNumOfKeys;
WORD *pMapPtr;
// Parse for customized layout
// Customized layout doesn't care about HKL, so there will be only one KeyMapList per layout.
if ( (pMapTable == NULL) || (lpKeyMapList == NULL) ) return E_FAIL;
pMapPtr = (WORD *)pMapTable;
wNumModComb = pMapPtr[0];
wNumOfKeys = pMapPtr[1];
pMapPtr += 2;
lpKeyMapList->wNumModComb = wNumModComb;
lpKeyMapList->wNumOfKeys = wNumOfKeys;
StringCchCopyW(lpKeyMapList->wszResource, ARRAYSIZE(lpKeyMapList->wszResource), (WCHAR *)pMapPtr);
pMapPtr += wcslen((WCHAR *)pMapPtr) + 1; // Plus NULL terminator
// Now strat to fill every Keylabel.
for ( iKey=0; iKey<wNumOfKeys; iKey++)
{
KEYLABELS *lpKeyLabel;
WORD wNumModInKey;
int jMod;
lpKeyLabel = &(lpKeyMapList->lpKeyLabels[iKey]);
lpKeyLabel->keyId = *pMapPtr;
pMapPtr += sizeof(KEYID)/sizeof(WORD);
wNumModInKey = *pMapPtr;
pMapPtr++;
lpKeyLabel->wNumModComb = wNumModInKey;
lpKeyLabel->lppLabelText=(BSTR *)cicMemAllocClear(lpKeyLabel->wNumModComb * sizeof(BSTR) );
if ( lpKeyLabel->lppLabelText == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
lpKeyLabel->lpLabelType = (WORD *)cicMemAllocClear(lpKeyLabel->wNumModComb * sizeof(WORD) );
if ( lpKeyLabel->lpLabelType == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
lpKeyLabel->lpLabelDisp = (WORD *)cicMemAllocClear(lpKeyLabel->wNumModComb * sizeof(WORD));
if ( lpKeyLabel->lpLabelDisp == NULL )
{
// Not enough memory.
// release all allocated memory.
hr = E_OUTOFMEMORY;
goto CleanUp;
}
for ( jMod=0; jMod < wNumModInKey; jMod++)
{
lpKeyLabel->lppLabelText[jMod] = SysAllocString( pMapPtr );
pMapPtr += wcslen(pMapPtr) + 1;
}
CopyMemory(lpKeyLabel->lpLabelType, pMapPtr, wNumModInKey * sizeof(WORD) );
pMapPtr += wNumModInKey;
CopyMemory(lpKeyLabel->lpLabelDisp, pMapPtr, wNumModInKey * sizeof(WORD) );
pMapPtr += wNumModInKey;
}
CleanUp:
if ( FAILED(hr) )
{
// Release all allocated memory in this function.
int i;
for (i=0; i<=iKey; i++)
{
KEYLABELS *lpKeyLabel;
int jMod;
if (lpKeyLabel = &(lpKeyMapList->lpKeyLabels[i]))
{
// free lppLabelText string for each state.
for ( jMod=0; jMod<lpKeyLabel->wNumModComb; jMod++)
{
if (lpKeyLabel->lppLabelText && lpKeyLabel->lppLabelText[jMod])
SysFreeString(lpKeyLabel->lppLabelText[jMod]);
}
SafeFreePointer(lpKeyLabel->lppLabelText);
SafeFreePointer(lpKeyLabel->lpLabelType);
SafeFreePointer(lpKeyLabel->lpLabelDisp);
}
}
}
return hr;
}
/*******************************************************************************
*
* Method function: ParseKeyboardLayout( )
*
* Parse Keyboard Layout description XML file, and fill the internal
* Layout and Mapping Table structure.
*
* if fFileName is TRUE, means lpszKeyboardDesFile stands for a file name
* if it is FALSE, lpszKeyboardDesFile points to the real memory block which
* contains XML content.
/********************************************************************************/
HRESULT CSoftKbd::_ParseKeyboardLayout(BOOL fFileName, WCHAR *lpszKeyboardDesFile, DWORD dwKbdLayoutID, KBDLAYOUTDES **lppKbdLayout )
{
KBDLAYOUTDES *pKbdLayout = NULL;
KBDLAYOUT *pLayout = NULL;
IXMLDOMNode *pNode = NULL;
IXMLDOMNode *pLayoutChild =NULL, *pLabelChild = NULL, *pNext = NULL, *pRoot=NULL ;
BSTR nodeName=NULL;
KEYMAP *lpKeyMapList = NULL;
BSTR pBURL = NULL;
HRESULT hr = S_OK;
if ( (lpszKeyboardDesFile == NULL) || ( lppKbdLayout == NULL) )
{
//
// this is not appropriate parameter.
//
hr = E_FAIL;
return hr;
}
if ( _pDoc == NULL )
{
// the first time this method is called.
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&_pDoc);
if ( FAILED(hr) )
return hr;
}
pKbdLayout = (KBDLAYOUTDES *)cicMemAllocClear(sizeof(KBDLAYOUTDES) );
if ( pKbdLayout == NULL )
{
hr = E_OUTOFMEMORY;
return hr;
}
pKbdLayout->wKbdLayoutID = dwKbdLayoutID;
pKbdLayout->ModifierStatus = 0;
pKbdLayout->CurModiState = 0;
pKbdLayout->lpKeyMapList = NULL;
if ( fFileName == TRUE )
StringCchCopyW(pKbdLayout->KbdLayoutDesFile, ARRAYSIZE(pKbdLayout->KbdLayoutDesFile), lpszKeyboardDesFile );
else
{
//
// we just set "_string" at this moment,
// after this function returns, the caller needs to set the real
// file path + resource ID as its new desfilepath.
//
wcscpy(pKbdLayout->KbdLayoutDesFile, L"_String");
}
pLayout = &(pKbdLayout->kbdLayout);
if ( fFileName == TRUE )
pBURL = SysAllocString(lpszKeyboardDesFile);
else
pBURL = lpszKeyboardDesFile;
CHECKHR(_LoadDocumentSync(pBURL, fFileName));
CHECKHR(_pDoc->QueryInterface(IID_IXMLDOMNode,(void**)&pNode));
CHECKHR(pNode->get_firstChild(&pRoot));
CHECKHR(pRoot->get_nodeName(&nodeName));
// Get the Root node
while ( wcscmp(nodeName, xSOFTKBDDES) ) {
pRoot->get_nextSibling(&pNext);
pRoot->Release();
pRoot = pNext;
if ( nodeName != NULL )
SysFreeString(nodeName);
pRoot->get_nodeName(&nodeName);
}
if ( nodeName != NULL )
SysFreeString(nodeName);
// Get the layout child and label child,
pLayoutChild = pLabelChild = NULL;
pRoot->get_firstChild(&pLayoutChild);
if ( pLayoutChild != NULL )
pLayoutChild->get_nextSibling(&pLabelChild);
CHECKHR(_ParseLayoutDescription(pLayoutChild, pLayout) );
// Handle Label part.
if ( pLayout->fStandard == TRUE )
{
//
// Generate mapping table for standard layout
//
// Mapping table is generated by SetKeyboardLabelText( ) method.
goto CleanUp;
}
if ( pLabelChild == NULL )
{
// the XML file is not complete.
hr = E_FAIL;
goto CleanUp;
}
lpKeyMapList = (KEYMAP *)cicMemAllocClear(sizeof(KEYMAP) );
if ( lpKeyMapList == NULL )
{
SafeFreePointer(pKbdLayout);
hr = E_OUTOFMEMORY;
goto CleanUp;
}
CHECKHR(_ParseMappingDescription(pLabelChild, lpKeyMapList));
pKbdLayout->lpKeyMapList = lpKeyMapList;
CleanUp:
SafeReleaseClear(pLayoutChild);
if ( pLabelChild != NULL )
pLabelChild->Release( );
SafeReleaseClear(pRoot);
SafeReleaseClear(pNode);
if ( fFileName == TRUE )
SysFreeString(pBURL);
if ( FAILED(hr) )
{
if ( pKbdLayout != NULL )
SafeFreePointer(pKbdLayout);
if ( lpKeyMapList != NULL )
SafeFreePointer( lpKeyMapList );
}
else
{
if ( lppKbdLayout != NULL )
*lppKbdLayout = pKbdLayout;
}
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateKeyboardLayoutFromSKD( )
*
* KBD file is a precompiled xml file, it is binary format, This KBD has been put
* into the resource section of DLL, the resource type is SKDFILE.
*
* This method function will read the resource content and try to fill the internal
* Layout and Mapping Table structure.
*
********************************************************************************/
HRESULT CSoftKbd::_GenerateKeyboardLayoutFromSKD(BYTE *lpszKeyboardDes, DWORD dwKbdLayoutID, KBDLAYOUTDES **lppKbdLayout)
{
KBDLAYOUTDES *pKbdLayout = NULL;
KBDLAYOUT *pLayout = NULL;
BYTE *pMapTable = NULL;
KEYMAP *lpKeyMapList = NULL;
WORD wNumberOfKeys, wLenLayout;
HRESULT hr = S_OK;
if ( (lpszKeyboardDes == NULL) || ( lppKbdLayout == NULL) )
{
//
// this is not appropriate parameter.
//
return E_FAIL;
}
pKbdLayout = (KBDLAYOUTDES *)cicMemAllocClear(sizeof(KBDLAYOUTDES) );
if ( pKbdLayout == NULL )
{
hr = E_OUTOFMEMORY;
return hr;
}
pKbdLayout->wKbdLayoutID = dwKbdLayoutID;
pKbdLayout->ModifierStatus = 0;
pKbdLayout->CurModiState = 0;
pKbdLayout->lpKeyMapList = NULL;
//
// we just set "_string" at this moment,
// after this function returns, the caller needs to set the real
// file path + resource ID as its new desfilepath.
//
wcscpy(pKbdLayout->KbdLayoutDesFile, L"_String");
pLayout = &(pKbdLayout->kbdLayout);
// Fill the layout internal structure from lpszKeyboardDes.
wNumberOfKeys = *(lpszKeyboardDes + sizeof(WORD) * 6 + sizeof(BOOL));
wLenLayout = sizeof(WORD) * 7 + sizeof(BOOL) + wNumberOfKeys * sizeof(KEYDES);
CopyMemory(pLayout, lpszKeyboardDes, wLenLayout);
// Handle Label part.
if ( pLayout->fStandard == TRUE )
{
// Mapping table is generated later by SetKeyboardLabelText( ) method.
goto CleanUp;
}
lpKeyMapList=(KEYMAP *)cicMemAllocClear(sizeof(KEYMAP));
if ( lpKeyMapList == NULL )
{
SafeFreePointer(pKbdLayout);
hr = E_OUTOFMEMORY;
goto CleanUp;
}
//Get the start position of Mapping Table content.
pMapTable = lpszKeyboardDes + wLenLayout;
CHECKHR(_GenerateMapDesFromSKD(pMapTable, lpKeyMapList));
pKbdLayout->lpKeyMapList = lpKeyMapList;
CleanUp:
if ( FAILED(hr) )
{
if ( pKbdLayout != NULL )
SafeFreePointer(pKbdLayout);
if ( lpKeyMapList != NULL )
SafeFreePointer( lpKeyMapList );
}
else
{
if ( lppKbdLayout != NULL )
*lppKbdLayout = pKbdLayout;
}
return hr;
}
/*******************************************************************************
*
* Method function: CreateSoftKeyboardLayoutFromXMLFile( )
*
* Create the real Soft Keyboard layout based on specified description XML file.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::CreateSoftKeyboardLayoutFromXMLFile(WCHAR *lpszKeyboardDesFile,INT szFileStrLen, DWORD *pdwLayoutCookie)
{
DWORD dwCurKbdLayoutID;
KBDLAYOUTDES *pKbdLayout=NULL;
HRESULT hr = S_OK;
dwCurKbdLayoutID = SOFTKBD_CUSTOMIZE_BEGIN;
if ( _lpKbdLayoutDesList != NULL )
{
// check if this des file is alreay parsed.
pKbdLayout = _lpKbdLayoutDesList;
while ( pKbdLayout != NULL ) {
if ( pKbdLayout->wKbdLayoutID > dwCurKbdLayoutID )
dwCurKbdLayoutID = pKbdLayout->wKbdLayoutID;
if ( wcscmp(pKbdLayout->KbdLayoutDesFile, lpszKeyboardDesFile) == 0 )
{
// find it.
*pdwLayoutCookie = pKbdLayout->wKbdLayoutID;
hr = S_OK;
return hr;
}
pKbdLayout = pKbdLayout->pNext;
}
}
// this is a new des file
dwCurKbdLayoutID ++;
CHECKHR(_ParseKeyboardLayout(TRUE, lpszKeyboardDesFile, dwCurKbdLayoutID, &pKbdLayout));
// link this new layout to the list.
pKbdLayout->CurModiState = 0; // use state 0 as initialization
if ( _lpKbdLayoutDesList == NULL ) {
_lpKbdLayoutDesList = pKbdLayout;
pKbdLayout->pNext = NULL;
}
else
{
pKbdLayout->pNext = _lpKbdLayoutDesList;
_lpKbdLayoutDesList = pKbdLayout;
}
*pdwLayoutCookie = pKbdLayout->wKbdLayoutID;
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: CreateSoftKeyboardLayoutFromResource( )
*
* Create the real Soft Keyboard layout based on XML content in resource section
* There will be two kinds of resouces, XMLFILE, and SKDFILE, SKDFILE is a
* Precomipled XML binary file.
*
* lpszResFile : path of file which contains XML content in its resource.
* lpszResString : resource string identifier for the XML or KBD resource.
*
* the resource Type could be either "XMLFILE" or "SKDFILE"
*
* lpdwLayoutCookie: receive the returned layout id.
*
/********************************************************************************/
HRESULT CSoftKbd::CreateSoftKeyboardLayoutFromResource(WCHAR *lpszResFile, WCHAR *lpszResType, WCHAR *lpszResString, DWORD *lpdwLayoutCookie)
{
DWORD dwCurKbdLayoutID;
KBDLAYOUTDES *pKbdLayout=NULL;
WCHAR *lpszKeyboardDesFile=NULL;
WCHAR wszInternalDesFileName[MAX_PATH];
CHAR lpszAnsiResString[MAX_PATH];
CHAR lpszAnsiResFile[MAX_PATH];
CHAR lpszAnsiResType[MAX_PATH];
HMODULE hResFile = NULL;
HRSRC hRsRc = NULL;
HGLOBAL hResData = NULL;
HRESULT hr = S_OK;
BOOL fXMLUnicode=TRUE;
DWORD dwResLen;
if ( (lpszResFile == NULL) || (lpszResString == NULL) || (lpszResType == NULL) || ( lpdwLayoutCookie == NULL) )
{
hr = E_FAIL;
return hr;
}
//
// Generate internal DesFile Name
//
StringCchCopyW(wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), lpszResType);
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), L":");
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), lpszResFile );
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), L":");
StringCchCatW( wszInternalDesFileName, ARRAYSIZE(wszInternalDesFileName), lpszResString );
dwCurKbdLayoutID = SOFTKBD_CUSTOMIZE_BEGIN;
if ( _lpKbdLayoutDesList != NULL )
{
// check if this des file is alreay parsed.
pKbdLayout = _lpKbdLayoutDesList;
while ( pKbdLayout != NULL ) {
if ( pKbdLayout->wKbdLayoutID > dwCurKbdLayoutID )
dwCurKbdLayoutID = pKbdLayout->wKbdLayoutID;
if ( wcscmp(pKbdLayout->KbdLayoutDesFile, wszInternalDesFileName) == 0 )
{
// find it.
*lpdwLayoutCookie = pKbdLayout->wKbdLayoutID;
hr = S_OK;
return hr;
}
pKbdLayout = pKbdLayout->pNext;
}
}
// this is a new des file
dwCurKbdLayoutID ++;
WideCharToMultiByte(CP_ACP, 0, lpszResFile, -1,
lpszAnsiResFile, MAX_PATH, NULL, NULL );
hResFile = LoadLibraryA(lpszAnsiResFile);
if ( hResFile == NULL )
{
hr = E_FAIL;
goto CleanUp;
}
WideCharToMultiByte(CP_ACP, 0, lpszResString, -1,
lpszAnsiResString, MAX_PATH, NULL, NULL );
WideCharToMultiByte(CP_ACP, 0, lpszResType, -1,
lpszAnsiResType, MAX_PATH, NULL, NULL );
hRsRc = FindResourceA(hResFile, lpszAnsiResString, lpszAnsiResType );
if ( hRsRc == NULL )
{
hr = E_FAIL;
goto CleanUp;
}
dwResLen = SizeofResource(hResFile, hRsRc);
hResData = LoadResource(hResFile, hRsRc );
if ( hResData == NULL )
{
hr = E_FAIL;
goto CleanUp;
}
lpszKeyboardDesFile = (WCHAR *)LockResource(hResData);
if ( lpszKeyboardDesFile == NULL )
{
hr = E_FAIL;
goto CleanUp;
}
if ( wcscmp(lpszResType, L"SKDFILE") == 0 )
{
CHECKHR(_GenerateKeyboardLayoutFromSKD((BYTE *)lpszKeyboardDesFile, dwCurKbdLayoutID, &pKbdLayout));
}
else if ( wcscmp(lpszResType, L"XMLFILE") == 0 )
{
// This is XMLFILE resource
//
// we assume the XML content in resource is in Unicode format.
//
if ( lpszKeyboardDesFile[0] == 0xFEFF )
{
fXMLUnicode = TRUE;
lpszKeyboardDesFile = lpszKeyboardDesFile + 1;
}
else
{
// if the content is UTF-8, we need to translate the string to Unicode
//
char *lpszXMLContentUtf8;
int iSize;
lpszXMLContentUtf8 = (char *)lpszKeyboardDesFile;
lpszKeyboardDesFile = NULL;
iSize = _Utf8ToUnicode(lpszXMLContentUtf8, dwResLen ,NULL, 0 );
if ( iSize == 0 )
{
hr = E_FAIL;
goto CleanUp;
}
fXMLUnicode = FALSE;
lpszKeyboardDesFile = (WCHAR *) cicMemAllocClear( (iSize+1) * sizeof(WCHAR) );
if ( lpszKeyboardDesFile == NULL )
{
hr = E_FAIL;
goto CleanUp;
}
iSize = _Utf8ToUnicode(lpszXMLContentUtf8, dwResLen,lpszKeyboardDesFile, iSize+1 );
if ( iSize == 0 )
{
hr = E_FAIL;
goto CleanUp;
}
lpszKeyboardDesFile[iSize] = L'\0';
}
CHECKHR(_ParseKeyboardLayout(FALSE, lpszKeyboardDesFile, dwCurKbdLayoutID, &pKbdLayout));
}
else
{
// This resource type is not supported.
hr = E_FAIL;
goto CleanUp;
}
// Change the internal DesFile name as following format:
//
// XMLRES: ResFileName : XMLResString to identify this layout's des file.
// Or
// KBDRES: ResFileName : KBDResString
//
wcscpy(pKbdLayout->KbdLayoutDesFile, wszInternalDesFileName);
// link this new layout to the list.
pKbdLayout->CurModiState = 0; // use state 0 as initialization
if ( _lpKbdLayoutDesList == NULL ) {
_lpKbdLayoutDesList = pKbdLayout;
pKbdLayout->pNext = NULL;
}
else
{
pKbdLayout->pNext = _lpKbdLayoutDesList;
_lpKbdLayoutDesList = pKbdLayout;
}
*lpdwLayoutCookie = pKbdLayout->wKbdLayoutID;
CleanUp:
if ( hResFile != NULL )
FreeLibrary(hResFile);
if ( (fXMLUnicode == FALSE) && ( lpszKeyboardDesFile != NULL ) )
SafeFreePointer(lpszKeyboardDesFile);
return hr;
}
HRESULT CSoftKbd::_GenerateRealKbdLayout( )
{
float fWidRat, fHigRat;
INT i;
KBDLAYOUT *realKbdLayout;
HRESULT hr;
WORD skbd_x, skbd_y, skbd_width, skbd_height;
BOOL fNewTitleSize = FALSE;
hr = S_OK;
if ( (_xReal == 0) &&
(_yReal == 0 ) &&
(_widthReal == 0) &&
(_heightReal == 0) )
{
//
// means CreateSoftKeyboardWindow( ) has not been called yet
// we don't do more things.
//
return hr;
}
//
// The soft keyboard window has already been created, and the window size is set,
// generate realKbdLayout by extending or shrinking the key size from the size
// specified in the des file.
//
// check if there is SoftKeyboard Layout is set.
//
if ( _wCurKbdLayoutID == NON_KEYBOARD || _lpCurKbdLayout == NULL )
{
//
// No layout is selected.
//
return hr;
}
// Generate the titlebar rect size, and button panel rectangle size.
// Keep the relative postion. ( window client coordinate )
switch ( _TitleBar_Type )
{
case TITLEBAR_NONE :
_TitleBarRect.left = 0;
_TitleBarRect.top = 0;
_TitleBarRect.right = 0;
_TitleBarRect.bottom = 0;
break;
case TITLEBAR_GRIPPER_HORIZ_ONLY :
_TitleBarRect.left = 0;
_TitleBarRect.top = 0;
_TitleBarRect.right = _TitleBarRect.left + _widthReal - 1;
_TitleBarRect.bottom = _TitleBarRect.top + 6;
break;
case TITLEBAR_GRIPPER_VERTI_ONLY :
_TitleBarRect.left = 0;
_TitleBarRect.top = 0;
_TitleBarRect.right = _TitleBarRect.left + 6;
_TitleBarRect.bottom = _TitleBarRect.top + _heightReal - 1;
break;
case TITLEBAR_GRIPPER_BUTTON :
// assume to use horizontal title bar.
_TitleBarRect.left = 0;
_TitleBarRect.top = 0;
_TitleBarRect.right = _TitleBarRect.left + _widthReal - 1;
_TitleBarRect.bottom = _TitleBarRect.top + 16;
fNewTitleSize = TRUE;
break;
}
if ( (_TitleBarRect.right - _TitleBarRect.left + 1) == _widthReal )
{
// This is a horizontal titlebar
skbd_x = 0;
skbd_y = (WORD)_TitleBarRect.bottom + 1;
skbd_width = (WORD)_widthReal;
skbd_height = (WORD)_heightReal - (WORD)(_TitleBarRect.bottom - _TitleBarRect.top + 1 );
}
else if ((_TitleBarRect.bottom - _TitleBarRect.top + 1) == _heightReal )
{
// This is a vertical titlebar.
skbd_y = 0;
skbd_x = (WORD)_TitleBarRect.right + 1;
skbd_height = (WORD)_heightReal;
skbd_width = (WORD)_widthReal - (WORD)(_TitleBarRect.right - _TitleBarRect.left + 1 );
}
else
{
// there is no titlebar
skbd_x = 0;
skbd_y = 0;
skbd_height = (WORD)_heightReal;
skbd_width = (WORD) _widthReal;
}
realKbdLayout = &( _lpCurKbdLayout->kbdLayout );
if ( (realKbdLayout->wWidth == skbd_width) && (realKbdLayout->wHeight == skbd_height) )
{
// this keyboard layout has been already adjusted.
//
hr = S_OK;
return hr;
}
if ( (realKbdLayout->wWidth == 0) || ( realKbdLayout->wHeight==0) )
{
Assert(0);
hr = E_FAIL;
return hr;
}
fWidRat = (float)skbd_width / (float)realKbdLayout->wWidth;
fHigRat = (float)(skbd_height) / (float) realKbdLayout->wHeight;
// Adjust every key's size
realKbdLayout->wMarginWidth = (WORD)((float)realKbdLayout->wMarginWidth * fWidRat);
realKbdLayout->wMarginHeight = (WORD)((float)realKbdLayout->wMarginHeight * fHigRat);
for ( i=0; i< realKbdLayout->wNumberOfKeys; i++ )
{
WORD wLeft;
WORD wTop;
WORD wWidth;
WORD wHeight;
wLeft = (WORD)((float)(realKbdLayout->lpKeyDes[i].wLeft - realKbdLayout->wLeft ) * fWidRat);
wTop = (WORD)((float)(realKbdLayout->lpKeyDes[i].wTop - realKbdLayout->wTop) * fHigRat);
wWidth = (WORD)((float)realKbdLayout->lpKeyDes[i].wWidth * fWidRat);
wHeight = (WORD)((float)realKbdLayout->lpKeyDes[i].wHeight * fHigRat);
realKbdLayout->lpKeyDes[i].wLeft = wLeft + skbd_x;
realKbdLayout->lpKeyDes[i].wTop = wTop + skbd_y;
realKbdLayout->lpKeyDes[i].wWidth = wWidth;
realKbdLayout->lpKeyDes[i].wHeight = wHeight;
}
realKbdLayout->wLeft = (WORD)skbd_x;
realKbdLayout->wTop = (WORD)skbd_y;
realKbdLayout->wWidth = (WORD)skbd_width;
realKbdLayout->wHeight = (WORD)skbd_height;
if ( fNewTitleSize )
{
_TitleBarRect.left = realKbdLayout->lpKeyDes[0].wLeft;
_TitleBarRect.right = realKbdLayout->lpKeyDes[realKbdLayout->wNumberOfKeys-1].wLeft +
realKbdLayout->lpKeyDes[realKbdLayout->wNumberOfKeys-1].wWidth - 1;
}
return hr;
}
/*******************************************************************************
*
* Method function: SelectSoftKeyboard( )
*
* Select current Active soft keyboard layout.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::SelectSoftKeyboard(DWORD dwKeyboardId)
{
HRESULT hr;
KBDLAYOUTDES *pKbdLayout;
hr = S_OK;
if ( _wCurKbdLayoutID == dwKeyboardId )
return hr;
pKbdLayout = _lpKbdLayoutDesList;
while ( pKbdLayout != NULL ) {
if ( pKbdLayout->wKbdLayoutID == dwKeyboardId )
break;
pKbdLayout = pKbdLayout->pNext;
}
if ( pKbdLayout == NULL )
{
//
// Cannot find this keyboard layout
//
hr = E_FAIL;
return hr;
}
_lpCurKbdLayout = pKbdLayout;
_wCurKbdLayoutID = dwKeyboardId;
// initialize realKbdLayout
hr = _GenerateRealKbdLayout( );
if ( _pSoftkbdUIWnd )
{
hr=_pSoftkbdUIWnd->_GenerateWindowLayout( );
}
return hr;
}
/*******************************************************************************
*
* Method function: _SetStandardLabelText( )
*
* Generate mapping table in a certain modifier status for a standard soft
* keyboard.
*
/********************************************************************************/
HRESULT CSoftKbd::_SetStandardLabelText(LPBYTE pKeyState, KBDLAYOUT *realKbdLayout,
KEYMAP *lpKeyMapList, int iState)
{
UINT i, j, nKeyNum;
UINT uVirtkey, uScanCode;
HRESULT hr;
hr = S_OK;
nKeyNum = (UINT)(realKbdLayout->wNumberOfKeys);
// fill _CurLabel
for ( i=0; i<nKeyNum; i++) {
// Assume the KEYID is scancode.
WCHAR szLabel[MAX_LABEL_LEN];
int iRet, jIndex;
KEYID keyId;
BOOL fPitcureKey;
PICTUREKEY *pPictureKeys;
switch ( _wCurKbdLayoutID ) {
case SOFTKBD_JPN_STANDARD :
case SOFTKBD_JPN_ENHANCE :
pPictureKeys = gJpnPictureKeys;
break;
case SOFTKBD_US_STANDARD :
case SOFTKBD_US_ENHANCE :
case SOFTKBD_EURO_STANDARD :
case SOFTKBD_EURO_ENHANCE :
pPictureKeys = gPictureKeys;
break;
}
keyId = lpKeyMapList->lpKeyLabels[i].keyId = realKbdLayout->lpKeyDes[i].keyId;
fPitcureKey = FALSE;
for ( j=0; j<NUM_PICTURE_KEYS; j++)
{
if ( pPictureKeys[j].uScanCode == keyId )
{
// this is a picture key.
fPitcureKey = TRUE;
jIndex = j;
break;
}
if ( pPictureKeys[j].uScanCode == 0 )
{
// This is the last item in pPictureKeys.
break;
}
}
if ( fPitcureKey )
{
lpKeyMapList->lpKeyLabels[i].lpLabelType[iState] = LABEL_PICTURE;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp[iState] = LABEL_DISP_ACTIVE;
lpKeyMapList->lpKeyLabels[i].lppLabelText[iState] = SysAllocString(pPictureKeys[jIndex].PictBitmap);
}
else
{
// All others are text labels. and have different strings for
// different modifier combination statets.
//
UINT uScanSpace = 0x39;
int iLabelSize;
BOOL fFunctKey;
uScanCode = realKbdLayout->lpKeyDes[i].keyId;
uVirtkey = MapVirtualKeyEx(uScanCode, 1, _lpCurKbdLayout->CurhKl);
fFunctKey = FALSE;
// For the Function keys, we just use the hard code string to set
// them as F1, F2, F3, ..... F12.
WCHAR wszFuncKey[MAX_LABEL_LEN];
wszFuncKey[0] = L'F';
switch (uScanCode) {
case KID_F1 :
case KID_F2 :
case KID_F3 :
case KID_F4 :
case KID_F5 :
case KID_F6 :
case KID_F7 :
case KID_F8 :
case KID_F9 :
wszFuncKey[1] = L'0' + uScanCode - KID_F1 + 1;
wszFuncKey[2] = L'\0';
wcscpy(szLabel, wszFuncKey);
fFunctKey = TRUE;
break;
case KID_F10 :
wcscpy(szLabel, L"F10");
fFunctKey = TRUE;
break;
case KID_F11 :
wcscpy(szLabel, L"F11");
fFunctKey = TRUE;
break;
case KID_F12 :
wcscpy(szLabel, L"F12");
fFunctKey = TRUE;
break;
default :
break;
}
if ( fFunctKey == TRUE )
{
lpKeyMapList->lpKeyLabels[i].lppLabelText[iState] = SysAllocString(szLabel);
lpKeyMapList->lpKeyLabels[i].lpLabelType[iState] = LABEL_TEXT;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp[iState] = LABEL_DISP_ACTIVE;
continue;
}
if ( IsOnNT( ) )
{
iRet = ToUnicodeEx(uVirtkey, uScanCode | 0x80, pKeyState, szLabel, (int)(sizeof(szLabel)/sizeof(WCHAR)), 0, _lpCurKbdLayout->CurhKl);
if ( iRet == 2 )
{
// it is possible to have previous dead key, flush again.
iRet = ToUnicodeEx(uVirtkey, uScanCode | 0x80, pKeyState, szLabel, (int)(sizeof(szLabel)/sizeof(WCHAR)), 0, _lpCurKbdLayout->CurhKl);
}
iLabelSize = iRet;
}
else
{
// Win9x doesn't support ToUnicodeEx, we just use alternative ToAsciiEx.
char szLabelAnsi[MAX_LABEL_LEN];
iRet = ToAsciiEx(uVirtkey, uScanCode | 0x80, pKeyState, (LPWORD)szLabelAnsi, 0, _lpCurKbdLayout->CurhKl);
if ( iRet == 2 )
{
// it is possible to have previous dead key, flush again.
iRet = ToAsciiEx(uVirtkey, uScanCode | 0x80, pKeyState, (LPWORD)szLabelAnsi, 0, _lpCurKbdLayout->CurhKl);
}
if ( iRet != 0 )
{
//
// Translate the ANSI label to Unicode based on ACP ... or other?
//
if ( iRet == -1 ) // dead key, one character is written to szLabelAnsi buffer.
szLabelAnsi[1] = '\0';
else
szLabelAnsi[iRet] = '\0';
iLabelSize = MultiByteToWideChar(CP_ACP, 0, szLabelAnsi, -1, szLabel, MAX_LABEL_LEN );
}
}
if ( iRet <= 0 )
{
iLabelSize = 1;
if ( iRet == 0 )
{
// Means no translation for this key at this shift state.
// We will display empty label, or space on the button.
szLabel[0] = 0x20;
}
}
szLabel[iLabelSize] = L'\0';
lpKeyMapList->lpKeyLabels[i].lppLabelText[iState] = SysAllocString(szLabel);
lpKeyMapList->lpKeyLabels[i].lpLabelType[iState] = LABEL_TEXT;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp[iState] = LABEL_DISP_ACTIVE;
}
}
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateUSStandardLabel( )
*
* Generate all mapping labels in different modifier status for US standard
* soft keyboard.
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateUSStandardLabel( )
{
//
// there are 4 different states for keyboard labels.
//
// state 0 : no any modifier key pressed
// state 1 : Caps On.
// state 2 : Shift pressed. Caps Off
// state 3 : Shift Pressed, Caps On
//
// check to see if this soft keyboard support specified HKL.
//
// ???
//
KEYMAP *lpKeyMapList;
HRESULT hr;
WORD wNumModComb, wNumOfKeys;
int i, j;
int iState;
BYTE lpKeyState[256], lpCurKeyState[256];
KBDLAYOUT *realKbdLayut;
hr = S_OK;
if ( _lpCurKbdLayout->lpKeyMapList != NULL )
{
// If the mapping table for the specified HKL has already been created,
// Just return it.
HKL CurhKl;
CurhKl = _lpCurKbdLayout->CurhKl;
lpKeyMapList = _lpCurKbdLayout->lpKeyMapList;
while ( lpKeyMapList != NULL )
{
if ( lpKeyMapList->hKl == CurhKl )
{
// The mapping table is already created,
return hr;
}
lpKeyMapList = lpKeyMapList->pNext;
}
}
realKbdLayut = &(_lpCurKbdLayout->kbdLayout);
lpKeyMapList = (KEYMAP *)cicMemAllocClear(sizeof(KEYMAP) );
if ( lpKeyMapList == NULL )
{
// there is not enough memory.
hr = E_OUTOFMEMORY;
return hr;
}
// we have four different states.
wNumModComb = 4;
wNumOfKeys = _lpCurKbdLayout->kbdLayout.wNumberOfKeys;
lpKeyMapList->wNumModComb = wNumModComb;
lpKeyMapList->wNumOfKeys = wNumOfKeys;
lpKeyMapList->hKl = _lpCurKbdLayout->CurhKl;
for ( i=0; i<wNumOfKeys; i++ )
{
BSTR *lppLabelText;
WORD *lpLabelType;
WORD *lpLabelDisp;
lppLabelText = (BSTR *)cicMemAllocClear(wNumModComb * sizeof(BSTR) );
if ( lppLabelText == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpLabelType = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
if ( lpLabelType == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lppLabelText);
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpLabelDisp = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
if ( lpLabelDisp == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lppLabelText);
SafeFreePointer(lpLabelType);
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpKeyMapList->lpKeyLabels[i].lppLabelText = lppLabelText;
lpKeyMapList->lpKeyLabels[i].lpLabelType = lpLabelType;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp = lpLabelDisp;
lpKeyMapList->lpKeyLabels[i].wNumModComb = wNumModComb;
}
// Keep the current keyboard states on Win9x
if ( !IsOnNT( ) )
{
if ( 0 == GetKeyboardState(lpCurKeyState) )
return E_FAIL;
}
iState = 0;
memset(lpKeyState, 0, 256);
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
iState = 1; // Caps On
memset(lpKeyState, 0, 256);
lpKeyState[VK_CAPITAL] = 0x01;
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
iState = 2; // Shift Down, Caps Off.
memset(lpKeyState, 0, 256);
lpKeyState[VK_SHIFT] = 0x80;
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
iState = 3; // Shift Down, Caps On
memset(lpKeyState, 0, 256);
lpKeyState[VK_CAPITAL] = 0x01;
lpKeyState[VK_SHIFT] = 0x80;
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
// Add the newly created KeyMapList to the head of the mapping table link.
lpKeyMapList->pNext = _lpCurKbdLayout->lpKeyMapList;
_lpCurKbdLayout->lpKeyMapList = lpKeyMapList;
CleanUp:
// Restore the current keyboard states on Win9x
if ( !IsOnNT( ) )
SetKeyboardState(lpCurKeyState);
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateUSEnhanceLabel( )
*
* Generate all mapping labels in different modifier status for US enhanced
* soft keyboard.
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateUSEnhanceLabel( )
{
HRESULT hr;
hr = E_NOTIMPL;
// not yet implemented.
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateEuroStandardLabel( )
*
* Generate all mapping labels in different modifier status for Euro standard
* soft keyboard. ( 102-key keyboard)
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateEuroStandardLabel( )
{
//
// there are 8 different states for keyboard labels.
//
// AltGr Shift Caps.
// Bit 2 1 0
//
// state 0 : no any modifier key pressed
// state 1 : Caps On.
// state 2 : Shift pressed. Caps Off
// state 3 : Shift Pressed, Caps On
//
// .........
KEYMAP *lpKeyMapList;
HRESULT hr;
WORD wNumModComb, wNumOfKeys;
int i, j;
int iState;
BYTE lpKeyState[256], lpCurKeyState[256];
KBDLAYOUT *realKbdLayut;
WORD BCaps, BShift, BAltGr;
BCaps = 1;
BShift = 2;
BAltGr = 4;
hr = S_OK;
if ( _lpCurKbdLayout->lpKeyMapList != NULL )
{
// If the mapping table for the specified HKL has already been created,
// Just return it.
HKL CurhKl;
CurhKl = _lpCurKbdLayout->CurhKl;
lpKeyMapList = _lpCurKbdLayout->lpKeyMapList;
while ( lpKeyMapList != NULL )
{
if ( lpKeyMapList->hKl == CurhKl )
{
// The mapping table is already created,
return hr;
}
lpKeyMapList = lpKeyMapList->pNext;
}
}
realKbdLayut = &(_lpCurKbdLayout->kbdLayout);
lpKeyMapList = (KEYMAP *)cicMemAllocClear(sizeof(KEYMAP) );
if ( lpKeyMapList == NULL )
{
// there is not enough memory.
hr = E_OUTOFMEMORY;
return hr;
}
// we have 8 different states.
wNumModComb = 8;
wNumOfKeys = _lpCurKbdLayout->kbdLayout.wNumberOfKeys;
lpKeyMapList->wNumModComb = wNumModComb;
lpKeyMapList->wNumOfKeys = wNumOfKeys;
lpKeyMapList->pNext = NULL;
lpKeyMapList->hKl = _lpCurKbdLayout->CurhKl;
for ( i=0; i<wNumOfKeys; i++ )
{
BSTR *lppLabelText=NULL;
WORD *lpLabelType=NULL;
WORD *lpLabelDisp=NULL;
lppLabelText = (BSTR *)cicMemAllocClear(wNumModComb * sizeof(BSTR) );
lpLabelType = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
lpLabelDisp = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
if ( (lpLabelDisp == NULL) || (lpLabelType== NULL) || (lppLabelText == NULL) ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lppLabelText);
SafeFreePointer(lpLabelType);
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpKeyMapList->lpKeyLabels[i].lppLabelText = lppLabelText;
lpKeyMapList->lpKeyLabels[i].lpLabelType = lpLabelType;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp = lpLabelDisp;
lpKeyMapList->lpKeyLabels[i].wNumModComb = wNumModComb;
}
// Keep the current keyboard states on Win9x.
if ( !IsOnNT( ) )
{
if ( 0 == GetKeyboardState(lpCurKeyState) )
return E_FAIL;
}
for (iState = 0; iState < wNumModComb; iState ++ )
{
memset(lpKeyState, 0, 256);
if ( iState & BCaps )
lpKeyState[VK_CAPITAL]=0x01;
if ( iState & BShift )
lpKeyState[VK_SHIFT] = 0x80;
if ( iState & BAltGr )
{
lpKeyState[VK_MENU] = 0x80;
lpKeyState[VK_CONTROL] = 0x80;
}
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
}
_lpCurKbdLayout->lpKeyMapList = lpKeyMapList;
CleanUp:
// Restore the current keyboard states on Win9x.
if ( ! IsOnNT( ) )
SetKeyboardState(lpCurKeyState);
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateEuroEnhanceLabel( )
*
* Generate all mapping labels in different modifier status for Euro Enhanced
* soft keyboard. ( 102-key + NumPad )
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateEuroEnhanceLabel( )
{
HRESULT hr;
hr = E_NOTIMPL;
// not yet implemented.
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateJpnStandardLabel( )
*
* Generate all mapping labels in different modifier status for JPN standard
* soft keyboard. ( 106-key)
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateJpnStandardLabel( )
{
//
// there are 16 different states for keyboard labels.
//
// Kana Alt Shift Caps.
// Bit 3 2 1 0
//
// state 0 : no any modifier key pressed
// state 1 : Caps On.
// state 2 : Shift pressed. Caps Off
// state 3 : Shift Pressed, Caps On
//
KEYMAP *lpKeyMapList;
HRESULT hr;
WORD wNumModComb, wNumOfKeys;
int i, j;
int iState;
BYTE lpKeyState[256], lpCurKeyState[256];
KBDLAYOUT *realKbdLayut;
WORD BCaps, BShift, BAlt, BKana;
BCaps = 1;
BShift = 2;
BAlt = 4;
BKana = 8;
hr = S_OK;
if ( _lpCurKbdLayout->lpKeyMapList != NULL )
{
return hr;
}
realKbdLayut = &(_lpCurKbdLayout->kbdLayout);
lpKeyMapList = (KEYMAP *)cicMemAllocClear(sizeof(KEYMAP) );
if ( lpKeyMapList == NULL )
{
// there is not enough memory.
hr = E_OUTOFMEMORY;
return hr;
}
// we have four different states.
wNumModComb = 16;
wNumOfKeys = _lpCurKbdLayout->kbdLayout.wNumberOfKeys;
lpKeyMapList->wNumModComb = wNumModComb;
lpKeyMapList->wNumOfKeys = wNumOfKeys;
lpKeyMapList->pNext = NULL;
lpKeyMapList->hKl = _lpCurKbdLayout->CurhKl;
for ( i=0; i<wNumOfKeys; i++ )
{
BSTR *lppLabelText;
WORD *lpLabelType;
WORD *lpLabelDisp;
lppLabelText = (BSTR *)cicMemAllocClear(wNumModComb * sizeof(BSTR) );
if ( lppLabelText == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpLabelType = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
if ( lpLabelType == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lppLabelText);
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpLabelDisp = (WORD *)cicMemAllocClear(wNumModComb * sizeof(WORD) );
if ( lpLabelDisp == NULL ) {
//
// there is not enough memory.
//
// release allocated memory and return
for ( j=0; j<i; j++ )
{
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lppLabelText);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelType);
SafeFreePointer(lpKeyMapList->lpKeyLabels[j].lpLabelDisp);
}
SafeFreePointer(lppLabelText);
SafeFreePointer(lpLabelType);
SafeFreePointer(lpKeyMapList);
hr = E_OUTOFMEMORY;
return hr;
}
lpKeyMapList->lpKeyLabels[i].lppLabelText = lppLabelText;
lpKeyMapList->lpKeyLabels[i].lpLabelType = lpLabelType;
lpKeyMapList->lpKeyLabels[i].lpLabelDisp = lpLabelDisp;
lpKeyMapList->lpKeyLabels[i].wNumModComb = wNumModComb;
}
// Keep the current keyboard states on Win9x.
if ( !IsOnNT( ) )
{
if ( 0 == GetKeyboardState(lpCurKeyState) )
return E_FAIL;
}
for (iState = 0; iState < wNumModComb; iState ++ )
{
memset(lpKeyState, 0, 256);
if ( iState & BCaps )
lpKeyState[VK_CAPITAL] = 0x01;
if ( iState & BShift )
lpKeyState[VK_SHIFT] = 0x80;
if ( iState & BAlt )
lpKeyState[VK_MENU] = 0x80;
if ( iState & BKana )
lpKeyState[VK_KANA] = 0x01;
CHECKHR(_SetStandardLabelText(lpKeyState, realKbdLayut,lpKeyMapList,iState));
}
_lpCurKbdLayout->lpKeyMapList = lpKeyMapList;
CleanUp:
// Restore the current keyboard states on Win9x.
if ( ! IsOnNT( ) )
SetKeyboardState(lpCurKeyState);
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateJpnEnhanceLabel( )
*
* Generate all mapping labels in different modifier status for JPN enhanced
* soft keyboard. (106-key + NumPad )
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateJpnEnhanceLabel( )
{
HRESULT hr;
hr = E_NOTIMPL;
// not yet implemented.
return hr;
}
/*******************************************************************************
*
* Method function: SetKeyboardLabelText( )
*
* Set the mapping label texts based on specified HKL.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::SetKeyboardLabelText(HKL hKl)
{
KBDLAYOUT *realKbdLayout;
HRESULT hr;
DWORD iModiCombState;
WORD iModifierStatus;
realKbdLayout = &(_lpCurKbdLayout->kbdLayout);
hr = S_OK;
if ( realKbdLayout->fStandard == FALSE ) {
//
// customized layout cannot accept HKL to change its keys' labels.
//
_lpCurKbdLayout->CurhKl = 0;
hr = E_FAIL;
return hr;
}
if ( ! IsOnNT( ) )
{
// We have to handle IME hkl specially on Win9x.
// For some reason, Win9x cannot receive IME HKL as parameter in MapVirtualKeyEx and ToAsciiEx.
INT_PTR iHkl;
iHkl = (INT_PTR)hKl;
if ( (iHkl & 0xF0000000) == 0xE0000000 )
{
// this is FE IME HKL.
iHkl = iHkl & 0x0000ffff;
hKl = (HKL) iHkl;
}
}
_lpCurKbdLayout->CurhKl = (HKL)hKl;
//
// check to see if current standard keyboard supports this HKL
//
switch ( _wCurKbdLayoutID ) {
case SOFTKBD_US_STANDARD :
CHECKHR(_GenerateUSStandardLabel( ));
break;
case SOFTKBD_US_ENHANCE :
CHECKHR(_GenerateUSEnhanceLabel( ));
break;
case SOFTKBD_EURO_STANDARD :
CHECKHR(_GenerateEuroStandardLabel( ));
break;
case SOFTKBD_EURO_ENHANCE :
CHECKHR(_GenerateEuroEnhanceLabel( ));
break;
case SOFTKBD_JPN_STANDARD :
CHECKHR(_GenerateJpnStandardLabel( ));
break;
case SOFTKBD_JPN_ENHANCE :
CHECKHR(_GenerateJpnEnhanceLabel( ));
break;
}
// set current Active mapping labels.
// Generate CurModiState based on current keyboard state
_GenerateCurModiState(&iModifierStatus, &iModiCombState);
_lpCurKbdLayout->ModifierStatus = iModifierStatus;
hr = SetKeyboardLabelTextCombination(iModiCombState);
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: _SetKeyboardLabelTextCombination( )
*
* Set current effective modifier combination status, so that the correct
* mapping labels will be shown up.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::SetKeyboardLabelTextCombination(DWORD iModiCombState)
{
WORD wNumberOfKeys, i;
KEYMAP *lpKeyMapList;
HRESULT hr;
hr = S_OK;
if ( _lpCurKbdLayout == NULL )
{
hr = E_FAIL;
return hr;
}
if ( _lpCurKbdLayout->lpKeyMapList == NULL )
{
hr = E_FAIL;
return hr;
}
if ( (_lpCurKbdLayout->kbdLayout).fStandard )
{
// This is a standard keyboard layout, we need to
// find out the correct mapping table for the current
// specified HKL.
// Every mapping table is associated with a HKL.
// the current specified HKL is stored in _lpCurKbdLayout->CurhKl.
HKL CurhKl;
CurhKl = _lpCurKbdLayout->CurhKl;
lpKeyMapList = _lpCurKbdLayout->lpKeyMapList;
while ( lpKeyMapList->hKl != CurhKl )
{
lpKeyMapList = lpKeyMapList->pNext;
if ( lpKeyMapList == NULL )
{
// No mapping table is associated with the specified HKL.
// return error.
hr = E_FAIL;
return hr;
}
}
}
else
lpKeyMapList = _lpCurKbdLayout->lpKeyMapList;
if ( iModiCombState >= lpKeyMapList->wNumModComb)
{
hr = E_FAIL;
return hr;
}
_lpCurKbdLayout->CurModiState = iModiCombState;
// Now fill _CurLabel, Current Active label for every key.
wNumberOfKeys = (_lpCurKbdLayout->kbdLayout).wNumberOfKeys;
for ( i=0; i<wNumberOfKeys; i++)
{
int iState;
_CurLabel[i].keyId = lpKeyMapList->lpKeyLabels[i].keyId;
iState = iModiCombState;
if ( iModiCombState >= lpKeyMapList->lpKeyLabels[i].wNumModComb )
{
// there is not enough different states for this key
// just use state 0.
iState = 0;
}
_CurLabel[i].lpLabelText = lpKeyMapList->lpKeyLabels[i].lppLabelText[iState];
_CurLabel[i].LabelType = lpKeyMapList->lpKeyLabels[i].lpLabelType[iState];
_CurLabel[i].LabelDisp = lpKeyMapList->lpKeyLabels[i].lpLabelDisp[iState];
}
if ( _pSoftkbdUIWnd )
{
_pSoftkbdUIWnd->_SetKeyLabel( );
}
return hr;
}
/*******************************************************************************
*
* Method function: _GenerateCurModiState( )
*
* Generate Softkbd recognized ModifierStatus and CurModiState based on
* current keyboard states.
*
/********************************************************************************/
HRESULT CSoftKbd::_GenerateCurModiState(WORD *ModifierStatus, DWORD *CurModiState )
{
DWORD iModiCombState;
WORD iModifierStatus;
DWORD iTmp;
HRESULT hr = S_OK;
if ( !ModifierStatus || !CurModiState )
return E_FAIL;
if ( (_lpCurKbdLayout->kbdLayout).fStandard == FALSE )
return E_FAIL;
iModifierStatus = 0;
if ( GetKeyState(VK_CAPITAL) & 0x01 )
{
// Caps key is Toggled.
iModifierStatus |= MODIFIER_CAPSLOCK ;
}
if ( GetKeyState(VK_SHIFT) & 0x80 )
{
// Shift key is pressed.
iModifierStatus |= MODIFIER_SHIFT;
}
if ( GetKeyState(VK_CONTROL) & 0x80 )
{
// Ctrl key is pressed.
iModifierStatus |= MODIFIER_CTRL;
}
if ( GetKeyState(VK_LMENU) & 0x80 )
{
// Left Alt key is pressed.
iModifierStatus |= MODIFIER_ALT;
}
if ( GetKeyState(VK_RMENU) & 0x80 )
{
// Right Alt key is pressed.
iModifierStatus |= MODIFIER_ALTGR;
}
if ( GetKeyState(VK_KANA) & 0x01 )
{
// KANA key is Toggled.
iModifierStatus |= MODIFIER_KANA;
}
*ModifierStatus = iModifierStatus;
switch ( _wCurKbdLayoutID ) {
case SOFTKBD_US_STANDARD :
case SOFTKBD_US_ENHANCE :
// this is for US Standard keyboard.
// others may need to handle separately.
iModiCombState = (iModifierStatus) & (MODIFIER_CAPSLOCK | MODIFIER_SHIFT);
iModiCombState = iModiCombState >> 1;
// bit1 for Caps.
// bit2 for Shift
break;
case SOFTKBD_EURO_STANDARD :
case SOFTKBD_EURO_ENHANCE :
// this is for Euro 102 standard keyboard.
// How to map ModifierStatus -> CurModiState.
// bit 1 for Caps, bit2 for Shift, bit3 for AltGr.
iModiCombState = (iModifierStatus) & ( MODIFIER_CAPSLOCK | MODIFIER_SHIFT );
iModiCombState = iModiCombState >> 1;
iTmp = (iModifierStatus) & MODIFIER_ALTGR;
iTmp = iTmp >> 4;
iModiCombState += iTmp;
break;
case SOFTKBD_JPN_STANDARD :
case SOFTKBD_JPN_ENHANCE :
// How to map ModifierStatus -> CurModiState.
iModiCombState = (iModifierStatus) & ( MODIFIER_CAPSLOCK | MODIFIER_SHIFT );
iModiCombState = iModiCombState >> 1;
iTmp = (iModifierStatus) & (MODIFIER_ALT | MODIFIER_KANA);
iTmp = iTmp >> 2;
iModiCombState += iTmp;
break;
}
*CurModiState = iModiCombState;
return hr;
}
/*******************************************************************************
*
* Method function: ShowSoftKeyboard( )
*
* Show or Hide the soft keyboard window based on the specified parameter.
*
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::ShowSoftKeyboard(INT iShow)
{
HRESULT hr;
hr = S_OK;
if (!_pSoftkbdUIWnd) {
hr = E_FAIL;
return hr;
}
// if client doesn't specify which layout is selected,
// we just select a default standard soft keyboard layout
// based on current thread keyboard layout.
// if current thread keyboard layout is JPN, use 106 key.
// others, use 101key.
// run SelectSoftKeyboard( SelectedID );
//
if ( _wCurKbdLayoutID == NON_KEYBOARD )
{
HKL hKl;
DWORD dwLayoutId;
LANGID langId;
hKl = GetKeyboardLayout(0);
langId = LOWORD( (DWORD)(UINT_PTR)hKl);
if ( langId == 0x0411 ) // Japanese keyboard
{
dwLayoutId = SOFTKBD_JPN_STANDARD;
}
else
dwLayoutId = SOFTKBD_US_STANDARD;
CHECKHR(SelectSoftKeyboard(dwLayoutId) );
CHECKHR(SetKeyboardLabelText(hKl));
}
_pSoftkbdUIWnd->Show(iShow);
_iShow = iShow;
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: CreateSoftKeyboardWindow( )
*
* Create a real soft keyboard popup window.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::CreateSoftKeyboardWindow(HWND hOwner, TITLEBAR_TYPE Titlebar_type, INT xPos, INT yPos, INT width, INT height)
{
// TODO: Add your implementation code here
HRESULT hr;
hr = S_OK;
_hOwner = hOwner;
_xReal = xPos;
_yReal = yPos;
_widthReal = width;
_heightReal= height;
_TitleBar_Type = Titlebar_type; // temporal solution.
//
// generate realKbdLayout
//
CHECKHR(_GenerateRealKbdLayout( ));
if ( _pSoftkbdUIWnd != NULL )
delete _pSoftkbdUIWnd;
_pSoftkbdUIWnd = new CSoftkbdUIWnd(this, g_hInst, UIWINDOW_TOPMOST | UIWINDOW_WSDLGFRAME | UIWINDOW_HABITATINSCREEN);
if ( _pSoftkbdUIWnd != NULL )
{
_pSoftkbdUIWnd->Initialize( );
_pSoftkbdUIWnd->_CreateSoftkbdWindow(hOwner, Titlebar_type, xPos, yPos, width, height);
}
_iShow = 0;
CleanUp:
return hr;
}
/*******************************************************************************
*
* Method function: DestroySoftKeyboardWindow( )
*
* Destroy the soft keyboard window
*
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::DestroySoftKeyboardWindow()
{
if ( _pSoftkbdUIWnd != NULL )
{
delete _pSoftkbdUIWnd;
_pSoftkbdUIWnd = NULL;
}
return S_OK;
}
/*******************************************************************************
*
* Method function: GetSoftKeyboardPosSize( )
*
* Return current soft keyboard window size and scrren position
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::GetSoftKeyboardPosSize(POINT *lpStartPoint, WORD *lpwidth, WORD *lpheight)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
if ( (lpStartPoint == NULL ) || ( lpwidth == NULL) || ( lpheight == NULL) )
{
hr = E_FAIL;
return hr;
}
lpStartPoint->x = _xReal;
lpStartPoint->y = _yReal;
*lpwidth = (WORD)_widthReal;
*lpheight = (WORD)_heightReal;
return hr;
}
/*******************************************************************************
*
* Method function: GetSoftKeyboardColors( )
*
* Return all different kinds of soft keyboard window colors.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::GetSoftKeyboardColors(COLORTYPE colorType, COLORREF *lpColor)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
if ( lpColor == NULL )
{
hr = E_FAIL;
return hr;
}
*lpColor = _color[colorType];
return hr;
}
/*******************************************************************************
*
* Method function: GetSoftKeyboardTypeMode( )
*
* Return current Soft keyboard 's typing mode.
* this is for On Screen Keyboard.
*
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::GetSoftKeyboardTypeMode(TYPEMODE *lpTypeMode)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
if ( lpTypeMode == NULL )
{
hr = E_FAIL;
return hr;
}
//
//
return hr;
}
/*******************************************************************************
*
* Method function: GetSoftKeyboardTextFont( )
*
* Return current soft keyboard label font data.
*
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::GetSoftKeyboardTextFont(LOGFONTW *pLogFont)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
if ( pLogFont == NULL )
{
hr = E_FAIL;
return hr;
}
if ( _plfTextFont )
{
CopyMemory(pLogFont, _plfTextFont, sizeof(LOGFONTW) );
}
else
hr = S_FALSE;
return hr;
}
STDMETHODIMP CSoftKbd::SetSoftKeyboardPosSize(POINT StartPoint, WORD width, WORD height)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
_xReal = StartPoint.x;
_yReal = StartPoint.y;
if ( width > 0 )
_widthReal = width;
if ( height > 0 )
_heightReal = height;
//
// generate realKbdLayout
//
CHECKHR(_GenerateRealKbdLayout( ));
_pSoftkbdUIWnd->Move(_xReal, _yReal, _widthReal, _heightReal);
if ( _iShow & SOFTKBD_SHOW )
{
CHECKHR(ShowSoftKeyboard(_iShow));
}
CleanUp:
return hr;
}
STDMETHODIMP CSoftKbd::SetSoftKeyboardColors(COLORTYPE colorType, COLORREF Color)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
_color[colorType] = Color;
if ( _iShow & SOFTKBD_SHOW )
{
CHECKHR(ShowSoftKeyboard(_iShow));
}
CleanUp:
return hr;
}
STDMETHODIMP CSoftKbd::SetSoftKeyboardTypeMode(TYPEMODE TypeMode)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
//
// Set type mode
//
if ( _iShow & SOFTKBD_SHOW )
{
CHECKHR(ShowSoftKeyboard(_iShow));
}
CleanUp:
return hr;
}
STDMETHODIMP CSoftKbd::SetSoftKeyboardTextFont(LOGFONTW *pLogFont)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
if ( pLogFont == NULL )
return E_INVALIDARG;
//
// set font data
//
if ( _plfTextFont == NULL )
_plfTextFont = (LOGFONTW *)cicMemAllocClear( sizeof(LOGFONTW) );
if ( _plfTextFont )
{
CopyMemory( _plfTextFont, pLogFont, sizeof(LOGFONTW) );
_pSoftkbdUIWnd->UpdateFont( _plfTextFont );
if ( _iShow & SOFTKBD_SHOW )
{
_pSoftkbdUIWnd->CallOnPaint( );
}
}
else
hr = E_OUTOFMEMORY;
return hr;
}
STDMETHODIMP CSoftKbd::ShowKeysForKeyScanMode(KEYID *lpKeyID, INT iKeyNum, BOOL fHighL)
{
HRESULT hr;
hr = S_OK;
if ( _pSoftkbdUIWnd == NULL )
{
hr = E_FAIL;
return hr;
}
return hr;
}
/*******************************************************************************
*
* Method function: UnadviseSoftKeyboardEventSink( )
*
* Unadvise the previously advised soft keyboard event sink interface.
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::UnadviseSoftKeyboardEventSink(/*[in] */DWORD dwCookie)
{
HRESULT hr;
KBDLAYOUTDES *pKbdLayout;
hr = S_OK;
// we assume dwCookie stands for the real soft keyboard Id.
if ( dwCookie == 0 )
{
hr = E_FAIL;
return hr;
}
if ( dwCookie == DWCOOKIE_SFTKBDWNDES )
{
SafeReleaseClear( _pskbdwndes );
return hr;
}
// Try to find the soft keyboard layout.
pKbdLayout = _lpKbdLayoutDesList;
while ( pKbdLayout != NULL ) {
if ( pKbdLayout->wKbdLayoutID == dwCookie )
break;
pKbdLayout = pKbdLayout->pNext;
}
if ( pKbdLayout == NULL )
{
//
// Cannot find this keyboard layout
//
hr = E_FAIL;
return hr;
}
if ( pKbdLayout->pskbes == NULL )
{
// this event sink has not be registered.
hr = E_FAIL;
return hr;
}
SafeReleaseClear(pKbdLayout->pskbes);
return hr;
}
/*******************************************************************************
*
* Method function: AdviseSoftKeyboardEventSink( )
*
* Register soft keyboard event sink interface for the client of this component
*
*
/********************************************************************************/
STDMETHODIMP CSoftKbd::AdviseSoftKeyboardEventSink(/*[in] */DWORD dwKeyboardId, /*[in]*/ REFIID riid, IUnknown *punk, /*[out] */DWORD *pdwCookie)
{
HRESULT hr;
KBDLAYOUTDES *pKbdLayout;
*pdwCookie = 0;
if ( ! IsEqualIID(riid, IID_ISoftKeyboardEventSink) && ! IsEqualIID(riid, IID_ISoftKbdWindowEventSink) )
return E_UNEXPECTED;
if ( IsEqualIID(riid, IID_ISoftKbdWindowEventSink) )
{
if ( _pskbdwndes != NULL )
return E_FAIL;
CHECKHR(punk->QueryInterface(riid, (void **)&_pskbdwndes) );
if ( pdwCookie != NULL )
*pdwCookie = DWCOOKIE_SFTKBDWNDES;
return hr;
}
// check to see if specified soft keyboard layout is already generated.
pKbdLayout = _lpKbdLayoutDesList;
while ( pKbdLayout != NULL ) {
if ( pKbdLayout->wKbdLayoutID == dwKeyboardId )
break;
pKbdLayout = pKbdLayout->pNext;
}
if ( pKbdLayout == NULL )
{
//
// Cannot find this keyboard layout
//
hr = E_FAIL;
return hr;
}
CHECKHR(punk->QueryInterface(riid, (void **)&(pKbdLayout->pskbes)) );
if ( pdwCookie != NULL )
*pdwCookie = dwKeyboardId;
CleanUp:
return hr == S_OK ? S_OK : E_UNEXPECTED;
}
HRESULT CSoftKbd::_HandleTitleBarEvent( DWORD dwId )
{
HRESULT hr = S_OK;
// dwId stands for IconId or CloseId.
// So far, we handle close button event only.
if (dwId == KID_CLOSE)
{
if (_pskbdwndes != NULL)
hr = _pskbdwndes->OnWindowClose( );
}
return hr;
}
HRESULT CSoftKbd::_HandleKeySelection(KEYID keyId)
{
HRESULT hr = S_OK;
int uKeyIndex, i;
KBDLAYOUT *realKbdLayout=NULL;
KBDLAYOUTDES *lpCurKbdLayout=NULL;
ACTIVELABEL *CurLabel=NULL;
BOOL fModifierSpecial = FALSE;
lpCurKbdLayout = _lpCurKbdLayout;
if ( lpCurKbdLayout == NULL ) return hr;
// Get the KeyIndex in the current layout's key description
realKbdLayout = &(lpCurKbdLayout->kbdLayout);
if ( realKbdLayout == NULL ) return hr;
CurLabel = _CurLabel;
uKeyIndex = -1;
for ( i=0; i<realKbdLayout->wNumberOfKeys; i++) {
if ( keyId == realKbdLayout->lpKeyDes[i].keyId )
{
uKeyIndex = i;
break;
}
}
if ( uKeyIndex == -1 )
{
// It is not a legal key, it is impossible, we just stop here.
return E_FAIL;
}
// set the modifier status
MODIFYTYPE tModifier;
tModifier = realKbdLayout->lpKeyDes[uKeyIndex].tModifier;
if ( tModifier != none )
{
lpCurKbdLayout->ModifierStatus ^= (1 << tModifier);
}
if (lpCurKbdLayout->pskbes != NULL )
{
int j;
WCHAR *lpszLabel;
WORD wNumOfKeys;
wNumOfKeys = realKbdLayout->wNumberOfKeys;
// Try to get the label text for this key.
for ( j=0; j< wNumOfKeys; j++ )
{
if ( CurLabel[j].keyId == keyId )
{
lpszLabel = CurLabel[j].lpLabelText;
break;
}
}
// Notify the client of key event.
(lpCurKbdLayout->pskbes)->OnKeySelection(keyId, lpszLabel);
}
else
{
// there is no event sink registered for this keyboard layout.
// this must be a standard keyboard layout.
// we will just simuate key stroke event for this key.
if ( realKbdLayout->fStandard == TRUE )
{
BYTE bVk, bScan;
int j, jIndex;
BOOL fExtendKey, fPictureKey;
PICTUREKEY *pPictureKeys;
switch ( _wCurKbdLayoutID ) {
case SOFTKBD_JPN_STANDARD :
case SOFTKBD_JPN_ENHANCE :
pPictureKeys = gJpnPictureKeys;
break;
case SOFTKBD_US_STANDARD :
case SOFTKBD_US_ENHANCE :
case SOFTKBD_EURO_STANDARD :
case SOFTKBD_EURO_ENHANCE :
pPictureKeys = gPictureKeys;
break;
}
fPictureKey = FALSE;
for ( j=0; j<NUM_PICTURE_KEYS; j++)
{
if ( pPictureKeys[j].uScanCode == keyId )
{
// This is a picture key.
// it may be a extended key.
jIndex = j;
fPictureKey = TRUE;
break;
}
if ( pPictureKeys[j].uScanCode == 0 )
{
// This is the last item in pPictureKeys.
break;
}
}
fExtendKey = FALSE;
if ( fPictureKey )
{
if ( (keyId & 0xFF00) == 0xE000 )
{
fExtendKey = TRUE;
bScan = (BYTE)(keyId & 0x000000ff);
}
else
{
fExtendKey = FALSE;
bScan = (BYTE)(keyId);
}
bVk = (BYTE)(pPictureKeys[jIndex].uVkey);
if ( bVk == 0 )
bVk = (BYTE)MapVirtualKeyEx((UINT)bScan, 1, lpCurKbdLayout->CurhKl);
}
else
{
bScan = (BYTE)keyId;
bVk = (BYTE)MapVirtualKeyEx((UINT)bScan, 1, lpCurKbdLayout->CurhKl);
}
if ( tModifier == none )
{
if ( fExtendKey )
{
keybd_event(bVk, bScan, (DWORD)KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(bVk, bScan, (DWORD)(KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP), 0);
}
else
{
keybd_event(bVk, bScan, 0, 0);
keybd_event(bVk, bScan, (DWORD)KEYEVENTF_KEYUP, 0);
}
// if the Shift Key is pressed, we need to release this key.
if ( lpCurKbdLayout->ModifierStatus & MODIFIER_SHIFT)
{
fModifierSpecial = TRUE;
lpCurKbdLayout->ModifierStatus &= ~((WORD)MODIFIER_SHIFT);
// simulate the SHIFT-UP key event.
keybd_event((BYTE)VK_SHIFT, (BYTE)KID_LSHFT, (DWORD)KEYEVENTF_KEYUP, 0);
}
// if the Ctrl Key is pressed, we need to release this key.
if ( lpCurKbdLayout->ModifierStatus & MODIFIER_CTRL)
{
fModifierSpecial = TRUE;
lpCurKbdLayout->ModifierStatus &= ~((WORD)MODIFIER_CTRL);
// simulate the SHIFT-UP key event.
keybd_event((BYTE)VK_CONTROL, (BYTE)KID_CTRL, (DWORD)KEYEVENTF_KEYUP, 0);
}
// if the Shift Key is pressed, we need to release this key.
if ( lpCurKbdLayout->ModifierStatus & MODIFIER_ALT)
{
fModifierSpecial = TRUE;
lpCurKbdLayout->ModifierStatus &= ~((WORD)MODIFIER_ALT);
// simulate the SHIFT-UP key event.
keybd_event((BYTE)VK_MENU, (BYTE)KID_ALT, (DWORD)KEYEVENTF_KEYUP, 0);
}
// if the Right Alt Key is pressed, we need to release this key.
if ( lpCurKbdLayout->ModifierStatus & MODIFIER_ALTGR)
{
fModifierSpecial = TRUE;
lpCurKbdLayout->ModifierStatus &= ~((WORD)MODIFIER_ALTGR);
// simulate the SHIFT-UP key event.
keybd_event((BYTE)VK_RMENU, (BYTE)KID_RALT, (DWORD)KEYEVENTF_KEYUP, 0);
}
}
else
{
// specially handle Caps Lock
if ( keyId == KID_CAPS )
{
// this is a togglable key
keybd_event(bVk, bScan, 0, 0);
keybd_event(bVk, bScan, (DWORD)KEYEVENTF_KEYUP, 0);
}
else if (keyId == KID_KANA)
{
BYTE pKeyState[256];
memset(pKeyState, 0, sizeof(pKeyState) );
if ( lpCurKbdLayout->ModifierStatus & (1 << tModifier) )
pKeyState[VK_KANA] = 0x01;
SetKeyboardState(pKeyState);
}
else
{
if ( lpCurKbdLayout->ModifierStatus & (1 << tModifier) ) {
// This key is pressed now
keybd_event(bVk, bScan, 0, 0);
}
else
{
// This key is released now
keybd_event(bVk, bScan, (DWORD)KEYEVENTF_KEYUP, 0);
}
}
}
}
}
if ( (realKbdLayout->lpKeyDes[uKeyIndex].tModifier != none) || fModifierSpecial )
{
if ( realKbdLayout->fStandard == TRUE )
{
DWORD iModiCombState;
DWORD iTmp;
switch ( _wCurKbdLayoutID ) {
case SOFTKBD_US_STANDARD :
case SOFTKBD_US_ENHANCE :
// this is for US Standard keyboard.
// others may need to handle separately.
iModiCombState = (lpCurKbdLayout->ModifierStatus) & (MODIFIER_CAPSLOCK | MODIFIER_SHIFT);
iModiCombState = iModiCombState >> 1;
// bit1 for Caps.
// bit2 for Shift
break;
case SOFTKBD_EURO_STANDARD :
case SOFTKBD_EURO_ENHANCE :
// this is for Euro 102 standard keyboard.
// How to map ModifierStatus -> CurModiState.
// bit 1 for Caps, bit2 for Shift, bit3 for AltGr.
iModiCombState = (lpCurKbdLayout->ModifierStatus) & ( MODIFIER_CAPSLOCK | MODIFIER_SHIFT );
iModiCombState = iModiCombState >> 1;
iTmp = (lpCurKbdLayout->ModifierStatus) & MODIFIER_ALTGR;
iTmp = iTmp >> 4;
iModiCombState += iTmp;
break;
case SOFTKBD_JPN_STANDARD :
case SOFTKBD_JPN_ENHANCE :
// How to map ModifierStatus -> CurModiState.
iModiCombState = (lpCurKbdLayout->ModifierStatus) & ( MODIFIER_CAPSLOCK | MODIFIER_SHIFT );
iModiCombState = iModiCombState >> 1;
iTmp = (lpCurKbdLayout->ModifierStatus) & (MODIFIER_ALT | MODIFIER_KANA);
iTmp = iTmp >> 2;
iModiCombState += iTmp;
break;
}
SetKeyboardLabelTextCombination(iModiCombState);
ShowSoftKeyboard(TRUE);
}
}
return hr;
}
/*******************************************************************************
*
* Method function: _UnicodeToUtf8( )
*
* Convert unicode characters to UTF8.
*
* Result is NULL terminated if sufficient space in result
* buffer is available.
*
* Arguments:
*
* pwUnicode -- ptr to start of unicode buffer
* cchUnicode -- length of unicode buffer
* pchResult -- ptr to start of result buffer for UTF8 chars
* cchResult -- length of result buffer
*
* Return Value:
*
* Count of UTF8 characters in result, if successful.
* 0 on error. GetLastError() has error code.
*
*
/********************************************************************************/
DWORD CSoftKbd::_UnicodeToUtf8(PWCHAR pwUnicode, DWORD cchUnicode, PCHAR pchResult, DWORD cchResult)
{
WCHAR wch; // current unicode character being converted
DWORD lengthUtf8 = 0; // length of UTF8 result string
WORD lowSurrogate;
DWORD surrogateDword;
//
// loop converting unicode chars until run out or error
//
Assert( cchUnicode > 0 );
while ( cchUnicode-- )
{
wch = *pwUnicode++;
//
// ASCII character (7 bits or less) -- converts to directly
//
if ( wch < 0x80 )
{
lengthUtf8++;
if ( pchResult )
{
if ( lengthUtf8 >= cchResult )
{
goto OutOfBuffer;
}
*pchResult++ = (CHAR)wch;
}
continue;
}
//
// wide character less than 0x07ff (11bits) converts to two bytes
// - upper 5 bits in first byte
// - lower 6 bits in secondar byte
//
else if ( wch <= UTF8_2_MAX )
{
lengthUtf8 += 2;
if ( pchResult )
{
if ( lengthUtf8 >= cchResult )
{
goto OutOfBuffer;
}
*pchResult++ = UTF8_1ST_OF_2 | wch >> 6;
*pchResult++ = UTF8_TRAIL | LOW6BITS( (UCHAR)wch );
}
continue;
}
//
// surrogate pair
// - if have high surrogate followed by low surrogate then
// process as surrogate pair
// - otherwise treat character as ordinary unicode "three-byte"
// character, by falling through to below
//
else if ( wch >= HIGH_SURROGATE_START &&
wch <= HIGH_SURROGATE_END &&
cchUnicode &&
(lowSurrogate = *pwUnicode) &&
lowSurrogate >= LOW_SURROGATE_START &&
lowSurrogate <= LOW_SURROGATE_END )
{
// have a surrogate pair
// - pull up next unicode character (low surrogate of pair)
// - make full DWORD surrogate pair
// - then lay out four UTF8 bytes
// 1st of four, then three trail bytes
// 0x1111xxxx
// 0x10xxxxxx
// 0x10xxxxxx
// 0x10xxxxxx
pwUnicode++;
cchUnicode--;
lengthUtf8 += 4;
if ( pchResult )
{
if ( lengthUtf8 >= cchResult )
{
goto OutOfBuffer;
}
surrogateDword = (((wch-0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000);
*pchResult++ = UTF8_1ST_OF_4 | (UCHAR) (surrogateDword >> 18);
*pchResult++ = UTF8_TRAIL | (UCHAR) LOW6BITS(surrogateDword >> 12);
*pchResult++ = UTF8_TRAIL | (UCHAR) LOW6BITS(surrogateDword >> 6);
*pchResult++ = UTF8_TRAIL | (UCHAR) LOW6BITS(surrogateDword);
}
}
//
// wide character (non-zero in top 5 bits) converts to three bytes
// - top 4 bits in first byte
// - middle 6 bits in second byte
// - low 6 bits in third byte
//
else
{
lengthUtf8 += 3;
if ( pchResult )
{
if ( lengthUtf8 >= cchResult )
{
goto OutOfBuffer;
}
*pchResult++ = UTF8_1ST_OF_3 | (wch >> 12);
*pchResult++ = UTF8_TRAIL | LOW6BITS( wch >> 6 );
*pchResult++ = UTF8_TRAIL | LOW6BITS( wch );
}
}
}
//
// NULL terminate buffer
// return UTF8 character count
//
if ( pchResult && lengthUtf8 < cchResult )
{
*pchResult = 0;
}
return( lengthUtf8 );
OutOfBuffer:
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return( 0 );
}
/*******************************************************************************
*
* Method function _Utf8ToUnicode( )
*
* Convert UTF8 characters to unicode.
*
* Result is NULL terminated if sufficient space in result
* buffer is available.
* Arguments:
*
* pwResult -- ptr to start of result buffer for unicode chars
* cwResult -- length of result buffer in WCHAR
* pwUtf8 -- ptr to start of UTF8 buffer
* cchUtf8 -- length of UTF8 buffer
*
* Return Value:
* Count of unicode characters in result, if successful.
* 0 on error. GetLastError() has error code.
*
*******************************************************************************/
DWORD CSoftKbd::_Utf8ToUnicode(PCHAR pchUtf8, DWORD cchUtf8, PWCHAR pwResult, DWORD cwResult)
{
CHAR ch; // current UTF8 character
WCHAR wch; // current unicode character
DWORD trailCount = 0; // count of UTF8 trail bytes to follow
DWORD lengthUnicode = 0; // length of unicode result string
BOOL bsurrogatePair = FALSE;
DWORD surrogateDword;
//
// loop converting UTF8 chars until run out or error
//
Assert( cchUtf8 > 0 );
while ( cchUtf8-- )
{
ch = *pchUtf8++;
//
// ASCII character -- just copy
//
if ( BIT7(ch) == 0 )
{
lengthUnicode++;
if ( pwResult )
{
if ( lengthUnicode >= cwResult )
{
goto OutOfBuffer;
}
*pwResult++ = (WCHAR)ch;
}
continue;
}
//
// UTF8 trail byte
// - if not expected, error
// - otherwise shift unicode character 6 bits and
// copy in lower six bits of UTF8
// - if last UTF8 byte, copy result to unicode string
//
else if ( BIT6(ch) == 0 )
{
if ( trailCount == 0 )
{
goto InvalidUtf8;
}
if ( !bsurrogatePair )
{
wch <<= 6;
wch |= LOW6BITS( ch );
if ( --trailCount == 0 )
{
lengthUnicode++;
if ( pwResult )
{
if ( lengthUnicode >= cwResult )
{
goto OutOfBuffer;
}
*pwResult++ = wch;
}
}
continue;
}
// surrogate pair
// - same as above EXCEPT build two unicode chars
// from surrogateDword
else
{
surrogateDword <<= 6;
surrogateDword |= LOW6BITS( ch );
if ( --trailCount == 0 )
{
lengthUnicode += 2;
if ( pwResult )
{
if ( lengthUnicode >= cwResult )
{
goto OutOfBuffer;
}
surrogateDword -= 0x10000;
*pwResult++ = (WCHAR) ((surrogateDword >> 10) + HIGH_SURROGATE_START);
*pwResult++ = (WCHAR) ((surrogateDword & 0x3ff) + LOW_SURROGATE_START);
}
bsurrogatePair = FALSE;
}
}
}
//
// UTF8 lead byte
// - if currently in extension, error
else
{
if ( trailCount != 0 )
{
goto InvalidUtf8;
}
// first of two byte character (110xxxxx)
if ( BIT5(ch) == 0 )
{
trailCount = 1;
wch = LOW5BITS(ch);
continue;
}
// first of three byte character (1110xxxx)
else if ( BIT4(ch) == 0 )
{
trailCount = 2;
wch = LOW4BITS(ch);
continue;
}
// first of four byte surrogate pair (11110xxx)
else if ( BIT3(ch) == 0 )
{
trailCount = 3;
surrogateDword = LOW4BITS(ch);
bsurrogatePair = TRUE;
}
else
{
goto InvalidUtf8;
}
}
}
// catch if hit end in the middle of UTF8 multi-byte character
if ( trailCount )
{
goto InvalidUtf8;
}
//
// NULL terminate buffer
// return the number of Unicode characters written.
//
if ( pwResult && lengthUnicode < cwResult )
{
*pwResult = 0;
}
return( lengthUnicode );
OutOfBuffer:
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return( 0 );
InvalidUtf8:
SetLastError( ERROR_INVALID_DATA );
return( 0 );
}