Example #1
0
void CIME::CheckInputLocale()
{
	static HKL hklPrev = 0;
	s_hklCurrent = GetKeyboardLayout(0);
	if (hklPrev == s_hklCurrent)
		return;

	hklPrev = s_hklCurrent;
	switch (GetPrimaryLanguage())
	{
		// Simplified Chinese
	case LANG_CHINESE:
		s_bVerticalCand = true;
		switch (GetSubLanguage())
		{
		case SUBLANG_CHINESE_SIMPLIFIED:
			s_wszCurrIndicator = s_aszIndicator[INDICATOR_CHS];
			s_bVerticalCand = GetImeId() == 0;
			break;
		case SUBLANG_CHINESE_TRADITIONAL:
			s_wszCurrIndicator = s_aszIndicator[INDICATOR_CHT];
			break;
		default:    // unsupported sub-language
			s_wszCurrIndicator = s_aszIndicator[INDICATOR_NON_IME];
			break;
		}
		break;
		// Korean
	case LANG_KOREAN:
		s_wszCurrIndicator = s_aszIndicator[INDICATOR_KOREAN];
		s_bVerticalCand = false;
		break;
		// Japanese
	case LANG_JAPANESE:
		s_wszCurrIndicator = s_aszIndicator[INDICATOR_JAPANESE];
		s_bVerticalCand = true;
		break;
	default:
		// A non-IME language.  Obtain the language abbreviation
		// and store it for rendering the indicator later.
		s_wszCurrIndicator = s_aszIndicator[INDICATOR_NON_IME];
	}

	// If non-IME, use the language abbreviation.
	if(s_wszCurrIndicator == s_aszIndicator[INDICATOR_NON_IME])
	{
		WCHAR wszLang[5];
		GetLocaleInfoW(MAKELCID(LOWORD(s_hklCurrent), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, wszLang, 5);
		s_wszCurrIndicator[0] = wszLang[0];
		s_wszCurrIndicator[1] = towlower(wszLang[1]);
	}
}
Example #2
0
//--------------------------------------------------------------------------------------
_Use_decl_annotations_
DXUTAPI void CDXUTIMEEditBox::RenderCandidateReadingWindow(bool bReading)
{
	RECT rc;
	UINT nNumEntries = bReading ? 4 : MAX_CANDLIST;
	int nX, nXFirst, nXComp;
	m_Buffer.CPtoX(m_nCaret, FALSE, &nX);
	m_Buffer.CPtoX(m_nFirstVisible, FALSE, &nXFirst);

	DWORD TextColor, TextBkColor, SelTextColor, SelBkColor;
	if (bReading)
	{
		TextColor = m_ReadingColor;
		TextBkColor = m_ReadingWinColor;
		SelTextColor = m_ReadingSelColor;
		SelBkColor = m_ReadingSelBkColor;
	}
	else
	{
		TextColor = m_CandidateColor;
		TextBkColor = m_CandidateWinColor;
		SelTextColor = m_CandidateSelColor;
		SelBkColor = m_CandidateSelBkColor;
	}

	// For Japanese IME, align the window with the first target converted character.
	// For all other IMEs, align with the caret.  This is because the caret
	// does not move for Japanese IME.
	if (GetLanguage() == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) && !GetImeId())
		nXComp = 0;
	else if (GetPrimaryLanguage() == LANG_JAPANESE)
		s_CompString.CPtoX(s_nFirstTargetConv, FALSE, &nXComp);
	else
		s_CompString.CPtoX(ImeUi_GetImeCursorChars(), FALSE, &nXComp);

	// Compute the size of the candidate window
	int nWidthRequired = 0;
	int nHeightRequired = 0;
	int nSingleLineHeight = 0;

	if ((ImeUi_IsVerticalCand() && !bReading) ||
		(!ImeUi_IsHorizontalReading() && bReading))
	{
		// Vertical window
		for (UINT i = 0; i < nNumEntries; ++i)
		{
			if (*(ImeUi_GetCandidate(i)) == L'\0')
				break;
			SetRect(&rc, 0, 0, 0, 0);
			m_pDialog->CalcTextRect(ImeUi_GetCandidate(i), m_Elements[1], &rc);
			nWidthRequired = std::max<int>(nWidthRequired, rc.right - rc.left);
			nSingleLineHeight = std::max<int>(nSingleLineHeight, rc.bottom - rc.top);
		}
		nHeightRequired = nSingleLineHeight * nNumEntries;
	}
	else
	{
		// Horizontal window
		SetRect(&rc, 0, 0, 0, 0);
		if (bReading)
			m_pDialog->CalcTextRect(s_wszReadingString, m_Elements[1], &rc);
		else
		{
			WCHAR wszCand[256] = L"";

			s_CandList.nFirstSelected = 0;
			s_CandList.nHoriSelectedLen = 0;
			for (UINT i = 0; i < MAX_CANDLIST; ++i)
			{
				if (*ImeUi_GetCandidate(i) == L'\0')
					break;

				WCHAR wszEntry[32];
				swprintf_s(wszEntry, 32, L"%s ", ImeUi_GetCandidate(i));
				// If this is the selected entry, mark its char position.
				if (ImeUi_GetCandidateSelection() == i)
				{
					s_CandList.nFirstSelected = (int)wcslen(wszCand);
					s_CandList.nHoriSelectedLen = (int)wcslen(wszEntry) - 1;  // Minus space
				}
				wcscat_s(wszCand, 256, wszEntry);
			}
			wszCand[wcslen(wszCand) - 1] = L'\0';  // Remove the last space
			s_CandList.HoriCand.SetText(wszCand);

			m_pDialog->CalcTextRect(s_CandList.HoriCand.GetBuffer(), m_Elements[1], &rc);
		}
		nWidthRequired = rc.right - rc.left;
		nSingleLineHeight = nHeightRequired = rc.bottom - rc.top;
	}

	// Now that we have the dimension, calculate the location for the candidate window.
	// We attempt to fit the window in this order:
	// bottom, top, right, left.

	bool bHasPosition = false;

	// Bottom
	SetRect(&rc, s_ptCompString.x + nXComp, s_ptCompString.y + m_rcText.bottom - m_rcText.top,
		s_ptCompString.x + nXComp + nWidthRequired, s_ptCompString.y + m_rcText.bottom - m_rcText.top +
		nHeightRequired);
	// if the right edge is cut off, move it left.
	if (rc.right > m_pDialog->GetWidth())
	{
		rc.left -= rc.right - m_pDialog->GetWidth();
		rc.right = m_pDialog->GetWidth();
	}
	if (rc.bottom <= m_pDialog->GetHeight())
		bHasPosition = true;

	// Top
	if (!bHasPosition)
	{
		SetRect(&rc, s_ptCompString.x + nXComp, s_ptCompString.y - nHeightRequired,
			s_ptCompString.x + nXComp + nWidthRequired, s_ptCompString.y);
		// if the right edge is cut off, move it left.
		if (rc.right > m_pDialog->GetWidth())
		{
			rc.left -= rc.right - m_pDialog->GetWidth();
			rc.right = m_pDialog->GetWidth();
		}
		if (rc.top >= 0)
			bHasPosition = true;
	}

	// Right
	if (!bHasPosition)
	{
		int nXCompTrail;
		s_CompString.CPtoX(ImeUi_GetImeCursorChars(), TRUE, &nXCompTrail);
		SetRect(&rc, s_ptCompString.x + nXCompTrail, 0,
			s_ptCompString.x + nXCompTrail + nWidthRequired, nHeightRequired);
		if (rc.right <= m_pDialog->GetWidth())
			bHasPosition = true;
	}

	// Left
	if (!bHasPosition)
	{
		SetRect(&rc, s_ptCompString.x + nXComp - nWidthRequired, 0,
			s_ptCompString.x + nXComp, nHeightRequired);
		if (rc.right >= 0)
			bHasPosition = true;
	}

	if (!bHasPosition)
	{
		// The dialog is too small for the candidate window.
		// Fall back to render at 0, 0.  Some part of the window
		// will be cut off.
		rc.left = 0;
		rc.right = nWidthRequired;
	}

	// If we are rendering the candidate window, save the position
	// so that mouse clicks are checked properly.
	if (!bReading)
		s_CandList.rcCandidate = rc;

	// Render the elements
	m_pDialog->DrawRect(&rc, TextBkColor);
	if ((ImeUi_IsVerticalCand() && !bReading) ||
		(!ImeUi_IsHorizontalReading() && bReading))
	{
		// Vertical candidate window
		for (UINT i = 0; i < nNumEntries; ++i)
		{
			// Here we are rendering one line at a time
			rc.bottom = rc.top + nSingleLineHeight;
			// Use a different color for the selected string
			if (ImeUi_GetCandidateSelection() == i)
			{
				m_pDialog->DrawRect(&rc, SelBkColor);
				m_Elements[1]->FontColor.SetCurrent(SelTextColor);
			}
			else
				m_Elements[1]->FontColor.SetCurrent(TextColor);

			m_pDialog->DrawText(ImeUi_GetCandidate(i), m_Elements[1], &rc);

			rc.top += nSingleLineHeight;
		}
	}
	else
	{
		// Horizontal candidate window
		m_Elements[1]->FontColor.SetCurrent(TextColor);
		if (bReading)
			m_pDialog->DrawText(s_wszReadingString, m_Elements[1], &rc);
		else
			m_pDialog->DrawText(s_CandList.HoriCand.GetBuffer(), m_Elements[1], &rc);

		// Render the selected entry differently
		if (!bReading)
		{
			int nXLeft, nXRight;
			s_CandList.HoriCand.CPtoX(s_CandList.nFirstSelected, FALSE, &nXLeft);
			s_CandList.HoriCand.CPtoX(s_CandList.nFirstSelected + s_CandList.nHoriSelectedLen, FALSE, &nXRight);

			rc.right = rc.left + nXRight;
			rc.left += nXLeft;
			m_pDialog->DrawRect(&rc, SelBkColor);
			m_Elements[1]->FontColor.SetCurrent(SelTextColor);
			m_pDialog->DrawText(s_CandList.HoriCand.GetBuffer() + s_CandList.nFirstSelected,
				m_Elements[1], &rc, false);
		}
	}
}
Example #3
0
// Obtain the reading string upon WM_IME_NOTIFY/INM_PRIVATE notification.
void CIME::GetPrivateReadingString()
{
	DWORD dwId = GetImeId();
	if(!dwId)
	{
		s_bShowReadingWindow = false;
		return;
	}

	HIMC hImc;
	hImc = ImmGetContext(UIGetHWND());
	if(!hImc)
	{
		s_bShowReadingWindow = false;
		return;
	}

	DWORD dwReadingStrLen = 0;
	DWORD dwErr = 0;
	WCHAR *pwszReadingStringBuffer = NULL;  // Buffer for when the IME supports GetReadingString()
	WCHAR *wstr = 0;
	bool bUnicodeIme = false;  // Whether the IME context component is Unicode.
	INPUTCONTEXT *lpIC = NULL;

	if(_GetReadingString)
	{
		UINT uMaxUiLen;
		BOOL bVertical;
		// Obtain the reading string size
		dwReadingStrLen = _GetReadingString(hImc, 0, NULL, (PINT)&dwErr, &bVertical, &uMaxUiLen);
		if(dwReadingStrLen)
		{
			wstr = pwszReadingStringBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * dwReadingStrLen);
			if(!pwszReadingStringBuffer)
			{
				// Out of memory. Exit.
				_ImmReleaseContext(UIGetHWND(), hImc);
				return;
			}

			// Obtain the reading string
			dwReadingStrLen = _GetReadingString(hImc, dwReadingStrLen, wstr, (PINT)&dwErr, &bVertical, &uMaxUiLen);
		}

		s_bHorizontalReading = !bVertical;
		bUnicodeIme = true;
	}
	else
	{
		// IMEs that doesn't implement Reading String API

		lpIC = _ImmLockIMC(hImc);

		LPBYTE p = 0;
		switch(dwId)
		{
		case IMEID_CHT_VER42: // New(Phonetic/ChanJie)IME98  : 4.2.x.x // Win98
		case IMEID_CHT_VER43: // New(Phonetic/ChanJie)IME98a : 4.3.x.x // WinMe, Win2k
		case IMEID_CHT_VER44: // New ChanJie IME98b          : 4.4.x.x // WinXP
			p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 24);
			if(!p) break;
			dwReadingStrLen = *(DWORD *)(p + 7 * 4 + 32 * 4);
			dwErr = *(DWORD *)(p + 8 * 4 + 32 * 4);
			wstr = (WCHAR *)(p + 56);
			bUnicodeIme = true;
			break;

		case IMEID_CHT_VER50: // 5.0.x.x // WinME
			p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 3 * 4);
			if(!p) break;
			p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4 + 4*2);
			if(!p) break;
			dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16);
			dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 + 1*4);
			wstr = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
			bUnicodeIme = false;
			break;

		case IMEID_CHT_VER51: // 5.1.x.x // IME2002(w/OfficeXP)
		case IMEID_CHT_VER52: // 5.2.x.x // (w/whistler)
		case IMEID_CHS_VER53: // 5.3.x.x // SCIME2k or MSPY3 (w/OfficeXP and Whistler)
			p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 4);
			if(!p) break;
			p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
			if(!p) break;
			dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2);
			dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2 + 1*4);
			wstr  = (WCHAR *) (p + 1*4 + (16*2+2*4) + 5*4);
			bUnicodeIme = true;
			break;

			// the code tested only with Win 98 SE (MSPY 1.5/ ver 4.1.0.21)
		case IMEID_CHS_VER41:
			{
				int nOffset;
				nOffset = (GetImeId(1) >= 0x00000002) ? 8 : 7;

				p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + nOffset * 4);
				if(!p) break;
				dwReadingStrLen = *(DWORD *)(p + 7*4 + 16*2*4);
				dwErr = *(DWORD *)(p + 8*4 + 16*2*4);
				dwErr = __min(dwErr, dwReadingStrLen);
				wstr = (WCHAR *)(p + 6*4 + 16*2*1);
				bUnicodeIme = true;
				break;
			}

		case IMEID_CHS_VER42: // 4.2.x.x // SCIME98 or MSPY2 (w/Office2k, Win2k, WinME, etc)
			{
				OSVERSIONINFOW osi;
				osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
				GetVersionExW(&osi);

				int nTcharSize = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT) ? sizeof(WCHAR) : sizeof(char);
				p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC(lpIC->hPrivate) + 1*4 + 1*4 + 6*4);
				if(!p) break;
				dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize);
				dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize + 1*4);
				wstr  = (WCHAR *) (p + 1*4 + (16*2+2*4) + 5*4);
				bUnicodeIme = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT) ? true : false;
			}
		}   // switch
	}

	// Copy the reading string to the candidate list first
	s_CandList.awszCandidate[0][0] = 0;
	s_CandList.awszCandidate[1][0] = 0;
	s_CandList.awszCandidate[2][0] = 0;
	s_CandList.awszCandidate[3][0] = 0;
	s_CandList.dwCount = dwReadingStrLen;
	s_CandList.dwSelection = (DWORD)-1; // do not select any char
	if(bUnicodeIme)
	{
		UINT i;
		for(i = 0; i < dwReadingStrLen; ++i) // dwlen > 0, if known IME
		{
			if(dwErr <= i && s_CandList.dwSelection == (DWORD)-1)
			{
				// select error char
				s_CandList.dwSelection = i;
			}

			s_CandList.awszCandidate[i][0] = wstr[i];
			s_CandList.awszCandidate[i][1] = 0;
		}
		s_CandList.awszCandidate[i][0] = 0;
	}
	else
	{
		char *p = (char *)wstr;
		DWORD i, j;
		for(i = 0, j = 0; i < dwReadingStrLen; ++i, ++j) // dwlen > 0, if known IME
		{
			if(dwErr <= i && s_CandList.dwSelection == (DWORD)-1)
			{
				s_CandList.dwSelection = j;
			}
			// Obtain the current code page
			WCHAR wszCodePage[8];
			UINT uCodePage = CP_ACP;  // Default code page
			if(GetLocaleInfoW(MAKELCID(GetLanguage(), SORT_DEFAULT),
				LOCALE_IDEFAULTANSICODEPAGE,
				wszCodePage,
				sizeof(wszCodePage)/sizeof(wszCodePage[0])))
			{
				uCodePage = wcstoul(wszCodePage, NULL, 0);
			}
			MultiByteToWideChar(uCodePage, 0, p + i, IsDBCSLeadByteEx(uCodePage, p[i]) ? 2 : 1,
				s_CandList.awszCandidate[j], 1);
			if(IsDBCSLeadByteEx(uCodePage, p[i]))
				++i;
		}
		s_CandList.awszCandidate[j][0] = 0;
		s_CandList.dwCount = j;
	}
	if(!_GetReadingString)
	{
		_ImmUnlockIMCC(lpIC->hPrivate);
		_ImmUnlockIMC(hImc);
		GetReadingWindowOrientation(dwId);
	}
	_ImmReleaseContext(UIGetHWND(), hImc);

	if(pwszReadingStringBuffer)
		HeapFree(GetProcessHeap(), 0, pwszReadingStringBuffer);

	// Copy the string to the reading string buffer
	if(s_CandList.dwCount > 0)
		s_bShowReadingWindow = true;
	else
		s_bShowReadingWindow = false;
	if(s_bHorizontalReading)
	{
		s_CandList.nReadingError = -1;
		s_wstrReadingString.clear();
		for(UINT i = 0; i < s_CandList.dwCount; ++i)
		{
			if(s_CandList.dwSelection == i)
				s_CandList.nReadingError = s_wstrReadingString.length();
			s_wstrReadingString+=s_CandList.awszCandidate[i];
		}
	}

	s_CandList.dwPageSize = MAX_CANDLIST;
}