diff src/video/win32/SDL_win32keyboard.c @ 4752:dc7bdcf06367

Initial IMM implementation. IME input should now work fairly well.
author dewyatt
date Mon, 12 Jul 2010 11:33:27 -0400
parents f3908cd80b10
children 11b0a6a3eb4d
line wrap: on
line diff
--- a/src/video/win32/SDL_win32keyboard.c	Sat Jul 10 13:15:47 2010 -0400
+++ b/src/video/win32/SDL_win32keyboard.c	Mon Jul 12 11:33:27 2010 -0400
@@ -26,6 +26,9 @@
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/scancodes_win32.h"
 
+#include <msctf.h>
+#include <imm.h>
+
 #ifndef MAPVK_VK_TO_VSC
 #define MAPVK_VK_TO_VSC     0
 #endif
@@ -46,6 +49,11 @@
     82, 79, 80, 81, 75, 76, 77, 71, 72, 73
 };
 
+void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
+void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
+void IME_Init(SDL_VideoData *videodata, HWND hwnd);
+void IME_Quit(SDL_VideoData *videodata);
+
 void
 WIN_InitKeyboard(_THIS)
 {
@@ -81,6 +89,15 @@
 
     data->key_layout = win32_scancode_table;
 
+    data->ime_com_initialized = SDL_FALSE;
+    data->ime_thread_mgr = 0;
+    data->ime_initialized = SDL_FALSE;
+    data->ime_enabled = SDL_FALSE;
+    data->ime_available = SDL_FALSE;
+    data->ime_hwnd_main = 0;
+    data->ime_hwnd_current = 0;
+    data->ime_himc = 0;
+
     WIN_UpdateKeymap();
 
     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
@@ -120,19 +137,25 @@
 void
 WIN_QuitKeyboard(_THIS)
 {
+    IME_Quit((SDL_VideoData *)_this->driverdata);
 }
 
 void
 WIN_StartTextInput(_THIS, SDL_Window *window)
 {
-	HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
-
+    HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+    SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+    IME_Init(videodata, hwnd);
+    IME_Enable(videodata, hwnd);
 }
 
 void
 WIN_StopTextInput(_THIS, SDL_Window *window)
 {
-
+    HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+    SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+    IME_Init(videodata, hwnd);
+    IME_Disable(videodata, hwnd);
 }
 
 void
@@ -141,4 +164,161 @@
 
 }
 
+void
+IME_Disable(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
+        return;
+
+    if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_current, NULL);
+
+    videodata->ime_enabled = SDL_FALSE;
+}
+
+void
+IME_Enable(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
+        return;
+
+    if (!videodata->ime_available) {
+        IME_Disable(videodata, hwnd);
+        return;
+    }
+    if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
+
+    videodata->ime_enabled = SDL_TRUE;
+}
+
+void
+IME_Init(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (videodata->ime_initialized)
+        return;
+
+    videodata->ime_hwnd_main = hwnd;
+    if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
+        videodata->ime_com_initialized = SDL_TRUE;
+        CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_thread_mgr);
+    }
+    videodata->ime_initialized = SDL_TRUE;
+    videodata->ime_hwnd_current = videodata->ime_hwnd_main;
+    if (videodata->ime_thread_mgr) {
+        struct ITfDocumentMgr *document_mgr = 0;
+        if (SUCCEEDED(videodata->ime_thread_mgr->lpVtbl->AssociateFocus(videodata->ime_thread_mgr, hwnd, NULL, &document_mgr))) {
+            if (document_mgr)
+                document_mgr->lpVtbl->Release(document_mgr);
+        }
+    }
+    videodata->ime_himc = ImmGetContext(hwnd);
+    ImmReleaseContext(hwnd, videodata->ime_himc);
+    if (!videodata->ime_himc) {
+        videodata->ime_available = SDL_FALSE;
+        IME_Disable(videodata, hwnd);
+        return;
+    }
+    videodata->ime_available = SDL_TRUE;
+    IME_Disable(videodata, hwnd);
+}
+
+void
+IME_Quit(SDL_VideoData *videodata)
+{
+    if (!videodata->ime_initialized)
+        return;
+
+    if (videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
+
+    videodata->ime_hwnd_main = 0;
+    videodata->ime_himc = 0;
+    if (videodata->ime_thread_mgr)
+    {
+        videodata->ime_thread_mgr->lpVtbl->Release(videodata->ime_thread_mgr);
+        videodata->ime_thread_mgr = 0;
+    }
+    if (videodata->ime_com_initialized)
+    {
+        CoUninitialize();
+        videodata->ime_com_initialized = SDL_FALSE;
+    }
+    videodata->ime_initialized = SDL_FALSE;
+}
+
+SDL_bool
+IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
+{
+    SDL_bool trap = SDL_FALSE;
+    HIMC himc = 0;
+    WCHAR Buffer[SDL_TEXTINPUTEVENT_TEXT_SIZE / 2];
+    if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
+        return SDL_FALSE;
+
+    switch (msg)
+    {
+    case WM_INPUTLANGCHANGE:
+        break;
+    case WM_IME_SETCONTEXT:
+        *lParam = 0;
+        break;
+    case WM_IME_STARTCOMPOSITION:
+        trap = SDL_TRUE;
+        break;
+    case WM_IME_COMPOSITION:
+        trap = SDL_TRUE;
+        himc = ImmGetContext(hwnd);
+        if (*lParam & GCS_RESULTSTR)
+        {
+            LONG Length = 0;
+            char *s = 0;
+            Length = ImmGetCompositionStringW(himc, GCS_RESULTSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
+            Buffer[Length / sizeof(Buffer[0])] = 0;
+            s = WIN_StringToUTF8(Buffer);
+            SDL_SendKeyboardText(s);
+            SDL_free(s);
+        }
+        if (*lParam & GCS_COMPSTR)
+        {
+            LONG Length = 0;
+            DWORD Cursor = 0;
+            char *s = 0;
+            Length = ImmGetCompositionStringW(himc, GCS_COMPSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
+            Buffer[Length / sizeof(Buffer[0])] = 0;
+            s = WIN_StringToUTF8(Buffer);
+            Cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
+            SDL_SendEditingText(s, Cursor, 0);
+            SDL_free(s);
+        }
+        ImmReleaseContext(hwnd, himc);
+        break;
+    case WM_IME_ENDCOMPOSITION:
+        SDL_SendKeyboardText("");
+        break;
+    case WM_IME_NOTIFY:
+        switch (wParam)
+        {
+        case IMN_SETCONVERSIONMODE:
+            break;
+        case IMN_SETOPENSTATUS:
+            break;
+        case IMN_OPENCANDIDATE:
+        case IMN_CHANGECANDIDATE:
+            trap = SDL_TRUE;
+            break;
+        case IMN_CLOSECANDIDATE:
+            trap = SDL_TRUE;
+            break;
+        case IMN_PRIVATE:
+            break;
+        default:
+            trap = SDL_TRUE;
+            break;
+        }
+        break;
+    }
+    return trap;
+}
+
 /* vi: set ts=4 sw=4 expandtab: */