Commit 8b5cca6a authored by mercury233's avatar mercury233

update & fix IME on Windows

parent 456556db
...@@ -612,6 +612,7 @@ namespace ...@@ -612,6 +612,7 @@ namespace
{ {
HWND hWnd; HWND hWnd;
irr::CIrrDeviceWin32* irrDev; irr::CIrrDeviceWin32* irrDev;
bool imeEnabled;
}; };
irr::core::list<SEnvMapper> EnvMap; irr::core::list<SEnvMapper> EnvMap;
...@@ -754,22 +755,32 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ...@@ -754,22 +755,32 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
return 0; return 0;
} }
dev = getDeviceFromHWnd(hWnd); SEnvMapper* env = getEnvMapperFromHWnd(hWnd);
if (dev) if (env && env->irrDev)
{ {
dev = env->irrDev;
irr::gui::IGUIElement* ele = dev->getGUIEnvironment()->getFocus(); irr::gui::IGUIElement* ele = dev->getGUIEnvironment()->getFocus();
if (!ele || (ele->getType() != irr::gui::EGUIET_EDIT_BOX) || !ele->isEnabled()) bool enable = (ele && (ele->getType() == irr::gui::EGUIET_EDIT_BOX) && ele->isEnabled());
if (enable != env->imeEnabled)
{ {
HIMC hIMC = ImmGetContext(hWnd); if (!enable)
if (hIMC)
{ {
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); HIMC hIMC = ImmGetContext(hWnd);
ImmReleaseContext(hWnd, hIMC); if (hIMC)
{
// When focus leaves the edit box, cancel the current composition to avoid
// committing unintended partial text.
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ImmReleaseContext(hWnd, hIMC);
}
ImmAssociateContextEx(hWnd, NULL, 0);
} }
ImmAssociateContextEx(hWnd, NULL, 0); else
ImmAssociateContextEx(hWnd, NULL, IACE_DEFAULT);
env->imeEnabled = enable;
} }
else
ImmAssociateContextEx(hWnd, NULL, IACE_DEFAULT);
} }
switch (message) switch (message)
...@@ -832,12 +843,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ...@@ -832,12 +843,17 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
int conversionResult = ToAsciiEx(wParam,scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL); int conversionResult = ToAsciiEx(wParam,scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL);
if (conversionResult == 1) if (conversionResult == 1)
{ {
WORD unicodeChar; // ToAsciiEx writes translated ANSI chars into WORDs. Convert only the
// produced byte(s) instead of interpreting the whole WORD array as a byte buffer.
char bytes[2];
bytes[0] = static_cast<char>(keyChars[0] & 0xFF);
bytes[1] = static_cast<char>(keyChars[1] & 0xFF);
WORD unicodeChar = 0;
MultiByteToWideChar( MultiByteToWideChar(
KEYBOARD_INPUT_CODEPAGE, KEYBOARD_INPUT_CODEPAGE,
MB_PRECOMPOSED, // default MB_PRECOMPOSED, // default
(LPCSTR)keyChars, bytes,
sizeof(keyChars), 1,
(WCHAR*)&unicodeChar, (WCHAR*)&unicodeChar,
1 ); 1 );
event.KeyInput.Char = unicodeChar; event.KeyInput.Char = unicodeChar;
...@@ -932,17 +948,70 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ...@@ -932,17 +948,70 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) ); KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
return 0; return 0;
case WM_IME_COMPOSITION:
{
// Prefer reading the IME result string directly.
// If we let DefWindowProc handle this, it may generate WM_IME_CHAR messages,
// which can lead to duplicate character events when we also handle IME.
if (lParam & GCS_RESULTSTR)
{
dev = getDeviceFromHWnd(hWnd);
if (dev)
{
HIMC hIMC = ImmGetContext(hWnd);
if (hIMC)
{
LONG bytes = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
if (bytes > 0)
{
const int wcharCount = bytes / (int)sizeof(WCHAR);
WCHAR* buffer = new WCHAR[wcharCount + 1];
ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buffer, bytes);
buffer[wcharCount] = 0;
event.EventType = irr::EET_KEY_INPUT_EVENT;
event.KeyInput.PressedDown = true;
event.KeyInput.Key = irr::KEY_ACCEPT;
event.KeyInput.Shift = 0;
event.KeyInput.Control = 0;
for (int i = 0; i < wcharCount; ++i)
{
event.KeyInput.Char = buffer[i];
dev->postEventFromUser(event);
}
delete[] buffer;
}
ImmReleaseContext(hWnd, hIMC);
// Remove GCS_RESULTSTR to prevent DefWindowProc from generating WM_IME_CHAR
lParam &= ~GCS_RESULTSTR;
}
}
}
if (lParam == 0)
return 0;
break;
}
case WM_IME_STARTCOMPOSITION: case WM_IME_STARTCOMPOSITION:
{ {
dev = getDeviceFromHWnd(hWnd); dev = getDeviceFromHWnd(hWnd);
if (!dev)
break;
irr::gui::IGUIElement* ele = dev->getGUIEnvironment()->getFocus(); irr::gui::IGUIElement* ele = dev->getGUIEnvironment()->getFocus();
if (!ele) if (!ele)
break; break;
irr::core::position2di pos = ele->getAbsolutePosition().UpperLeftCorner; irr::core::position2di pos = ele->getAbsolutePosition().UpperLeftCorner;
COMPOSITIONFORM CompForm = { CFS_POINT, { pos.X, pos.Y + ele->getAbsolutePosition().getHeight() } }; COMPOSITIONFORM CompForm = { CFS_POINT, { pos.X, pos.Y + ele->getAbsolutePosition().getHeight() } };
HIMC hIMC = ImmGetContext(hWnd); HIMC hIMC = ImmGetContext(hWnd);
ImmSetCompositionWindow(hIMC, &CompForm); if (hIMC)
ImmReleaseContext(hWnd, hIMC); {
ImmSetCompositionWindow(hIMC, &CompForm);
ImmReleaseContext(hWnd, hIMC);
}
} }
break; break;
...@@ -962,11 +1031,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ...@@ -962,11 +1031,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
ch[1] = 0; ch[1] = 0;
} }
WORD unicodeChar; WORD unicodeChar;
const int bytesLen = (wParam >> 8) ? 2 : 1;
MultiByteToWideChar( MultiByteToWideChar(
KEYBOARD_INPUT_CODEPAGE, KEYBOARD_INPUT_CODEPAGE,
MB_PRECOMPOSED, // default MB_PRECOMPOSED, // default
(LPCSTR)ch, (LPCSTR)ch,
sizeof(wParam), bytesLen,
(WCHAR*)&unicodeChar, (WCHAR*)&unicodeChar,
1); 1);
event.KeyInput.Char = unicodeChar; event.KeyInput.Char = unicodeChar;
...@@ -1118,6 +1188,7 @@ CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params) ...@@ -1118,6 +1188,7 @@ CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
SEnvMapper em; SEnvMapper em;
em.irrDev = this; em.irrDev = this;
em.hWnd = HWnd; em.hWnd = HWnd;
em.imeEnabled = true;
EnvMap.push_back(em); EnvMap.push_back(em);
// set this as active window // set this as active window
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment