#include "StdAfx.h" #include "EtUIIMEEditBox.h" #include "EtUIDialog.h" #ifdef _DEBUG #define new new(_NORMAL_BLOCK,__FILE__,__LINE__) #endif CEtUIIMEEditBox::CEtUIIMEEditBox( CEtUIDialog *pParent ) : CEtUIEditBox( pParent ), m_bFirstVisibleOver( false ) { m_Property.UIType = UI_CONTROL_IMEEDITBOX; m_Property.IMEEditBoxProperty.fIndicatorSize = 0.0f; m_dwCompTargetColor = D3DCOLOR_ARGB( 255, 255, 255, 255 ); m_dwCompTargetBkColor = D3DCOLOR_ARGB( 255, 150, 150, 150 ); m_dwCompTargetNonColor = D3DCOLOR_ARGB( 255, 255, 255, 0 ); m_dwCompTargetNonBkColor = D3DCOLOR_ARGB( 255, 150, 150, 150 ); m_bForceBottomPosition = false; m_nTempCompSize = 0; } CEtUIIMEEditBox::~CEtUIIMEEditBox(void) { } void CEtUIIMEEditBox::Initialize( SUIControlProperty *pProperty ) { CEtUIEditBox::Initialize( pProperty ); UpdateRects(); } void CEtUIIMEEditBox::SetTemplate( int nTemplateIndex ) { CEtUIEditBox::SetTemplate( nTemplateIndex ); if( m_Property.IMEEditBoxProperty.dwMaxChars == 0 ) m_Property.IMEEditBoxProperty.dwMaxChars = 256; SetMaxEditLength( m_Property.IMEEditBoxProperty.dwMaxChars ); } bool CEtUIIMEEditBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) { if( !IsEnable() || !IsShow() || !IsKeyLock() ) { return false; } #if defined(DEBUG) || defined(_DEBUG) assert( m_bIMEStaticMsgProcCalled && L"To fix, call CEtUIDialogResourceManager::MsgProc() first" ); #endif static LPARAM lAlt = 0x80000000, lCtrl = 0x80000000, lShift = 0x80000000; bool bpbTrappedData, *pbTrapped; HIMC hImc; pbTrapped = &bpbTrappedData; *pbTrapped = false; if( !s_bEnableImeSystem ) { return CEtUIEditBox::MsgProc( uMsg, wParam, lParam ); } // 참고자료. // IME 조합중에 오는 WM_KEYDOWN 의 wParam을 보면 항상 VK_PROCESSKEY다. // 원래의 vk값이 필요하다면, ImmGetVirtualKey함수를 통해 얻으면 되는데, // TranslateMessage가 호출되지 않은 상태여야만 한다. // 그런데 아래와 같은 코드는 백스페이스 제외하고 나머지는 디폴트 프로시저로 안보내서 IME처리가 안되게 하려는 코드처럼 보이겠지만, // 이렇게 해봤자 IME는 내부적으로 다 메세지를 처리하고 있다.(즉, 조합되고 있다.) // 이런 식으로 메세지를 무시하는 방법으로는 조합을 막을 수 없는 거 같다. //if( m_bFirstVisibleOver ) //{ // if( uMsg == WM_KEYDOWN && wParam == VK_PROCESSKEY ) // { // UINT nKey = ImmGetVirtualKey( m_pParent->GetHWnd() ); // if( nKey == VK_BACK ) // m_bFirstVisibleOver = false; // else // return true; // } //} switch( uMsg ) { case WM_IME_COMPOSITION: { // Note : m_Buffer가 static 변수가 아니라서 이 부분에서 체크를 한다. // 최대 길이라면 더 이상 문자 조합을 하지 않는다. // if( m_Buffer.IsMaxEditBoxLength() ) { PostMessage( GetFocus(), WM_IME_ENDCOMPOSITION, 0, 0 ); break; } // Note: 조합중인 문자열이 너무 길어서 완성된 문자열을 밀어내서 하나도 보이지 않게 되는 경우를 막는다. // 안그러면 m_nFirstVisible 값이 문자열 길이를 넘어가게 되어버림. // 백 스페이스를 제외한 글자가 추가되는 경우에만 체크한다. 안그러면 꽉찬 상황에서 지워지지도 않아서 먹통됨. if( m_bFirstVisibleOver ) { HIMC hImc; hImc = _ImmGetContext( m_pParent->GetHWnd() ); _ImmNotifyIME( hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ); _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); m_bFirstVisibleOver = false; break; // #14215 이슈(m_bFirstVisibleOver 상태가 되었을때 위에처럼 리셋하지 말고 유지되게 하기)를 해결하기 위해 여러가지로 시도를 했었다. // 1. 우선 이렇게 리셋되는 이유가 m_bFirstVisibleOver 상태로 바꾸는 거 자체가 별로라 생각되서, // m_bFirstVisibleOver를 true로 만드는 PlaceCaret 검사부분에서 ImmSetCompositionString을 호출해 조합중인 글자의 길이를 조절하려 했으나 // 아무리 설정해도 함수가 FALSE를 리턴한다. // 구글에서 찾아봐도 안된다고 하는 사람은 많은데, 어떻게 고쳐야된다고 적어둔건 하나도 못찾았다. // 2. ImmProcessKey나 ImmLockIMC를 이용해 사이즈 제한을 두려 했으나, 함수콜이 실패해서 안됨. // 3. 여러 함수들이 제대로 작동하지 않아서 메세지 자체를 막기로 했다. // 그래서 WM_IME_COMPOSITION 을 디폴트 프로시저로 안보내 무시하려고 했으나, // 디폴트 프로시저로 가지 않더라도 IME가 내부적으로 메세지를 따로 받기때문에 조합Result를 얻어보면 계속 조합되고 있는 상태의 스트링이 전달되었다. // 즉, 메세지를 안보내는 방법으로도 조합 맥스길이 조절 실패. // (디폴트 프로시저로 IME메세지를 안보내도 내부적으로 처리되고 있다는 걸 확인하고 싶다면, // m_bFirstVisibleOver 일때 return true 해놓고, 쭉 입력해보면, 조합윈도우에 더이상 문자가 추가되지 않으나, // 알트탭 한번 했다오면, wm_paint로 갱신되면서 눌렀던 글자들이 모두 조합되있는것을 확인할 수 있다.) // 4. 그래서 계속 찾아보니 키보드 후킹을 통해서만, IME로 가는 메세지를 차단할 수 있었다고 한다. // 5. 대부분의 경우엔 조합중인 글자에 대해서는 길이제한을 두지 않고, 조합 Result로 올때 길이제한을 건다고 한다. // // 단지 길이제한을 위해서, 키보드후킹까지 쓰는건 좀 별로인거 같아서 // 좋은 개선안이 생기기 전까지 우선 현재 방법대로 유지하도록 하겠다. // 아니면 그냥 현재까지 조합된 글자를 강제로 Result로 내보내던지.. } LONG lRet; WCHAR wszCompStr[ MAX_COMPSTRING_SIZE ]={0}; *pbTrapped = true; hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc == NULL ) { break; } if( lParam & GCS_CURSORPOS ) { s_nCompCaret = _ImmGetCompositionStringW( hImc, GCS_CURSORPOS, NULL, 0 ); if( s_nCompCaret < 0 ) { s_nCompCaret = 0; } } if( lParam & GCS_RESULTSTR ) { lRet = _ImmGetCompositionStringW( hImc, GCS_RESULTSTR, wszCompStr, sizeof( wszCompStr ) ); if( lRet > 0 ) { lRet /= sizeof( WCHAR ); wszCompStr[ lRet ] = 0; TruncateCompString( false, ( int )wcslen( wszCompStr ) ); s_CompString.SetText( wszCompStr ); if( CEtUIIME::s_bRESULTSTR_NotSendComp == false ) { SendCompString(); } else { GetEtDevice()->SetDialogBoxMode(false); CEtUIIME::s_bRESULTSTR_NotSendComp = true; } ResetCompositionString(); } } if( lParam & GCS_COMPSTR ) { lRet = _ImmGetCompositionStringW( hImc, GCS_COMPSTR, wszCompStr, sizeof( wszCompStr ) ); if( lRet > 0 ) { int i; lRet /= sizeof( WCHAR ); wszCompStr[ lRet ] = 0; TruncateCompString( false, ( int )wcslen( wszCompStr ) ); s_CompString.SetText( wszCompStr ); m_pParent->ProcessCommand(EVENT_EDITBOX_IME_CHANGE, true, this, WM_IME_COMPOSITION); if( ( GetLanguage() == LANG_CHT ) && ( !GetImeId() ) ) { if( lstrlenW( s_CompString.GetBuffer() ) ) { s_CandList.dwCount = 4; s_CandList.dwSelection = ( DWORD ) - 1; for( i = 3; i >= 0; i-- ) { if( i > lstrlenW( s_CompString.GetBuffer() ) - 1 ) { s_CandList.awszCandidate[ i ][ 0 ] = 0; } else { s_CandList.awszCandidate[ i ][ 0 ] = s_CompString[ i ]; s_CandList.awszCandidate[ i ][ 1 ] = 0; } } s_CandList.dwPageSize = MAX_CANDLIST; memset( ( void * )s_CompString.GetBuffer(), 0, sizeof( WCHAR ) * 4 ); s_bShowReadingWindow = true; GetReadingWindowOrientation( 0 ); if( s_bHorizontalReading ) { s_CandList.nReadingError = -1; s_wszReadingString[ 0 ] = 0; for( i = 0; i < ( int )s_CandList.dwCount; i++ ) { if( s_CandList.dwSelection == i ) { s_CandList.nReadingError = lstrlenW( s_wszReadingString ); } wcscat_s( s_wszReadingString, 32, s_CandList.awszCandidate[ i ] ); } } } else { s_CandList.dwCount = 0; s_bShowReadingWindow = false; } } if( s_bInsertOnType ) { int nCount; SendCompString(); nCount = lstrlenW( s_CompString.GetBuffer() + s_nCompCaret ); for( i = 0; i < nCount; i++ ) { SendMessage( m_pParent->GetHWnd(), WM_KEYDOWN, VK_LEFT, 0 ); } SendMessage( m_pParent->GetHWnd(), WM_KEYUP, VK_LEFT, 0 ); } } ResetCaretBlink(); // Note : 한글조합중에 문자열이 컨트롤의 크기를 벗어나는 것을 조정한다. // 현재는 한글만 테스트 했고 이 후에 중국, 일본의 경우도 체크해야 한다. // // 위치는 여기가 되야한다. PlaceCaret( (int)lRet ); } if( lParam & GCS_COMPATTR ) { lRet = _ImmGetCompositionStringW( hImc, GCS_COMPATTR, s_abyCompStringAttr, sizeof( s_abyCompStringAttr ) ); if( lRet > 0 ) { s_abyCompStringAttr[lRet] = 0; } } if( CEtUIIME::s_bProcess_GCS_COMPCLAUSE ) { if( lParam & GCS_COMPCLAUSE ) { lRet = _ImmGetCompositionStringW( hImc, GCS_COMPCLAUSE, s_adwCompStringClause, sizeof( s_adwCompStringClause ) ); s_adwCompStringClause[ lRet / sizeof( DWORD ) ] = 0; } } if( CEtUIIME::s_bRESULTSTR_NotSendComp == true ) { // 컴포지션 윈도우 위치 조정. float fX1 = CEtUIIMEEditBox::s_CurrentCaretPos.fX * m_pParent->GetScreenWidth(); float fX2 = CEtUIIMEEditBox::s_CurrentCaretPos.fY * m_pParent->GetScreenHeight(); RECT rcWindow; GetWindowRect( m_pParent->GetHWnd(), &rcWindow ); POINT pt; pt.x = (long)fX1 - rcWindow.left; pt.y = (long)fX2 - rcWindow.top; // 풀스크린때는 윈도우 캡션을 고려하지 않고 그 자리에 렌더링해 원래 입력창이 가려진다. // 그래서 강제로 20픽셀 내리도록 하겠다. if( !(GetWindowLong( m_pParent->GetHWnd(), GWL_STYLE ) & WS_CAPTION) ) pt.y += 20; ClientToScreen(m_pParent->GetHWnd(), &pt); COMPOSITIONFORM cf; cf.dwStyle = CFS_POINT; cf.ptCurrentPos.x = pt.x; cf.ptCurrentPos.y = pt.y; ImmSetCompositionWindow(hImc, &cf); } _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); if( CEtUIIME::s_bRESULTSTR_NotSendComp == true ) { return CEtUIEditBox::MsgProc( uMsg, wParam, lParam ); } } break; case WM_IME_ENDCOMPOSITION: TruncateCompString(); ResetCompositionString(); s_bHideCaret = false; s_bShowReadingWindow = false; m_pParent->ProcessCommand(EVENT_EDITBOX_IME_CHANGE, true, this, WM_IME_ENDCOMPOSITION); break; case WM_IME_NOTIFY: switch( wParam ) { case IMN_SETCONVERSIONMODE: case IMN_SETOPENSTATUS: CheckToggleState(); break; case IMN_OPENCANDIDATE: case IMN_CHANGECANDIDATE: { int i, j; LPCANDIDATELIST lpCandList; DWORD dwLenRequired; s_CandList.bShowWindow = true; *pbTrapped = true; hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc == NULL ) { break; } lpCandList = NULL; s_bShowReadingWindow = false; dwLenRequired = _ImmGetCandidateListW( hImc, 0, NULL, 0 ); if( dwLenRequired ) { lpCandList = ( LPCANDIDATELIST )HeapAlloc( GetProcessHeap(), 0, dwLenRequired ); dwLenRequired = _ImmGetCandidateListW( hImc, 0, lpCandList, dwLenRequired ); } if( lpCandList ) { int nPageTopIndex; s_CandList.dwSelection = lpCandList->dwSelection; s_CandList.dwCount = lpCandList->dwCount; nPageTopIndex = 0; s_CandList.dwPageSize = min( lpCandList->dwPageSize, MAX_CANDLIST ); if( GetPrimaryLanguage() == LANG_JAPANESE ) { nPageTopIndex = ( s_CandList.dwSelection / s_CandList.dwPageSize ) * s_CandList.dwPageSize; } else { nPageTopIndex = lpCandList->dwPageStart; } if( GetLanguage() == LANG_CHS && !GetImeId() ) { s_CandList.dwSelection = ( DWORD ) - 1; } else { s_CandList.dwSelection = s_CandList.dwSelection - nPageTopIndex; } memset( s_CandList.awszCandidate, 0, sizeof(s_CandList.awszCandidate) ); for( i = nPageTopIndex, j = 0; i < ( int )lpCandList->dwCount && j < ( int )s_CandList.dwPageSize; i++, j++ ) { LPWSTR pwsz; WCHAR *pwszNewCand; pwsz = s_CandList.awszCandidate[ j ]; *pwsz = ( WCHAR )( L'0' + ( ( j + 1 ) % 10 ) ); pwsz++; if( s_bVerticalCand ) { *pwsz = L' '; pwsz++; } pwszNewCand = ( LPWSTR )( ( BYTE * )lpCandList + lpCandList->dwOffset[ i ] ); while( *pwszNewCand ) { *pwsz = *pwszNewCand; pwsz++; pwszNewCand++; } if( !s_bVerticalCand ) { *pwsz = L' '; pwsz++; } *pwsz = 0; } s_CandList.dwCount = lpCandList->dwCount - lpCandList->dwPageStart; if( s_CandList.dwCount > lpCandList->dwPageSize ) { s_CandList.dwCount = lpCandList->dwPageSize; } HeapFree( GetProcessHeap(), 0, lpCandList ); _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); if( GetPrimaryLanguage() == LANG_KOREAN || GetLanguage() == LANG_CHT && !GetImeId() ) { s_CandList.dwSelection = ( DWORD ) - 1; } if( !s_bVerticalCand ) { WCHAR wszCand[ 256 ] = L""; s_CandList.nFirstSelected = 0; s_CandList.nHoriSelectedLen = 0; for( i = 0; i < MAX_CANDLIST; i++ ) { WCHAR wszEntry[ 32 ]; if( s_CandList.awszCandidate[ i ][ 0 ] == L'\0' ) { break; } swprintf_s( wszEntry, 32, L"%s ", s_CandList.awszCandidate[ i ] ); if( i == s_CandList.dwSelection ) { s_CandList.nFirstSelected = lstrlenW( wszCand ); s_CandList.nHoriSelectedLen = lstrlenW( wszEntry ) - 1; } wcscat_s( wszCand, 256, wszEntry ); } wszCand[ lstrlenW( wszCand ) - 1 ] = L'\0'; s_CandList.HoriCand.SetText( wszCand ); } } break; } case IMN_CLOSECANDIDATE: { s_CandList.bShowWindow = false; if( !s_bShowReadingWindow ) { s_CandList.dwCount = 0; memset( s_CandList.awszCandidate, 0, sizeof( s_CandList.awszCandidate ) ); } *pbTrapped = true; break; } case IMN_PRIVATE: { DWORD dwId; if( !s_CandList.bShowWindow ) { GetPrivateReadingString(); } dwId = GetImeId(); switch( dwId ) { case IMEID_CHT_VER42: case IMEID_CHT_VER43: case IMEID_CHT_VER44: case IMEID_CHS_VER41: case IMEID_CHS_VER42: if( ( lParam == 1 ) || ( lParam == 2 ) ) { *pbTrapped = true; } break; case IMEID_CHT_VER50: case IMEID_CHT_VER51: case IMEID_CHT_VER52: case IMEID_CHT_VER60: case IMEID_CHS_VER53: if( (lParam == 16) || (lParam == 17) || (lParam == 26) || (lParam == 27) || (lParam == 28) ) { *pbTrapped = true; } break; } } break; default: *pbTrapped = true; break; } break; case WM_KEYUP: case WM_SYSKEYUP: if( !( lAlt & 0x80000000 ) && wParam != VK_MENU && ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) == 0 ) { PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_MENU, ( lAlt & 0x01ff0000 ) | 0xC0000001 ); } else if( !( lCtrl & 0x80000000 ) && wParam != VK_CONTROL && ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) == 0 ) { PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_CONTROL, ( lCtrl & 0x01ff0000 ) | 0xC0000001 ); } else if( !( lShift & 0x80000000 ) && wParam != VK_SHIFT && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 ) { PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_SHIFT, ( lShift & 0x01ff0000 ) | 0xC0000001 ); } case WM_KEYDOWN: case WM_SYSKEYDOWN: switch ( wParam ) { case VK_MENU: lAlt = lParam; break; case VK_SHIFT: lShift = lParam; break; case VK_CONTROL: lCtrl = lParam; break; } default: return CEtUIEditBox::MsgProc( uMsg, wParam, lParam ); } return *pbTrapped; } bool CEtUIIMEEditBox::HandleMouse( UINT uMsg, float fX, float fY, WPARAM wParam, LPARAM lParam ) { if( !IsEnable() || !IsShow() || !IsKeyLock() ) { return false; } switch( uMsg ) { case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: { float fFontHeight = m_pParent->GetFontHeight( m_Template.m_vecElement[5].nFontIndex, m_Template.m_vecElement[5].nFontHeight ); //ID3DXFont *pFont = m_pParent->GetFont( m_Template.m_vecElement[5].nFontIndex, m_Template.m_vecElement[5].nFontHeight ); int nCompStrWidth = 0; CEtFontMng& FontMng = CEtFontMng::GetInstance(); SUIElement* pElement = GetElement( 0 ); nCompStrWidth = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_CompString.GetTextSize() ); //s_CompString.CPtoX( s_CompString.GetTextSize(), FALSE, &nCompStrWidth ); if( ( s_fCompStringX <= fX ) && ( s_fCompStringY <= fY ) && ( s_fCompStringX + nCompStrWidth / m_pParent->GetScreenWidth() > fX ) && ( s_fCompStringY + fFontHeight > fY ) ) { HIMC hImc; int nCharBodyHit, nCharHit; int nTrail; nCharBodyHit = FontMng.GetCaretFromCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, (int)((fX - s_fCompStringX) * m_pParent->GetScreenWidth()), nTrail ); //s_CompString.XtoCP( ( int )( ( fX - s_fCompStringX ) * m_pParent->GetScreenWidth() ), &nCharBodyHit, &nTrail ); if( ( nTrail ) && ( nCharBodyHit < s_CompString.GetTextSize() ) ) { nCharHit = nCharBodyHit + 1; } else { nCharHit = nCharBodyHit; } hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( !hImc ) { return true; } _ImmNotifyIME( hImc, NI_CLOSECANDIDATE, 0, 0 ); _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); switch( GetPrimaryLanguage() ) { case LANG_JAPANESE: if( s_nFirstTargetConv != -1 ) { int nClauseClicked, nClauseSelected, nSendCount; BYTE byVirtKey; nClauseClicked = 0; while( ( int )s_adwCompStringClause[ nClauseClicked + 1 ] <= nCharBodyHit ) { nClauseClicked++; } nClauseSelected = 0; while( ( int )s_adwCompStringClause[ nClauseSelected + 1 ] <= s_nFirstTargetConv ) { nClauseSelected++; } if( nClauseClicked > nClauseSelected ) { byVirtKey = VK_RIGHT; } else { byVirtKey = VK_LEFT; } nSendCount = abs( nClauseClicked - nClauseSelected ); while( nSendCount-- > 0 ) { SendKey( byVirtKey ); } return true; } case LANG_CHINESE: { BYTE byVirtKey; int nSendCount; if( nCharHit > s_nCompCaret ) { byVirtKey = VK_RIGHT; } else { byVirtKey = VK_LEFT; } nSendCount = abs( nCharHit - s_nCompCaret ); while( nSendCount-- > 0 ) { SendKey( byVirtKey ); } break; } } return true; } if( ( s_CandList.bShowWindow ) && ( s_CandList.CandidateCoord.IsInside( fX, fY ) ) ) { if( s_bVerticalCand ) { int nRow; nRow = ( int )( ( fY - s_CandList.CandidateCoord.fY ) / fFontHeight ); if( nRow < ( int )s_CandList.dwCount ) { switch( GetPrimaryLanguage() ) { case LANG_CHINESE: case LANG_KOREAN: SendKey( ( BYTE ) ( '0' + nRow + 1 ) ); break; case LANG_JAPANESE: { BYTE byVirtKey; int nNumToHit, nStrike; if( nRow > ( int )s_CandList.dwSelection ) { byVirtKey = VK_DOWN; } else { byVirtKey = VK_UP; } nNumToHit = abs( ( int) ( nRow - s_CandList.dwSelection ) ); for( nStrike = 0; nStrike < nNumToHit; nStrike++ ) { SendKey( byVirtKey ); } SendKey( VK_RIGHT ); SendKey( VK_LEFT ); break; } } } } else { int i, nCharHit, nTrail, nCandidate, nEntryStart; nCharHit = FontMng.GetCaretFromCaretPos( s_CandList.HoriCand.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, (int)((fX - s_CandList.CandidateCoord.fX) * m_pParent->GetScreenWidth()), nTrail ); //s_CandList.HoriCand.XtoCP( ( int )( ( fX - s_CandList.CandidateCoord.fX ) * m_pParent->GetScreenWidth() ), &nCharHit, &nTrail ); nCandidate = s_CandList.dwCount - 1; nEntryStart = 0; for( i = 0; i < ( int )s_CandList.dwCount; i++ ) { if( nCharHit >= nEntryStart ) { nEntryStart += lstrlenW( s_CandList.awszCandidate[ i ] ) + 1; } else { nCandidate = i - 1; break; } } switch( GetPrimaryLanguage() ) { case LANG_CHINESE: case LANG_KOREAN: SendKey( ( BYTE ) ( '0' + nCandidate + 1 ) ); break; } } return true; } } } return CEtUIEditBox::HandleMouse( uMsg, fX, fY, wParam, lParam ); } void CEtUIIMEEditBox::Focus( bool fFocus ) { CEtUIEditBox::Focus( fFocus ); // 중국 일부 IME의 경우 강제로 아래처럼 막아주지 않으면 // 디폴트프로시저로 들어오는 영문자들 다 받아채서 캔디데이트를 띄워버린다. // // 포커스가 없을때 한영키 전환이 안된다는 것때문에 국내빌드에선 사용하지 않는 것일지도 모르겠지만, // 해외빌드에선 제공되는 IME를 사용해야하고, 포커스가 없을때도 뜨는 캔디데이트를 방지하기 위해, 아래 코드를 사용해야만 한다. // // EtInterface에서는 국가별 디파인이 없으므로 static bool 값으로 외부에서 설정받아 사용한다. if( CEtUIIME::s_bDisableIMEonKillFocus ) { if( fFocus ) { HIMC hImc; if( s_bEnableImeSystem ) { _ImmAssociateContext( m_pParent->GetHWnd(), s_hImcDef ); CheckToggleState(); } else { _ImmAssociateContext( m_pParent->GetHWnd(), NULL ); } hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc != NULL ) { if( !s_bEnableImeSystem ) { s_ImeState = IMEUI_STATE_OFF; } _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); CheckToggleState(); } } else { FinalizeString( false ); _ImmAssociateContext( m_pParent->GetHWnd(), NULL ); } } } void CEtUIIMEEditBox::PumpMessage() { MSG msg; while( PeekMessageW( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { if( !GetMessageW( &msg, NULL, 0, 0 ) ) { PostQuitMessage( (int)msg.wParam ); return; } TranslateMessage( &msg ); DispatchMessageA( &msg ); } } void CEtUIIMEEditBox::UpdateRects() { float fTempWidth; fTempWidth = m_Property.UICoord.fWidth; if( m_Property.IMEEditBoxProperty.fIndicatorSize > 0.0f ) { m_Property.UICoord.fWidth -= m_Property.IMEEditBoxProperty.fIndicatorSize + m_Property.IMEEditBoxProperty.fBorder * 2; } CEtUIEditBox::UpdateRects(); m_IndicatorCoord.SetCoord( m_Property.UICoord.Right(), m_Property.UICoord.fY, m_Property.IMEEditBoxProperty.fIndicatorSize + m_Property.IMEEditBoxProperty.fBorder * 2, m_Property.UICoord.fHeight ); m_Property.UICoord.fWidth = fTempWidth; } void CEtUIIMEEditBox::Show( bool bShow ) { CEtUIControl::Show( bShow ); s_bHideCaret = false; } void CEtUIIMEEditBox::Render( float fElapsedTime ) { if( !IsShow() ) { return; } /* if( m_Property.IMEEditBoxProperty.fIndicatorSize <= 0.0f ) { int i; for( i = 0; i < 5; i++ ) { SUICoord Coord; Coord.SetCoord( 0.0f, 0.0f, 0.1f, 0.1f ); m_pParent->CalcTextRect( s_aszIndicator[ i ], &m_Template.m_vecElement[ 5 ], Coord ); m_Property.IMEEditBoxProperty.fIndicatorSize = max( m_Property.IMEEditBoxProperty.fIndicatorSize, Coord.fWidth ); } UpdateRects(); }*/ SUIElement *pElement; pElement = GetElement(0); if( pElement ) { m_fCompositionWidth = 0.0f; if( m_bFocus && s_bHideCaret ) { SUICoord CompCoord; m_pParent->CalcTextRect( s_CompString.GetBuffer(), pElement, CompCoord ); m_fCompositionWidth = CompCoord.fWidth; } CEtUIEditBox::Render( fElapsedTime ); //ID3DXFont *pFont = m_pParent->GetFont( pElement->nFontIndex, pElement->nFontHeight ); //s_CompString.SetFont( pFont ); //s_CandList.HoriCand.SetFont( pFont ); } if( CEtUIIME::s_bDisableIMEonIMEControl ) return; if( m_bFocus ) { RenderIndicator( fElapsedTime ); if( s_bHideCaret ) RenderComposition( fElapsedTime ); if( s_bShowReadingWindow ) { RenderCandidateReadingWindow( fElapsedTime, true ); } else if( s_CandList.bShowWindow ) { RenderCandidateReadingWindow( fElapsedTime, false ); } } } void CEtUIIMEEditBox::RenderCandidateReadingWindow( float fElapsedTime, bool bReading ) { UINT i, nNumEntries; SUICoord Coord; DWORD dwTextColor, dwTextBkColor, dwSelTextColor, dwSelBkColor; int nX, nXFirst, nXComp; nNumEntries = MAX_CANDLIST; if( bReading ) { nNumEntries = 4; } CEtFontMng& FontMng = CEtFontMng::GetInstance(); SUIElement* pElement = GetElement( 0 ); nX = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nCaret ); nXFirst = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nFirstVisible ); //m_Buffer.CPtoX( m_nCaret, FALSE, &nX ); //m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst ); if( bReading ) { dwTextColor = m_Property.IMEEditBoxProperty.dwReadingTextColor; dwTextBkColor = m_Property.IMEEditBoxProperty.dwReadingBackColor; dwSelTextColor = m_Property.IMEEditBoxProperty.dwReadingSelTextColor; dwSelBkColor = m_Property.IMEEditBoxProperty.dwReadingSelBackColor; } else { dwTextColor = m_Property.IMEEditBoxProperty.dwCandiTextColor; dwTextBkColor = m_Property.IMEEditBoxProperty.dwCandiBackColor; dwSelTextColor = m_Property.IMEEditBoxProperty.dwCandiSelTextColor; dwSelBkColor = m_Property.IMEEditBoxProperty.dwCandiSelBackColor; } if( ( GetLanguage() == LANG_CHT ) && ( !GetImeId() ) ) { nXComp = 0; } else { if( GetPrimaryLanguage() == LANG_JAPANESE ) { nXComp = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_nFirstTargetConv ); //s_CompString.CPtoX( s_nFirstTargetConv, FALSE, &nXComp ); } else { nXComp = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_nCompCaret ); //s_CompString.CPtoX( s_nCompCaret, FALSE, &nXComp ); } } //SUIElement *pElement = GetElement(0); if( !pElement ) return; float fWidthRequired = 0.0f; float fHeightRequired = 0.0f; float fSingleLineHeight = 0.0f; if( ( s_bVerticalCand && !bReading ) || ( !s_bHorizontalReading && bReading ) ) { for( i = 0; i < nNumEntries; i++ ) { if( s_CandList.awszCandidate[ i ][ 0 ] == L'\0' ) { break; } Coord.SetCoord( 0.0f, 0.0f, 0.0f, 0.0f ); m_pParent->CalcTextRect( s_CandList.awszCandidate[i], pElement, Coord ); fWidthRequired = max( fWidthRequired, Coord.fWidth ); fSingleLineHeight = max( fSingleLineHeight, Coord.fHeight ); } fHeightRequired = fSingleLineHeight * nNumEntries; } else { Coord.SetCoord( 0.0f, 0.0f, 0.0f, 0.0f ); if( bReading ) { m_pParent->CalcTextRect( s_wszReadingString, pElement, Coord ); } else { m_pParent->CalcTextRect( s_CandList.HoriCand.GetBuffer(), pElement, Coord ); } // 너무 꽉차게 그리지 않고 여유를 좀 두기 위해서 공간을 준다 Coord.fWidth += 0.01f; Coord.fHeight += 0.01f; fWidthRequired = Coord.fWidth;; fSingleLineHeight = Coord.fHeight; fHeightRequired = Coord.fHeight; } bool bHasPosition = false; Coord.SetCoord( s_fCompStringX + FloatXCoord( nXComp ), s_fCompStringY + m_TextCoord.fHeight, fWidthRequired, fHeightRequired ); if( Coord.Right() > m_pParent->Width() ) { Coord.fX -= Coord.Right() - m_pParent->Width(); Coord.fWidth = m_pParent->Width() - Coord.fX; } if( Coord.Bottom() <= m_pParent->Height() ) { bHasPosition = true; } else if( m_bForceBottomPosition ) { bHasPosition = true; } if( !bHasPosition ) { Coord.SetCoord( s_fCompStringX + FloatXCoord( nXComp ), s_fCompStringY - fHeightRequired, fWidthRequired, fHeightRequired ); if( Coord.Right() > m_pParent->Width() ) { Coord.fX -= Coord.Right() - m_pParent->Width(); Coord.fWidth = m_pParent->Width(); } if( Coord.fY >= 0.0f ) { bHasPosition = true; } } if( !bHasPosition ) { int nXCompTrail; nXCompTrail = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_nCompCaret ); //s_CompString.CPtoX( s_nCompCaret, TRUE, &nXCompTrail ); Coord.SetCoord( s_fCompStringX + FloatXCoord( nXCompTrail ), 0.0f, fWidthRequired, fHeightRequired ); if( Coord.Right() <= m_pParent->Width() ) { bHasPosition = true; } } if( !bHasPosition ) { Coord.SetCoord( s_fCompStringX + FloatXCoord( nXComp ) - fWidthRequired, 0.0f, fWidthRequired, fHeightRequired ); if( Coord.Right() >= 0.0f ) { bHasPosition = true; } } if( !bHasPosition ) { Coord.fX = 0.0f; Coord.fWidth = fWidthRequired; } if( !bReading ) { s_CandList.CandidateCoord = Coord; } m_pParent->DrawRect( Coord, dwTextBkColor ); if( ( s_bVerticalCand && !bReading ) || ( !s_bHorizontalReading && bReading ) ) { for( i = 0; i < nNumEntries; i++ ) { Coord.fHeight = fSingleLineHeight; if( s_CandList.dwSelection == i ) { m_pParent->DrawRect( Coord, dwSelBkColor ); m_pParent->DrawDlgText( s_CandList.awszCandidate[ i ], pElement, dwSelTextColor, Coord ); } else { m_pParent->DrawDlgText( s_CandList.awszCandidate[ i ], pElement, dwTextColor, Coord ); } Coord.fY += fSingleLineHeight; } } else { if( bReading ) { //m_pParent->DrawDlgText( s_wszReadingString, pElement, dwTextColor, Coord ); m_pParent->DrawDlgText( s_wszReadingString, pElement, dwTextColor, Coord, -1, -1, true ); } else { m_pParent->DrawDlgText( s_CandList.HoriCand.GetBuffer(), pElement, dwTextColor, Coord, -1, -1, true/*, DT_VCENTER | DT_CENTER*/ ); } if( !bReading ) { int nXLeft, nXRight; nXLeft = FontMng.GetCaretPos( s_CandList.HoriCand.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_CandList.nFirstSelected ); //s_CandList.HoriCand.CPtoX( s_CandList.nFirstSelected, FALSE, &nXLeft ); nXRight = FontMng.GetCaretPos( s_CandList.HoriCand.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_CandList.nFirstSelected + s_CandList.nHoriSelectedLen ); if( nXLeft != nXRight ) { //s_CandList.HoriCand.CPtoX( s_CandList.nFirstSelected + s_CandList.nHoriSelectedLen, FALSE, &nXRight ); Coord.fWidth = FloatXCoord( nXRight - nXLeft ); Coord.fX += FloatXCoord( nXLeft ); m_pParent->DrawRect( Coord, dwSelBkColor ); m_pParent->DrawDlgText( s_CandList.HoriCand.GetBuffer() + s_CandList.nFirstSelected, pElement, dwSelTextColor, Coord, -1, -1, true ); } } } } void CEtUIIMEEditBox::RenderComposition( float fElapsedTime ) { int nX, nXFirst; CEtFontMng& FontMng = CEtFontMng::GetInstance(); SUIElement* pElement = GetElement( 0 ); nX = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nCaret ); //m_Buffer.CPtoX( m_nCaret, FALSE, &nX ); nXFirst = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nFirstVisible ); //m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst ); SUICoord CompCoord, FirstCoord, CaretCoord; //SUIElement *pElement = GetElement(0); if( !pElement ) return; CompCoord.SetCoord( m_TextCoord.fX + ( nX - nXFirst ) / m_pParent->GetScreenWidth(), m_TextCoord.fY, 0.1f, m_TextCoord.fHeight ); m_pParent->CalcTextRect( s_CompString.GetBuffer(), pElement, CompCoord ); //if( CompCoord.Right() > m_TextCoord.Right() ) //{ // CompCoord.fX += m_TextCoord.fX - CompCoord.fX; // CompCoord.fY += CompCoord.fHeight; //} FirstCoord = CompCoord; s_fCompStringX = CompCoord.fX; s_fCompStringY = CompCoord.fY; int nCharLeft; const WCHAR *pwszComp; DWORD dwTextColor; dwTextColor = m_Property.IMEEditBoxProperty.dwCompTextColor; pElement->FontColor.dwCurrentColor = dwTextColor; pwszComp = s_CompString.GetBuffer(); nCharLeft = s_CompString.GetTextSize(); if( nCharLeft == 0 ) return; while( 1 ) { int nLastInLine, nTrail, nNumCharToDraw; nLastInLine = FontMng.GetCaretFromCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, (int)((CompCoord.fX + CompCoord.fWidth - m_TextCoord.fX) * m_pParent->GetScreenWidth() + 0.0001f), nTrail ); // 23.9999때문에 23으로 int화 되서 그냥 0.0001 더해 올림처리 한다. if( 0 == nLastInLine ) nLastInLine = 1; // Note: Trail 값은 무조건 1임.. 폰트매니져에서 새로 캐싱된 문자열은 Trail 값이 딸려 나오므로 더해줘야함.. if( 0 != nTrail ) nLastInLine += 1; //s_CompString.XtoCP( ( int )( ( m_TextCoord.Right() - CompCoord.fX ) * m_pParent->GetScreenWidth() ), &nLastInLine, &bTrail ); nNumCharToDraw = min( nCharLeft, nLastInLine ); m_pParent->CalcTextRect( pwszComp, pElement, CompCoord, nNumCharToDraw ); CompCoord.fHeight = m_TextCoord.fHeight; if( GetPrimaryLanguage() == LANG_KOREAN ) { if( m_bCaretOn ) { m_pParent->DrawRect( CompCoord, m_Property.IMEEditBoxProperty.dwCompBackColor ); } else { dwTextColor = pElement->FontColor.dwColor[ UI_STATE_NORMAL ]; } } else { m_pParent->DrawRect( CompCoord, m_Property.IMEEditBoxProperty.dwCompBackColor ); } pElement->FontColor.dwCurrentColor = dwTextColor; //CEtFontMng::GetInstance().EnableFreeType( false ); m_pParent->DrawDlgText( pwszComp, pElement, dwTextColor, CompCoord, nNumCharToDraw ); //CEtFontMng::GetInstance().EnableFreeType( true ); nCharLeft -= nNumCharToDraw; pwszComp += nNumCharToDraw; if( nCharLeft <= 0 ) { break; } CompCoord.fX += m_TextCoord.fX - CompCoord.fX; CompCoord.fY += CompCoord.fHeight; } //CompCoord = FirstCoord; CompCoord.fX = FirstCoord.fX; CompCoord.fY = FirstCoord.fY; CompCoord.fWidth = FirstCoord.fWidth; int nCharFirst; BYTE *pAttr; const WCHAR *pcComp; nCharFirst = 0; nXFirst = 0; s_nFirstTargetConv = -1; for( pcComp = s_CompString.GetBuffer(), pAttr = s_abyCompStringAttr; *pcComp != L'\0'; pcComp++, pAttr++ ) { DWORD dwBkColor; int nXLeft, nXRight; nXLeft = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, int(pcComp - s_CompString.GetBuffer()) ); //s_CompString.CPtoX( ( int )( pcComp - s_CompString.GetBuffer() ), FALSE, &nXLeft ); nXRight = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_CompString.GetTextSize() ); //s_CompString.CPtoX( ( int )( pcComp - s_CompString.GetBuffer() ), TRUE, &nXRight ); if( m_bFirstVisibleOver == false && m_nTempCompSize == 0 ) { if( nXRight - nXFirst > ( int )( ( m_TextCoord.Right() - CompCoord.fX ) * m_pParent->GetScreenWidth() ) ) { CompCoord.fX += m_TextCoord.fX - CompCoord.fX; CompCoord.fY += CompCoord.fHeight; nCharFirst = ( int )( pcComp - s_CompString.GetBuffer() ); nXFirst = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, nCharFirst ); //s_CompString.CPtoX( nCharFirst, FALSE, &nXFirst ); } } if( s_nCompCaret == ( int )( pcComp - s_CompString.GetBuffer() ) ) { CaretCoord = CompCoord; CaretCoord.fX += ( nXLeft - nXFirst - 1 ) / m_pParent->GetScreenWidth(); CaretCoord.fWidth = 2.0f / m_pParent->GetScreenWidth(); } if( *pAttr == ATTR_TARGET_CONVERTED ) { pElement->FontColor.dwCurrentColor = m_dwCompTargetColor; dwBkColor = m_dwCompTargetBkColor; } else { if( *pAttr == ATTR_TARGET_NOTCONVERTED ) { pElement->FontColor.dwCurrentColor = m_dwCompTargetNonColor; dwBkColor = m_dwCompTargetNonBkColor; } else { continue; } } SUICoord TargetCoord; TargetCoord.SetCoord( CompCoord.fX + ( nXLeft - nXFirst ) / m_pParent->GetScreenWidth(), CompCoord.fY, ( nXRight - nXLeft ) / m_pParent->GetScreenWidth(), CompCoord.fHeight ); m_pParent->DrawRect( TargetCoord, dwBkColor ); m_pParent->DrawDlgText( pcComp, pElement, pElement->FontColor.dwCurrentColor, TargetCoord, 1 ); if( s_nFirstTargetConv == -1 ) { s_nFirstTargetConv = ( int )( pAttr - s_abyCompStringAttr ); } } if( m_bCaretOn ) { if( s_nCompCaret == s_CompString.GetTextSize() ) { nX = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, s_nCompCaret ); //s_CompString.CPtoX( s_nCompCaret, FALSE, &nX ); CaretCoord = CompCoord; CaretCoord.fX += ( nX - nXFirst - 1 ) / m_pParent->GetScreenWidth(); CaretCoord.fWidth = 2.0f / m_pParent->GetScreenWidth(); } m_pParent->DrawRect( CaretCoord, m_Property.IMEEditBoxProperty.dwCompCaretColor ); } } void CEtUIIMEEditBox::RenderIndicator( float fElapsedTime ) { if( m_Property.IMEEditBoxProperty.fIndicatorSize <= 0.0f ) { return; } UpdateBlendRate(); SUIElement *pElement; SUICoord TempCoord;//, CalcCoord; WCHAR *pwszIndicator; pElement = GetElement(5); pElement->TextureColor.Blend( UI_STATE_NORMAL, fElapsedTime, m_fBlendRate ); if( m_bExistTemplateTexture ) m_pParent->DrawSprite( m_Template.m_hTemplateTexture, pElement->TemplateUVCoord, pElement->TextureColor.dwCurrentColor, m_IndicatorCoord ); else m_pParent->DrawSprite( pElement->UVCoord, pElement->TextureColor.dwCurrentColor, m_IndicatorCoord ); /* TempCoord = m_IndicatorCoord; TempCoord.fX += m_Property.IMEEditBoxProperty.fSpace; TempCoord.fY += m_Property.IMEEditBoxProperty.fSpace; TempCoord.fWidth -= m_Property.IMEEditBoxProperty.fSpace * 2; TempCoord.fHeight -= m_Property.IMEEditBoxProperty.fSpace * 2; */ pElement->FontColor.dwCurrentColor = m_Property.IMEEditBoxProperty.dwIndiTextColor; if( ( s_ImeState == IMEUI_STATE_ON ) && ( s_bEnableImeSystem ) ) { pwszIndicator = s_pwszCurrIndicator; } else { pwszIndicator = s_aszIndicator[ 0 ]; } /* if( ( s_ImeState == IMEUI_STATE_ON ) && ( s_bEnableImeSystem ) ) { pElement->FontColor.dwCurrentColor = m_dwIndicatorImeColor; } else { pElement->FontColor.dwCurrentColor = m_dwIndicatorEngColor; } if( s_bEnableImeSystem ) { pwszIndicator = s_pwszCurrIndicator; } else { pwszIndicator = s_aszIndicator[ 0 ]; } */ TempCoord = m_IndicatorCoord; m_pParent->CalcTextRect( pwszIndicator, pElement, TempCoord ); float fMidHeight = ( m_IndicatorCoord.fHeight - TempCoord.fHeight ) / 2.0f; TempCoord.fX -= m_Property.IMEEditBoxProperty.fSpace; TempCoord.fY = m_IndicatorCoord.fY + fMidHeight; m_pParent->DrawDlgText( pwszIndicator, pElement, pElement->FontColor.dwCurrentColor, TempCoord ); } void CEtUIIMEEditBox::TruncateCompString( bool bUseBackSpace, int iNewStrLen ) { if( !s_bInsertOnType ) { return; } int i, cc; cc = ( int )wcslen( s_CompString.GetBuffer() ); assert( iNewStrLen == 0 || iNewStrLen >= cc ); for ( i = 0; i < cc - s_nCompCaret; i++ ) { SendMessage( m_pParent->GetHWnd(), WM_KEYDOWN, VK_RIGHT, 0 ); } SendMessage( m_pParent->GetHWnd(), WM_KEYUP, VK_RIGHT, 0 ); if( ( bUseBackSpace ) || ( m_bInsertMode ) ) { iNewStrLen = 0; } if( iNewStrLen < cc ) { for( i = 0; i < cc - iNewStrLen; i++ ) { SendMessage( m_pParent->GetHWnd(), WM_KEYDOWN, VK_BACK, 0 ); SendMessageW( m_pParent->GetHWnd(), WM_CHAR, VK_BACK, 0 ); } SendMessage( m_pParent->GetHWnd(), WM_KEYUP, VK_BACK, 0 ); } else { iNewStrLen = cc; } for ( i = 0; i < iNewStrLen; i++ ) { SendMessage( m_pParent->GetHWnd(), WM_KEYDOWN, VK_LEFT, 0 ); } SendMessage( m_pParent->GetHWnd(), WM_KEYUP, VK_LEFT, 0 ); } void CEtUIIMEEditBox::FinalizeString( bool bSend ) { HIMC hImc; static bool bProcessing = false; hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc == NULL ) { return; } if( bProcessing ) { _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); return; } bProcessing = true; if( ( !s_bInsertOnType ) && ( bSend ) ) { LONG lLength; lLength = lstrlenW( s_CompString.GetBuffer() ); if( ( GetLanguage() == LANG_CHT ) && ( s_CompString[ lLength - 1 ] == 0x3000 ) ) { s_CompString[ lLength - 1 ] = 0; } SendCompString(); } TruncateCompString(); s_bHideCaret = false; s_bShowReadingWindow = false; ResetCompositionString(); _ImmNotifyIME( hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ); _ImmNotifyIME( hImc, NI_CLOSECANDIDATE, 0, 0 ); _ImmReleaseContext( m_pParent->GetHWnd(), hImc ); bProcessing = false; } void CEtUIIMEEditBox::SendCompString() { for( int i = 0; i < lstrlenW( s_CompString.GetBuffer() ); i++ ) { MsgProc( WM_CHAR, ( WPARAM )s_CompString[ i ], 0 ); } } void CEtUIIMEEditBox::PlaceCaret( int nCP ) { int nX1, nX2, nCompSize(0); m_bFirstVisibleOver = false; m_nTempCompSize = 0; CEtFontMng& FontMng = CEtFontMng::GetInstance(); SUIElement* pElement = GetElement( 0 ); nX1 = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nFirstVisible ); //m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1 ); nX2 = FontMng.GetCaretPos( m_Buffer.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, m_nCaret ); //m_Buffer.CPtoX( m_nCaret, FALSE, &nX2 ); nCompSize = FontMng.GetCaretPos( s_CompString.GetBuffer(), pElement->nFontIndex, pElement->nFontHeight, nCP ); //s_CompString.CPtoX( nCP, FALSE, &nCompSize ); int nTextWidth = (int)( m_TextCoord.fWidth * m_pParent->GetScreenWidth() ); if( (nX2-nX1+nCompSize) > nTextWidth ) { int nTemp = m_Buffer.GetMaxEditBoxLength() - m_Buffer.GetTextSize(); int nCPNew1st(0); if( nTemp < 3 ) ++nCPNew1st; else nCPNew1st += 3; // Note: 조합중인 문자열이 너무 길어서 완성된 문자열을 밀어내서 하나도 보이지 않게 되는 경우를 막는다. // 안그러면 m_nFirstVisible 값이 문자열 길이를 넘어가게 되어버림. if( m_nFirstVisible + nCPNew1st < (int)wcslen( m_Buffer.GetBuffer() ) ) m_nFirstVisible += nCPNew1st; else m_bFirstVisibleOver = true; // 아무래도 CustomUI에는 없는 m_bFirstVisibleOver 변수를 추가해 처리한거 자체가 별로인거 같아서, // 이 상태가 되었을때 ImmSetCompositionStringW함수를 호출해 조합중인 글자를 일정길이로 제한두려 했으나, // 아무리 설정해도 함수가 FALSE를 리턴한다. // 구글에서 찾아봐도 안된다고 하는 사람은 많은데, 어떻게 고쳐야된다고 적어둔건 하나도 못찾았다. // #30251 귓속말[아이디]가 길 경우 실제로 문자를 입력할 수 있는 공간은 얼마 되지 않는다. // 글자공간이 짧은데다가 자꾸 리셋된다고 별로라 해서, 이쪽 루틴을 다시 검토해봤는데, // CustomUI에는 없는 m_bFirstVisibleOver게 있는 이유는.. Custom UI와 달리, 조합중인 글자도 영역을 차지해서 // 우측에 있는 글자를 밀어내는 기능이 드네엔 들어있기 때문이다.(그리고 이게 더 자연스럽다.) // 이건 거의 모든 편집기가 다 이렇게 되어있는데, 첨에는 모든 조합중인 문자가 다 이런줄 알았다. // 근데 해보니까, 한글만 이렇고, // 일본어, 중국어처럼 조합스트링이 2자 이상인 것들은 조합중인 윈도우가 따로 뜨고, // 문자열 사이에서 조합하더라도 우측 글자를 밀지 않다가 확정이 되어야만 밀어낸다. // 근데, 현재 드네는 그 구분이 되어있지 않다. // 그래서 아래와 같은 s_CompString 해결책을 사용한다. if( m_bFirstVisibleOver && (int)wcslen( s_CompString.GetBuffer() ) < 10 ) { m_bFirstVisibleOver = false; m_nTempCompSize = nCompSize; } } } void CEtUIIMEEditBox::ClearText() { CEtUIEditBox::ClearText(); ResetCompositionString(); } void CEtUIIMEEditBox::CheckIMEToggleState() { CheckToggleState(); } void CEtUIIMEEditBox::CancelIMEComposition() { HIMC hImc; hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc == NULL ) return; _ImmNotifyIME( hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ); } void CEtUIIMEEditBox::GetIMECompositionString(std::wstring& str) { HIMC hImc; hImc = _ImmGetContext( m_pParent->GetHWnd() ); if( hImc == NULL ) return; WCHAR wszCompStr[MAX_COMPSTRING_SIZE]={0}; LONG lRet = _ImmGetCompositionStringW( hImc, GCS_COMPSTR, wszCompStr, sizeof( wszCompStr ) ); if (lRet > 0) { lRet /= sizeof( WCHAR ); wszCompStr[lRet] = 0; str = wszCompStr; } } int CEtUIIMEEditBox::GetMaxChar() const { return m_Property.IMEEditBoxProperty.dwMaxChars; } void CEtUIIMEEditBox::SetMaxChar( DWORD dwChar ) { m_Property.IMEEditBoxProperty.dwMaxChars = dwChar; SetMaxEditLength( dwChar ); }