#include #include #include #include "FullIME.h" static DWORD CompColor[ 4 ] = { RGB( 255, 0, 0 ), RGB( 255, 0 , 255 ), RGB( 0, 0, 255 ), RGB( 0, 255, 0 ) }; //********************************************************************** // // void ImeUIStartComposition() // // This handles WM_IME_STARTCOMPOSITION message. // //********************************************************************** void ImeUIStartComposition( HWND hwnd ) { // // Change caption title to DBCS composition mode. // SetWindowText( hwnd, szSteCompTitle ); // // Reset global variables. // gImeUIData.uCompLen = 0; // length of composition string. gImeUIData.ImeState |= IME_IN_COMPOSITION; } //********************************************************************** // // void ImeUIComposition() // // This handles WM_IME_COMPOSITION message. It here just handles // composition string and result string. For normal case, it should // examine all posibile flags indicated by CompFlag, then do some // actitions to reflect what kinds of composition info. IME conversion // engine informs. // //********************************************************************** void ImeUIComposition( HWND hwnd, WPARAM wParam, LPARAM CompFlag ) { if ( CompFlag & GCS_RESULTSTR ) { GetResultStr( hwnd ); } else { if ( CompFlag & GCS_COMPSTR ) { GetCompositionStr( hwnd, CompFlag ); } } } //********************************************************************** // // void GetCompositionStr() // // This handles WM_IME_COMPOSITION message with GCS_COMPSTR flag on. // //********************************************************************** void GetCompositionStr( HWND hwnd, LPARAM CompFlag ) { LONG bufLen; // Stogare for len. of composition str LPSTR lpCompStr; // Pointer to composition str. HIMC hIMC; // Input context handle. HLOCAL hMem; // Memory handle. LPSTR lpCompStrAttr; // Pointer to composition str array. HLOCAL hMemAttr = NULL; // Memory handle for comp. str. array. LONG bufLenAttr; // // If fail to get input context handle then do nothing. // Applications should call ImmGetContext API to get // input context handle. // if ( !( hIMC = ImmGetContext( hwnd ) ) ) return; // // Determines how much memory space to store the composition string. // Applications should call ImmGetCompositionString with // GCS_COMPSTR flag on, buffer length zero, to get the bullfer // length. // bufLen = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void*)NULL, 0l ); if ( ( IMM_ERROR_NODATA == bufLen) || ( IMM_ERROR_GENERAL == bufLen) ) { goto exit2; } // // Allocates memory with bufLen+1 bytes to store the composition // string. Here we allocale on more byte to put null character. // if ( !( hMem = LocalAlloc( LPTR, (int)bufLen + 1 ) ) ) goto exit2; if ( !( lpCompStr = (LPSTR) LocalLock( hMem ) ) ) goto exit1; // // Reads in the composition string. // ImmGetCompositionString( hIMC, GCS_COMPSTR, lpCompStr, bufLen ); // // Null terminated. // lpCompStr[ bufLen ] = 0; // // If GCS_COMPATTR flag is on, then we need to take care of it. // if ( CompFlag & GCS_COMPATTR ) { bufLenAttr = ImmGetCompositionString( hIMC, GCS_COMPATTR, (void*)NULL, 0l ); if ( ( IMM_ERROR_NODATA == bufLenAttr) || ( IMM_ERROR_GENERAL == bufLenAttr) ) { goto nothing; } // // Allocate memory to store attributes of composition strings. // if ( !( hMemAttr = LocalAlloc( LPTR, (int)bufLenAttr + 1 ) ) ) goto nothing; if ( !( lpCompStrAttr = (LPSTR) LocalLock( hMemAttr ) ) ) { LocalFree( hMemAttr ); goto nothing; } // // Reads in the attribute array. // ImmGetCompositionString( hIMC, GCS_COMPATTR, lpCompStrAttr, bufLenAttr ); lpCompStrAttr[ bufLenAttr ] = 0; } else { nothing: lpCompStrAttr = NULL; } // // Display new composition chars. // DisplayCompString( hwnd, lpCompStr, lpCompStrAttr ); // // Keep the length of the composition string for using later. // gImeUIData.uCompLen = (UINT)bufLen; LocalUnlock( hMem ); if ( lpCompStrAttr ) { if (NULL != hMemAttr) { LocalUnlock( hMemAttr ); LocalFree( hMemAttr ); } } exit1: LocalFree( hMem ); exit2: ImmReleaseContext( hwnd, hIMC ); } //*********************************************************************** // // void GetResultStr() // // This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on. // //*********************************************************************** void GetResultStr( HWND hwnd ) { LONG bufLen; // Storage for length of result str. LPSTR lpResultStr; // Pointer to result string. HIMC hIMC; // Input context handle. HLOCAL hMem; // Memory handle. // // If fail to get input context handle then do nothing. // if ( !( hIMC = ImmGetContext( hwnd ) ) ) return; // // Determines how much memory space to store the result string. // Applications should call ImmGetCompositionString with // GCS_RESULTSTR flag on, buffer length zero, to get the bullfer // length. // if ( ( bufLen = ImmGetCompositionString( hIMC, GCS_RESULTSTR, (void *)NULL, (DWORD) 0 ) ) <= 0 ) goto exit2; // // Allocates memory with bufLen+1 bytes to store the result // string. Here we allocale on more byte to put null character. // if ( !( hMem = LocalAlloc( LPTR, (int)bufLen + 1 ) ) ) goto exit2; if ( !( lpResultStr = (LPSTR) LocalLock( hMem ) ) ) goto exit1; // // Reads in the result string. // ImmGetCompositionString( hIMC, GCS_RESULTSTR, lpResultStr, bufLen ); // // Displays the result string. // DisplayResultString( hwnd, lpResultStr ); LocalUnlock( hMem ); exit1: LocalFree( hMem ); exit2: ImmReleaseContext( hwnd, hIMC ); } //********************************************************************** // // void ImeUIEndComposition // // This handles WM_IME_ENDCOMPOSITION message. // //********************************************************************** void ImeUIEndComposition( HWND hwnd ) { RECT rect = {0}; // // Change caption title to normal // SetWindowText( hwnd, szSteTitle ); // // Update client area. // GetClientRect( hwnd, &rect ); InvalidateRect( hwnd, &rect, FALSE ); // // Reset the length of composition string to zero. // gImeUIData.uCompLen = 0; gImeUIData.ImeState &= ~IME_IN_COMPOSITION; } //********************************************************************** // // BOOL ImeUINotify() // // This handles WM_IME_NOTIFY message. // //********************************************************************** BOOL ImeUINotify( HWND hwnd, WPARAM wParam, LPARAM lParam ) { switch (wParam ) { case IMN_OPENCANDIDATE: ImeUIOpenCandidate( hwnd, lParam ); break; case IMN_CLOSECANDIDATE: ImeUICloseCandidate( hwnd, lParam ); break; case IMN_CHANGECANDIDATE: ImeUIChangeCandidate( hwnd, lParam ); break; case IMN_SETOPENSTATUS: ImeUISetOpenStatus( hwnd ); break; default: return FALSE; } return TRUE; } //********************************************************************** // // void ImeUIOpenCandidate() // // This handles WM_IME_NOTIFY message with wParam = IMN_OPENCANDIDATE. // //********************************************************************** void ImeUIOpenCandidate( HWND hwnd, LPARAM CandList ) { HIMC hIMC; // Input context handle. LPCANDIDATELIST lpCandList; // Storage for LP to candidate list. CANDIDATELIST tempCandList; // Storage for LP to candidate list. DWORD bufLen; // Storage for candidate strings. LPSTR lpStr; // Storage for LP to a string. DWORD dwIndex; // Storage for index of ListCand array DWORD i; // Loop count. int width = 0; // Storage for width of listCand int CurNumCandList = 0; // Storage for number of cand. lists. DWORD dwPreferNumPerPage; // Storage for PreferNumPerPage POINT point; // Storage for caret position. // // If fail to get input context handle, do nothing. // if ( ! (hIMC = ImmGetContext( hwnd ) ) ) return; // // Change caption title to DBCS candidate mode. // SetWindowText( hwnd, szSteCandTitle ); // // Find out how many candidate windows have already been opened. // for( i = 0; i < MAX_LISTCAND; i++ ) { if ( gImeUIData.hListCand[ i ] ) { CurNumCandList++; } } // // Check which candidate lists should be displayed by loopping // through all possible candidate lists. // for( dwIndex = 0; dwIndex < MAX_LISTCAND ; dwIndex ++ ) { if ( CandList & ( 1 << dwIndex ) ) { // // The dwIndex-th candidate list contains candidate strings. // So here we want to display them. // // // Determines how musch memory space should be allocated to // read in the corresponding candidate list . // if ( ! ( bufLen = ImmGetCandidateList( hIMC, dwIndex, &tempCandList, 0 ) ) ) goto exit2; // // Allocate memory space. // if( !( gImeUIData.hListCandMem[ dwIndex ] = GlobalAlloc( LPTR, (int)bufLen ) ) ) goto exit2; if( !( lpStr = (LPSTR)GlobalLock( gImeUIData.hListCandMem[ dwIndex ] ) ) ) { GlobalFree( gImeUIData.hListCandMem[ dwIndex ] ); gImeUIData.hListCandMem[ dwIndex ] = NULL; goto exit2; } lpCandList = (LPCANDIDATELIST) lpStr; // // Reads in the corresponding candidate list. // ImmGetCandidateList( hIMC, dwIndex, lpCandList, bufLen ); // // Get current caret position. // GetCaretPos( (POINT *)&point ); ClientToScreen( hwnd, &point ); // // Determines how many candidate strings per page. // dwPreferNumPerPage = ( !lpCandList->dwPageSize ) ? DEFAULT_CAND_NUM_PER_PAGE : lpCandList->dwPageSize; // // Determining maximum character length the list box // will display by loopping through all candidate strings. // for( i = 0; i < lpCandList->dwCount; i++ ) { // // Get the pointer to i-th candidate string. // lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[ i ]; width = ( width < lstrlen( lpStr ) ) ? lstrlen( lpStr ) : width; } // // Create a candidate window for the candidate list. // gImeUIData.hListCand[ dwIndex ] = CreateWindow( szCandClass, NULL, WS_BORDER | WS_POPUP | WS_DISABLED, CurNumCandList * X_INDENT + point.x, CurNumCandList * Y_INDENT + point.y + cyMetrics, ( width ) * cxMetrics + 10, (int)(dwPreferNumPerPage) * cyMetrics + 5, hwnd, NULL, (HINSTANCE)GetWindowLongPtr( hwnd, GWLP_HINSTANCE ), NULL ); // // If fail to create the candidate window then do nothing. // if ( gImeUIData.hListCand[ dwIndex ] < 0 ) { GlobalUnlock( gImeUIData.hListCandMem[ dwIndex ] ); GlobalFree( gImeUIData.hListCandMem[ dwIndex ] ); goto exit2; } // // Show candidate window. // ShowWindow( gImeUIData.hListCand[ dwIndex ], SW_SHOWNOACTIVATE ); // // Display candidate strings. // DisplayCandStrings( gImeUIData.hListCand[ dwIndex ], lpCandList ); GlobalUnlock( gImeUIData.hListCandMem[ dwIndex ] ); CurNumCandList++; } } // // Reset IME state. // gImeUIData.ImeState |= IME_IN_CHOSECAND; exit2: ImmReleaseContext( hwnd, hIMC ); } //********************************************************************** // // void ImeUICloseCandidate() // // This handles WM_IME_NOTIFY message with // wParam = IMN_CLOSECANDIDATE. // //********************************************************************** void ImeUICloseCandidate( HWND hwnd, LPARAM CandList ) { int index; // // Change window's caption title to normal. // SetWindowText( hwnd, szSteCompTitle ); // // If the i-th bit on of CandList that means the i-th // candidate list should be closed. // for( index = 0; index < MAX_LISTCAND; index ++ ) { if (( CandList & ( 1 << index ) ) && gImeUIData.hListCand[ index ]) { // // Destroy the candidate window. // DestroyWindow( gImeUIData.hListCand[ index ] ); gImeUIData.hListCand[ index ] = NULL; // // Free memory. // GlobalFree( gImeUIData.hListCandMem[ index ] ); gImeUIData.hListCandMem[ index ] = NULL; } } gImeUIData.ImeState &= ~IME_IN_CHOSECAND; } //********************************************************************** // // void ImeUIChangeCandidate() // // This handles WM_IME_NOTIFY message with wParam = IMN_CHANGECANDIDATE. // //********************************************************************** void ImeUIChangeCandidate( HWND hwnd, LPARAM CandList ) { HIMC hIMC; LPCANDIDATELIST lpCandList = NULL; DWORD dwIndex; DWORD bufLen; LPSTR lpStr; DWORD i; RECT rect = {0}; int width = 0; DWORD dwPreferNumPerPage; // // If fail to get input context, do nothing. // if ( !( hIMC = ImmGetContext( hwnd ) ) ) return; // // Determine which candidate list should be updated. // for ( dwIndex = 0; dwIndex < MAX_LISTCAND; dwIndex++ ) if ( CandList & ( 1 << dwIndex ) ) break; // // If dwIndex == MAX_LISTCAND, then something wrong, do nothing. // if ( dwIndex == MAX_LISTCAND ) return; // // Determines how much memory space should be allocated to read in the // corresponding candidate list. // if ( !( bufLen = ImmGetCandidateList( hIMC, dwIndex, lpCandList, 0 ) ) ) goto exit2; // // Relocate memory space. // if ( !( gImeUIData.hListCandMem[ dwIndex ] = GlobalReAlloc( gImeUIData.hListCandMem[ dwIndex ], (int)bufLen, LPTR ) ) ) { goto exit2; } if ( !( lpStr = (LPSTR)GlobalLock( gImeUIData.hListCandMem[ dwIndex ] ) ) ) { GlobalFree( gImeUIData.hListCandMem[ dwIndex ] ); gImeUIData.hListCandMem[ dwIndex ] = NULL; goto exit2; } lpCandList = (LPCANDIDATELIST) lpStr; // // Reads in the corresponding candidate list. // ImmGetCandidateList( hIMC, dwIndex, lpCandList, bufLen ); // // Determines how many candidate strings per page. // dwPreferNumPerPage = ( !lpCandList->dwPageSize ) ? DEFAULT_CAND_NUM_PER_PAGE : lpCandList->dwPageSize; // // Determining maximum character length the list box // will display by loopping through all candidate strings. // for( i = 0; i < lpCandList->dwCount; i++ ) { // // Get the pointer to i-th candidate string. // lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[ i ]; width = ( width < lstrlen( lpStr ) ) ? lstrlen( lpStr ) : width; } GetWindowRect( gImeUIData.hListCand[ dwIndex ] , &rect); SetWindowPos( gImeUIData.hListCand[ dwIndex ], hwnd, rect.left, rect.top, ( width ) * cxMetrics + 10, (int)(dwPreferNumPerPage) * cyMetrics + 5, SWP_NOZORDER | SWP_NOACTIVATE ); DisplayCandStrings( gImeUIData.hListCand[ dwIndex ], lpCandList ); GlobalUnlock( gImeUIData.hListCandMem[ dwIndex ] ); exit2: return; } //*********************************************************************** // // void ImeUISetOpenStatus() // // This handles WM_IME_REPORT message with wParam = IR_NOTIFY & // lParam = IMC_SETOPENSTATUS. // //********************************************************************** void ImeUISetOpenStatus( HWND hwnd ) { int i; // Lopp counter HIMC hIMC; // Storage for input context handle. // // If fail to get input context handle then do nothing // if ( !( hIMC = ImmGetContext( hwnd ) ) ) return; if ( ImmGetOpenStatus( hIMC ) ) { // // If the IME conversion engine is open, here we change // window's caption title to DBCS composition mode. // SetWindowText( hwnd, (LPSTR)szSteCompTitle ); } else { RECT rect = {0}; // // If the IME conversion engine is closed, here we // erase all already displayed composition chars if any, // change the window's caption title to normal. // GetClientRect( hwnd, &rect ); InvalidateRect( hwnd, &rect, FALSE ); SetWindowText( hwnd, (LPSTR)szSteTitle ); // // Here we close and destroy all of candidate windows // if IME conversion engine is closed. // for( i = 0; i <= MAX_LISTCAND; i++ ) { if ( gImeUIData.hListCand[ i ] ) { DestroyWindow( gImeUIData.hListCand[ i ] ); gImeUIData.hListCand[ i ] = NULL; GlobalFree( gImeUIData.hListCandMem[ i ] ); gImeUIData.hListCandMem[ i ] = NULL; } } // // Reset IMEUI's global data. // gImeUIData.uCompLen = 0; gImeUIData.ImeState = 0; ResetCaret( hwnd ); } ImmReleaseContext( hwnd, hIMC ); } //********************************************************************* // // void DisplayCompString() // // This displays composition string. // // This function supports only fixed pitch font. // //********************************************************************* void DisplayCompString( HWND hwnd, LPSTR lpStr, LPSTR lpStrAttr ) { HDC hdc; int StrLen = lstrlen( lpStr ); RECT rect; DWORD dwColor; int i; BOOL fDBCSTrailByte = FALSE; hdc = GetDC( hwnd ); HideCaret( hwnd ); // // Determine OPAQUE rect. // rect.left = xPos * cxMetrics; rect.top = yPos * cyMetrics; rect.bottom = rect.top + cyMetrics; rect.right = ( (int)gImeUIData.uCompLen > StrLen ) ? ( xPos + gImeUIData.uCompLen ) * cxMetrics: ( xPos + StrLen ) * cxMetrics; // // This example we use red to display composition chars // with attribute 000, pink for attribute 001, // blue for attribute 010, green for attribute 011. // // // Each composition character has different attribute. // We here use different kinds of color to represent attributes. // Red, pink, blue and green are for attribute 000, 001, 010 and 011, // respectively. // dwColor = GetTextColor( hdc ); if ( ( StrLen % 2 ) ) { if ( IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 1 ] ) ) { textbuf[ yPos ][ xPos + StrLen ] = ' '; fDBCSTrailByte = TRUE; } } else { if ( !IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 2 ] ) ) { if ( IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 1 ] ) ) { textbuf[ yPos ][ xPos + StrLen ] = ' '; fDBCSTrailByte = TRUE; } } } if ( !lpStrAttr ) { // // If there are not attribute array, here we use default color, RED, // to display all of composition characters. // SetTextColor( hdc, CompColor[ 0 ] ); // default color ExtTextOut( hdc, xPos * cxMetrics, yPos * cyMetrics, ETO_OPAQUE, &rect, lpStr, StrLen, 0 ); } else { int ColorIndex; ExtTextOut( hdc, xPos * cxMetrics, yPos * cyMetrics, ETO_OPAQUE, &rect, NULL, 0, 0 ); for( i = 0; *lpStr;) { int cnt = IsDBCSLeadByte(*lpStr) ? 2 : 1; ColorIndex = ( ((int)*lpStrAttr) < 0 ) ? 0 : (int)*lpStrAttr; ColorIndex = ( ColorIndex > 3 ) ? 3 : ColorIndex; SetTextColor( hdc, CompColor[ ColorIndex ] ); TextOut( hdc, ( i + xPos ) * cxMetrics, yPos * cyMetrics, lpStr, cnt ); lpStr += cnt; lpStrAttr += cnt; i += cnt; } } SetTextColor( hdc, dwColor ); if ( fDBCSTrailByte ) { TextOut( hdc, ( xPos + StrLen ) * cxMetrics, yPos * cyMetrics, " ", 1 ); } SetCaretPos( ( xPos + StrLen ) * cxMetrics, yPos * cyMetrics ); ShowCaret( hwnd ); ReleaseDC( hwnd, hdc ); } //********************************************************************* // // void DisplayResultString() // // This displays result string. // // This function supports only fixed pitch font. // //********************************************************************* void DisplayResultString( HWND hwnd, LPSTR lpStr ) { int StrLen; // Storage for string length. int i; // Loop counter. HDC hdc; // Display context handle. StrLen = lstrlen( lpStr ); // // If there is no room for compsoition string, discard it // if ( xPos == ( LASTCOL - StrLen - 1 ) ) return; // // if insert mode or during composition session, // move rest of line to the right by StrLen bytes. // if ( fInsertMode ) { for( i = LASTCOL; i > xPos; i-- ) textbuf[ yPos ][ i ] = textbuf[ yPos ][ i - StrLen ]; // // If the row ends on a lead byte, blank it out, // To do this we must first traverse the string starting // from a know character boundry until we reach the last column. // If the last column is a character boundry then the last // character is either a string byte or a lead byte. // for( i = xPos + StrLen; i < LASTCOL; ) { if ( IsDBCSLeadByte( textbuf[ yPos ][ i ] ) ) i++; i++; } if ( i == LASTCOL && IsDBCSLeadByte( textbuf[ yPos ][ i ] ) ) textbuf[ yPos ][ LASTCOL ] = ' '; } else { // // overtype mode // if ( ( StrLen % 2 ) ) { if ( IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 1 ] ) ) textbuf[ yPos ][ xPos + StrLen ] = ' '; } else { if ( !IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 2 ] ) ) { // // Overtyping the current byte, plus the following byte // which could be a lead byte. // if ( IsDBCSLeadByte( textbuf[ yPos ][ xPos + StrLen - 1 ] ) ) textbuf[ yPos ][ xPos + StrLen ] = ' '; } } } // // Store input character at current caret position. // for( i = 0; i <= LASTCOL && *lpStr; i++ ) textbuf[ yPos ][ xPos + i ] = *lpStr++; // // Display input character // hdc = GetDC( hwnd ); HideCaret( hwnd ); // // Displays result string with normal color. // TextOut( hdc, xPos *cxMetrics, yPos * cyMetrics, (LPCSTR)&( textbuf[ yPos][xPos] ), MAXCOL - xPos ); ShowCaret( hwnd ); ReleaseDC( hwnd, hdc ); // // Reset Caret position // xPos += StrLen; if ( xPos > LASTCOL ) xPos = LASTCOL; ResetCaret( hwnd ); gImeUIData.uCompLen = 0; } //********************************************************************** // // void RestoreImeUI() // // This repaints all displayed composition string if need. // Main window procedure will call this upon receiving // WM_PAINT message. // //********************************************************************** void RestoreImeUI( HWND hwnd ) { HIMC hIMC; // Storage for input context handle. LONG bufLen; // // // If fail to get input context handle then do nothing. // if ( !( hIMC = ImmGetContext( hwnd ) ) ) return; // // If IME conversion engine is open and there are any composition // string in the context then we redisplay them. // if ( ImmGetOpenStatus( hIMC ) && gImeUIData.ImeState && ( bufLen = ImmGetCompositionString( hIMC, GCS_COMPSTR, (void *)NULL, 0l ) ) > 0 ) { LPSTR lpCompStr; // Pointer to composition string HLOCAL hMem; // Storage for memory handle. LPSTR lpCompStrAttr = NULL; // Pointer to composition string's attribute LONG bufLenAttr; // HLOCAL hMemAttr = NULL; // Memory handle for composition string's // attributes. // // If fail to allocate and lock memory space for reading in // the composition string then do nothing. // if ( !( hMem = LocalAlloc( LPTR, (int)bufLen + 1 ) ) ) goto exit2; if( !( lpCompStr = (LPSTR) LocalLock( hMem ) ) ) { LocalFree( hMem ); goto exit2; } // // Get composition string and redisplay them. // if ( ImmGetCompositionString( hIMC, GCS_COMPSTR, lpCompStr, bufLen ) > 0 ) { // // Make sure whether we need to handle composition string's // attributes. // if ( ( bufLenAttr = ( ImmGetCompositionString( hIMC, GCS_COMPATTR, (void FAR*)NULL, 0l ) ) ) > 0 ) { // // If fail to allocate and lock memory space for reading in // the composition string's attribute then we assume // no attribute array. // if ( !( hMemAttr = LocalAlloc(LPTR, (int)bufLenAttr + 1 ))) goto nothing; if ( !( lpCompStrAttr = (LPSTR) LocalLock( hMemAttr ) ) ) { LocalFree( hMemAttr ); goto nothing; } ImmGetCompositionString( hIMC, GCS_COMPATTR, lpCompStrAttr, bufLenAttr ); lpCompStrAttr[ bufLenAttr ] = 0; } else { nothing: lpCompStrAttr = NULL; } lpCompStr[ bufLen ] = 0; DisplayCompString( hwnd, lpCompStr, lpCompStrAttr ); } LocalUnlock( hMem ); LocalFree( hMem ); if ( lpCompStrAttr ) { if (NULL != hMemAttr) { LocalUnlock( hMemAttr ); LocalFree( hMemAttr ); } } } exit2: ImmReleaseContext( hwnd, hIMC ); } //********************************************************************** // // void ImeUIMove() // // Handler routine of WM_MOVE message. // //********************************************************************* void ImeUIMoveCandWin( HWND hwnd ) { if ( gImeUIData.ImeState & IME_IN_CHOSECAND ) { POINT point; // Storage for caret position. int i; // loop counter. int NumCandWin; // Storage for num of cand win. RECT rect; // Storage for client rect. // // If current IME state is in chosing candidate, here we // move all candidate windows, if any, to the appropriate // position based on the parent window's position. // NumCandWin = 0; GetCaretPos( &point ); ClientToScreen( hwnd, &point ); for ( i = 0; i < MAX_LISTCAND ; i++ ) { if ( gImeUIData.hListCand[ i ] ) { GetClientRect( gImeUIData.hListCand[ i ], &rect ); MoveWindow( gImeUIData.hListCand[ i ], point.x + X_INDENT * NumCandWin, point.y + Y_INDENT * NumCandWin + cyMetrics, ( rect.right - rect.left + 1 ), ( rect.bottom - rect.top + 1 ), TRUE ); NumCandWin++; } } } } //********************************************************************** // // void ImeUIClearData() // // Handler routine of WM_IME_SELECT message. // //********************************************************************** void ImeUIClearData( HWND hwnd ) { RECT rect; int i; SetWindowText( hwnd, szSteTitle ); // // If user switches to other IME, here we destroy all candidate // windows which has been opened and erase all composition // chars if any. // for( i = 0; i < MAX_LISTCAND; i++ ) { if ( gImeUIData.hListCand[ i ] ) { // // The i-th candidate list has already been displayed, // destroy it and free memory which stores candidate // strings. // DestroyWindow( gImeUIData.hListCand[ i] ); GlobalFree( gImeUIData.hListCandMem[ i ] ); gImeUIData.hListCand[ i ] = gImeUIData.hListCandMem[ i ] = NULL; } } // // Update client area. // GetClientRect( hwnd, &rect ); InvalidateRect( hwnd, &rect, FALSE ); // // Reset IMEUI's global data. // gImeUIData.uCompLen = gImeUIData.ImeState = 0; // // Reset caret to the original position. // HideCaret( hwnd ); ResetCaret( hwnd ); ShowCaret( hwnd ); }