Sync with trunk head
[reactos.git] / dll / win32 / imm32 / imm.c
index 4ba1d63..6f97448 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(imm);
 
-#define FROM_IME 0xcafe1337
-
-static void (*pX11DRV_ForceXIMReset)(HWND);
-
 typedef struct tagIMCCInternal
 {
     DWORD dwLock;
@@ -76,15 +73,12 @@ typedef struct _tagImmHkl{
 
 typedef struct tagInputContextData
 {
-        BOOL            bInternalState;
-        BOOL            bRead;
-        BOOL            bInComposition;
-        HFONT           textfont;
-
         DWORD           dwLock;
         INPUTCONTEXT    IMC;
 
         ImmHkl          *immKbd;
+        HWND            imeWnd;
+        UINT            lastVK;
 } InputContextData;
 
 typedef struct _tagTRANSMSG {
@@ -93,12 +87,12 @@ typedef struct _tagTRANSMSG {
     LPARAM lParam;
 } TRANSMSG, *LPTRANSMSG;
 
-static InputContextData *root_context = NULL;
-static HWND hwndDefault = NULL;
-static HANDLE hImeInst;
-static const WCHAR WC_IMECLASSNAME[] = {'I','M','E',0};
-static ATOM atIMEClass = 0;
+typedef struct _tagIMMThreadData {
+    HIMC defaultContext;
+    HWND hwndDefault;
+} IMMThreadData;
 
+static DWORD tlsIndex = 0;
 static struct list ImmHklList = LIST_INIT(ImmHklList);
 
 /* MSIME messages */
@@ -111,15 +105,174 @@ static UINT WM_MSIME_QUERYPOSITION;
 static UINT WM_MSIME_DOCUMENTFEED;
 
 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
-/*
- * prototypes
- */
-static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
-                                          LPARAM lParam);
-static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable);
-static void ImmInternalPostIMEMessage(InputContextData*, UINT, WPARAM, LPARAM);
-static void ImmInternalSetOpenStatus(BOOL fOpen);
-static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len);
+
+static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
+static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
+static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
+
+
+#define is_himc_ime_unicode(p)  (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE)
+#define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
+
+static BOOL IMM_DestroyContext(HIMC hIMC);
+
+static inline WCHAR *strdupAtoW( const char *str )
+{
+    WCHAR *ret = NULL;
+    if (str)
+    {
+        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+        if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+            MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+    }
+    return ret;
+}
+
+static inline CHAR *strdupWtoA( const WCHAR *str )
+{
+    CHAR *ret = NULL;
+    if (str)
+    {
+        DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
+        if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
+            WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+    }
+    return ret;
+}
+
+static DWORD convert_candidatelist_WtoA(
+        LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
+{
+    DWORD ret, i, len;
+
+    ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
+    if ( lpDst && dwBufLen > 0 )
+    {
+        *lpDst = *lpSrc;
+        lpDst->dwOffset[0] = ret;
+    }
+
+    for ( i = 0; i < lpSrc->dwCount; i++)
+    {
+        LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
+
+        if ( lpDst && dwBufLen > 0 )
+        {
+            LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
+
+            len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
+                                      (LPSTR)dest, dwBufLen, NULL, NULL);
+
+            if ( i + 1 < lpSrc->dwCount )
+                lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
+            dwBufLen -= len * sizeof(char);
+        }
+        else
+            len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
+
+        ret += len * sizeof(char);
+    }
+
+    if ( lpDst )
+        lpDst->dwSize = ret;
+
+    return ret;
+}
+
+static DWORD convert_candidatelist_AtoW(
+        LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
+{
+    DWORD ret, i, len;
+
+    ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
+    if ( lpDst && dwBufLen > 0 )
+    {
+        *lpDst = *lpSrc;
+        lpDst->dwOffset[0] = ret;
+    }
+
+    for ( i = 0; i < lpSrc->dwCount; i++)
+    {
+        LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
+
+        if ( lpDst && dwBufLen > 0 )
+        {
+            LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
+
+            len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
+                                      (LPWSTR)dest, dwBufLen);
+
+            if ( i + 1 < lpSrc->dwCount )
+                lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
+            dwBufLen -= len * sizeof(WCHAR);
+        }
+        else
+            len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
+
+        ret += len * sizeof(WCHAR);
+    }
+
+    if ( lpDst )
+        lpDst->dwSize = ret;
+
+    return ret;
+}
+
+static IMMThreadData* IMM_GetThreadData(void)
+{
+    IMMThreadData* data = TlsGetValue(tlsIndex);
+    if (!data)
+    {
+        data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                         sizeof(IMMThreadData));
+        TlsSetValue(tlsIndex,data);
+        TRACE("Thread Data Created\n");
+    }
+    return data;
+}
+
+static void IMM_FreeThreadData(void)
+{
+    IMMThreadData* data = TlsGetValue(tlsIndex);
+    if (data)
+    {
+        IMM_DestroyContext(data->defaultContext);
+        DestroyWindow(data->hwndDefault);
+        HeapFree(GetProcessHeap(),0,data);
+        TRACE("Thread Data Destroyed\n");
+    }
+}
+
+static HMODULE LoadDefaultWineIME(void)
+{
+    char buffer[MAX_PATH], libname[32], *name, *next;
+    HMODULE module = 0;
+    HKEY hkey;
+
+    TRACE("Attempting to fall back to wine default IME\n");
+
+    strcpy( buffer, "x11" );  /* default value */
+    /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
+    if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey ))
+    {
+        DWORD type, count = sizeof(buffer);
+        RegQueryValueExA( hkey, "Ime", 0, &type, (LPBYTE) buffer, &count );
+        RegCloseKey( hkey );
+    }
+
+    name = buffer;
+    while (name)
+    {
+        next = strchr( name, ',' );
+        if (next) *next++ = 0;
+
+        snprintf( libname, sizeof(libname), "wine%s.drv", name );
+        if ((module = LoadLibraryA( libname )) != 0) break;
+        name = next;
+    }
+
+    return module;
+}
 
 /* ImmHkl loading and freeing */
 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
@@ -128,7 +281,7 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl)
     ImmHkl *ptr;
     WCHAR filename[MAX_PATH];
 
-    TRACE("Seeking ime for keyboard 0x%x\n",(unsigned)hkl);
+    TRACE("Seeking ime for keyboard %p\n",hkl);
 
     LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
     {
@@ -141,32 +294,49 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl)
 
     ptr->hkl = hkl;
     if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
+    if (!ptr->hIME)
+        ptr->hIME = LoadDefaultWineIME();
     if (ptr->hIME)
     {
         LOAD_FUNCPTR(ImeInquire);
-        LOAD_FUNCPTR(ImeDestroy);
-        LOAD_FUNCPTR(ImeSelect);
-        if (!ptr->pImeInquire || !ptr->pImeDestroy || !ptr->pImeSelect)
+        if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
         {
             FreeLibrary(ptr->hIME);
             ptr->hIME = NULL;
         }
         else
         {
-            ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL);
-            LOAD_FUNCPTR(ImeConfigure);
-            LOAD_FUNCPTR(ImeEscape);
-            LOAD_FUNCPTR(ImeSetActiveContext);
-            LOAD_FUNCPTR(ImeToAsciiEx);
-            LOAD_FUNCPTR(NotifyIME);
-            LOAD_FUNCPTR(ImeRegisterWord);
-            LOAD_FUNCPTR(ImeUnregisterWord);
-            LOAD_FUNCPTR(ImeEnumRegisterWord);
-            LOAD_FUNCPTR(ImeSetCompositionString);
-            LOAD_FUNCPTR(ImeConversionList);
-            LOAD_FUNCPTR(ImeProcessKey);
-            LOAD_FUNCPTR(ImeGetRegisterWordStyle);
-            LOAD_FUNCPTR(ImeGetImeMenuItems);
+            LOAD_FUNCPTR(ImeDestroy);
+            LOAD_FUNCPTR(ImeSelect);
+            if (!ptr->pImeSelect || !ptr->pImeDestroy)
+            {
+                FreeLibrary(ptr->hIME);
+                ptr->hIME = NULL;
+            }
+            else
+            {
+                LOAD_FUNCPTR(ImeConfigure);
+                LOAD_FUNCPTR(ImeEscape);
+                LOAD_FUNCPTR(ImeSetActiveContext);
+                LOAD_FUNCPTR(ImeToAsciiEx);
+                LOAD_FUNCPTR(NotifyIME);
+                LOAD_FUNCPTR(ImeRegisterWord);
+                LOAD_FUNCPTR(ImeUnregisterWord);
+                LOAD_FUNCPTR(ImeEnumRegisterWord);
+                LOAD_FUNCPTR(ImeSetCompositionString);
+                LOAD_FUNCPTR(ImeConversionList);
+                LOAD_FUNCPTR(ImeProcessKey);
+                LOAD_FUNCPTR(ImeGetRegisterWordStyle);
+                LOAD_FUNCPTR(ImeGetImeMenuItems);
+                /* make sure our classname is WCHAR */
+                if (!is_kbd_ime_unicode(ptr))
+                {
+                    WCHAR bufW[17];
+                    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
+                                        -1, bufW, 17);
+                    lstrcpyW(ptr->imeClassName, bufW);
+                }
+            }
         }
     }
     list_add_head(&ImmHklList,&ptr->entry);
@@ -191,54 +361,6 @@ static void IMM_FreeAllImmHkl(void)
     }
 }
 
-static VOID IMM_PostResult(InputContextData *data)
-{
-    unsigned int i;
-    LPCOMPOSITIONSTRING compstr;
-    LPBYTE compdata;
-    LPWSTR ResultStr;
-    HIMCC newCompStr;
-
-    TRACE("Posting result as IME_CHAR\n");
-    compdata = ImmLockIMCC(root_context->IMC.hCompStr);
-    compstr = (LPCOMPOSITIONSTRING)compdata;
-    ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
-
-    for (i = 0; i < compstr->dwResultStrLen; i++)
-        ImmInternalPostIMEMessage (root_context, WM_IME_CHAR, ResultStr[i], 1);
-
-    ImmUnlockIMCC(root_context->IMC.hCompStr);
-
-    /* clear the buffer */
-    newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
-    ImmDestroyIMCC(root_context->IMC.hCompStr);
-    root_context->IMC.hCompStr = newCompStr;
-}
-
-static void IMM_Register(void)
-{
-    WNDCLASSW wndClass;
-    ZeroMemory(&wndClass, sizeof(WNDCLASSW));
-    wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
-    wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
-    wndClass.cbClsExtra = 0;
-    wndClass.cbWndExtra = 0;
-    wndClass.hInstance = hImeInst;
-    wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
-    wndClass.hIcon = NULL;
-    wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
-    wndClass.lpszMenuName   = 0;
-    wndClass.lpszClassName = WC_IMECLASSNAME;
-    atIMEClass = RegisterClassW(&wndClass);
-}
-
-static void IMM_Unregister(void)
-{
-    if (atIMEClass) {
-        UnregisterClassW(WC_IMECLASSNAME, NULL);
-    }
-}
-
 static void IMM_RegisterMessages(void)
 {
     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
@@ -250,29 +372,26 @@ static void IMM_RegisterMessages(void)
     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
 }
 
-
 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
 {
-    HMODULE x11drv;
-
     TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
     switch (fdwReason)
     {
         case DLL_PROCESS_ATTACH:
-            DisableThreadLibraryCalls(hInstDLL);
-            hImeInst = hInstDLL;
             IMM_RegisterMessages();
-            x11drv = GetModuleHandleA("winex11.drv");
-            if (x11drv) pX11DRV_ForceXIMReset = (void *)GetProcAddress( x11drv, "ForceXIMReset");
+            tlsIndex = TlsAlloc();
+            if (tlsIndex == TLS_OUT_OF_INDEXES)
+                return FALSE;
+            break;
+        case DLL_THREAD_ATTACH:
+            break;
+        case DLL_THREAD_DETACH:
+            IMM_FreeThreadData();
             break;
         case DLL_PROCESS_DETACH:
-            if (hwndDefault)
-            {
-                DestroyWindow(hwndDefault);
-                hwndDefault = 0;
-            }
-            IMM_Unregister();
+            IMM_FreeThreadData();
             IMM_FreeAllImmHkl();
+            TlsFree(tlsIndex);
             break;
     }
     return TRUE;
@@ -306,337 +425,25 @@ static HIMCC ImmCreateBlankCompStr(void)
     HIMCC rc;
     LPCOMPOSITIONSTRING ptr;
     rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
-    ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
+    ptr = ImmLockIMCC(rc);
     memset(ptr,0,sizeof(COMPOSITIONSTRING));
     ptr->dwSize = sizeof(COMPOSITIONSTRING);
     ImmUnlockIMCC(rc);
     return rc;
 }
 
-static void ImmInternalSetOpenStatus(BOOL fOpen)
-{
-    TRACE("Setting internal state to %s\n",(fOpen)?"OPEN":"CLOSED");
-
-    if (root_context->IMC.fOpen && fOpen == FALSE)
-    {
-        ShowWindow(hwndDefault,SW_HIDE);
-        ImmDestroyIMCC(root_context->IMC.hCompStr);
-        root_context->IMC.hCompStr = ImmCreateBlankCompStr();
-    }
-
-    root_context->IMC.fOpen = fOpen;
-    root_context->bInternalState = fOpen;
-
-    ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
-}
-
-static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
-                       LPBYTE target, LPBYTE source, DWORD* lenParam,
-                       DWORD* offsetParam, BOOL wchars )
-{
-     if (origLen > 0 && origOffset > 0)
-     {
-        int truelen = origLen;
-        if (wchars)
-            truelen *= sizeof(WCHAR);
-
-        memcpy(&target[currentOffset], &source[origOffset], truelen);
-
-        *lenParam = origLen;
-        *offsetParam = currentOffset;
-        currentOffset += truelen;
-     }
-     return currentOffset;
-}
-
-static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
-{
-    /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
-     * set and correct */
-    int needed_size;
-    HIMCC   rc;
-    LPBYTE newdata = NULL;
-    LPBYTE olddata = NULL;
-    LPCOMPOSITIONSTRING new_one;
-    LPCOMPOSITIONSTRING lpcs = NULL;
-    INT current_offset = 0;
-
-    TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
-
-    if (old == NULL && compstr == NULL && len == 0)
-        return NULL;
-
-    if (old != NULL)
-    {
-        olddata = ImmLockIMCC(old);
-        lpcs = (LPCOMPOSITIONSTRING)olddata;
-    }
-
-    needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
-                  len + sizeof(DWORD) * 2;
-
-    if (lpcs != NULL)
-    {
-        needed_size += lpcs->dwCompReadAttrLen;
-        needed_size += lpcs->dwCompReadClauseLen;
-        needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwResultReadClauseLen;
-        needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwResultClauseLen;
-        needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwPrivateSize;
-    }
-    rc = ImmCreateIMCC(needed_size);
-    newdata = ImmLockIMCC(rc);
-    new_one = (LPCOMPOSITIONSTRING)newdata;
-
-    new_one->dwSize = needed_size;
-    current_offset = sizeof(COMPOSITIONSTRING);
-    if (lpcs != NULL)
-    {
-        current_offset = updateField(lpcs->dwCompReadAttrLen,
-                                     lpcs->dwCompReadAttrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadAttrLen,
-                                     &new_one->dwCompReadAttrOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompReadClauseLen,
-                                     lpcs->dwCompReadClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadClauseLen,
-                                     &new_one->dwCompReadClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompReadStrLen,
-                                     lpcs->dwCompReadStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadStrLen,
-                                     &new_one->dwCompReadStrOffset, TRUE);
-
-        /* new CompAttr, CompClause, CompStr, dwCursorPos */
-        new_one->dwDeltaStart = 0;
-
-        current_offset = updateField(lpcs->dwResultReadClauseLen,
-                                     lpcs->dwResultReadClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultReadClauseLen,
-                                     &new_one->dwResultReadClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwResultReadStrLen,
-                                     lpcs->dwResultReadStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultReadStrLen,
-                                     &new_one->dwResultReadStrOffset, TRUE);
-
-        current_offset = updateField(lpcs->dwResultClauseLen,
-                                     lpcs->dwResultClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultClauseLen,
-                                     &new_one->dwResultClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwResultStrLen,
-                                     lpcs->dwResultStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultStrLen,
-                                     &new_one->dwResultStrOffset, TRUE);
-
-        current_offset = updateField(lpcs->dwPrivateSize,
-                                     lpcs->dwPrivateOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwPrivateSize,
-                                     &new_one->dwPrivateOffset, FALSE);
-    }
-
-    /* set new data */
-    /* CompAttr */
-    new_one->dwCompAttrLen = len;
-    if (len > 0)
-    {
-        new_one->dwCompAttrOffset = current_offset;
-        memset(&newdata[current_offset],ATTR_INPUT,len);
-        current_offset += len;
-    }
-
-    /* CompClause */
-    if (len > 0)
-    {
-        new_one->dwCompClauseLen = sizeof(DWORD) * 2;
-        new_one->dwCompClauseOffset = current_offset;
-        *(DWORD*)(&newdata[current_offset]) = 0;
-        current_offset += sizeof(DWORD);
-        *(DWORD*)(&newdata[current_offset]) = len;
-        current_offset += sizeof(DWORD);
-    }
-
-    /* CompStr */
-    new_one->dwCompStrLen = len;
-    if (len > 0)
-    {
-        new_one->dwCompStrOffset = current_offset;
-        memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
-    }
-
-    /* CursorPos */
-    new_one->dwCursorPos = len;
-
-    ImmUnlockIMCC(rc);
-    if (lpcs)
-        ImmUnlockIMCC(old);
-
-    return rc;
-}
-
-static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
-{
-    /* we need to make sure the ResultStr and ResultClause fields are all
-     * set and correct */
-    int needed_size;
-    HIMCC   rc;
-    LPBYTE newdata = NULL;
-    LPBYTE olddata = NULL;
-    LPCOMPOSITIONSTRING new_one;
-    LPCOMPOSITIONSTRING lpcs = NULL;
-    INT current_offset = 0;
-
-    TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
-
-    if (old == NULL && resultstr == NULL && len == 0)
-        return NULL;
-
-    if (old != NULL)
-    {
-        olddata = ImmLockIMCC(old);
-        lpcs = (LPCOMPOSITIONSTRING)olddata;
-    }
-
-    needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
-                  sizeof(DWORD) * 2;
-
-    if (lpcs != NULL)
-    {
-        needed_size += lpcs->dwCompReadAttrLen;
-        needed_size += lpcs->dwCompReadClauseLen;
-        needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwCompAttrLen;
-        needed_size += lpcs->dwCompClauseLen;
-        needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwResultReadClauseLen;
-        needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
-        needed_size += lpcs->dwPrivateSize;
-    }
-    rc = ImmCreateIMCC(needed_size);
-    newdata = ImmLockIMCC(rc);
-    new_one = (LPCOMPOSITIONSTRING)newdata;
-
-    new_one->dwSize = needed_size;
-    current_offset = sizeof(COMPOSITIONSTRING);
-    if (lpcs != NULL)
-    {
-        current_offset = updateField(lpcs->dwCompReadAttrLen,
-                                     lpcs->dwCompReadAttrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadAttrLen,
-                                     &new_one->dwCompReadAttrOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompReadClauseLen,
-                                     lpcs->dwCompReadClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadClauseLen,
-                                     &new_one->dwCompReadClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompReadStrLen,
-                                     lpcs->dwCompReadStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompReadStrLen,
-                                     &new_one->dwCompReadStrOffset, TRUE);
-
-        current_offset = updateField(lpcs->dwCompAttrLen,
-                                     lpcs->dwCompAttrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompAttrLen,
-                                     &new_one->dwCompAttrOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompClauseLen,
-                                     lpcs->dwCompClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompClauseLen,
-                                     &new_one->dwCompClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwCompStrLen,
-                                     lpcs->dwCompStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwCompStrLen,
-                                     &new_one->dwCompStrOffset, TRUE);
-
-        new_one->dwCursorPos = lpcs->dwCursorPos;
-        new_one->dwDeltaStart = 0;
-
-        current_offset = updateField(lpcs->dwResultReadClauseLen,
-                                     lpcs->dwResultReadClauseOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultReadClauseLen,
-                                     &new_one->dwResultReadClauseOffset, FALSE);
-
-        current_offset = updateField(lpcs->dwResultReadStrLen,
-                                     lpcs->dwResultReadStrOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwResultReadStrLen,
-                                     &new_one->dwResultReadStrOffset, TRUE);
-
-        /* new ResultClause , ResultStr */
-
-        current_offset = updateField(lpcs->dwPrivateSize,
-                                     lpcs->dwPrivateOffset,
-                                     current_offset, newdata, olddata,
-                                     &new_one->dwPrivateSize,
-                                     &new_one->dwPrivateOffset, FALSE);
-    }
-
-    /* set new data */
-    /* ResultClause */
-    if (len > 0)
-    {
-        new_one->dwResultClauseLen = sizeof(DWORD) * 2;
-        new_one->dwResultClauseOffset = current_offset;
-        *(DWORD*)(&newdata[current_offset]) = 0;
-        current_offset += sizeof(DWORD);
-        *(DWORD*)(&newdata[current_offset]) = len;
-        current_offset += sizeof(DWORD);
-    }
-
-    /* ResultStr */
-    new_one->dwResultStrLen = len;
-    if (len > 0)
-    {
-        new_one->dwResultStrOffset = current_offset;
-        memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
-    }
-    ImmUnlockIMCC(rc);
-    if (lpcs)
-        ImmUnlockIMCC(old);
-
-    return rc;
-}
-
-
-
 /***********************************************************************
  *             ImmAssociateContext (IMM32.@)
  */
 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
 {
     HIMC old = NULL;
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("(%p, %p):\n", hWnd, hIMC);
 
-    /*
-     * WINE SPECIFIC! MAY CONFLICT
-     * associate the root context we have an XIM created
-     */
-    if (hWnd == 0x000)
-    {
-        root_context = (InputContextData*)hIMC;
-    }
+    if (!IMM_GetThreadData()->defaultContext)
+        IMM_GetThreadData()->defaultContext = ImmCreateContext();
 
     /*
      * If already associated just return
@@ -646,19 +453,26 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
 
     if (hWnd)
     {
-        old = (HIMC)RemovePropW(hWnd,szwWineIMCProperty);
+        old = RemovePropW(hWnd,szwWineIMCProperty);
 
         if (old == NULL)
-            old = (HIMC)root_context;
+            old = IMM_GetThreadData()->defaultContext;
         else if (old == (HIMC)-1)
             old = NULL;
 
-        if (hIMC != (HIMC)root_context)
+        if (hIMC != IMM_GetThreadData()->defaultContext)
         {
             if (hIMC == NULL) /* Meaning disable imm for that window*/
                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
             else
-                SetPropW(hWnd,szwWineIMCProperty,(HANDLE)hIMC);
+                SetPropW(hWnd,szwWineIMCProperty,hIMC);
+        }
+
+        if (old)
+        {
+            InputContextData *old_data = old;
+            if (old_data->IMC.hWnd == hWnd)
+                old_data->IMC.hWnd = NULL;
         }
     }
 
@@ -686,14 +500,48 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
     return old;
 }
 
+
+/*
+ * Helper function for ImmAssociateContextEx
+ */
+static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
+{
+    HIMC hImc = (HIMC)lParam;
+    ImmAssociateContext(hwnd,hImc);
+    return TRUE;
+}
+
 /***********************************************************************
  *              ImmAssociateContextEx (IMM32.@)
  */
 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
 {
-    FIXME("(%p, %p, %d): stub\n", hWnd, hIMC, dwFlags);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    TRACE("(%p, %p, %d): stub\n", hWnd, hIMC, dwFlags);
+
+    if (!IMM_GetThreadData()->defaultContext)
+        IMM_GetThreadData()->defaultContext = ImmCreateContext();
+
+    if (dwFlags == IACE_DEFAULT)
+    {
+        ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext);
+        return TRUE;
+    }
+    else if (dwFlags == IACE_IGNORENOCONTEXT)
+    {
+        if (GetPropW(hWnd,szwWineIMCProperty))
+            ImmAssociateContext(hWnd,hIMC);
+        return TRUE;
+    }
+    else if (dwFlags == IACE_CHILDREN)
+    {
+        EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
+        return TRUE;
+    }
+    else
+    {
+        ERR("Unknown dwFlags 0x%x\n",dwFlags);
+        return FALSE;
+    }
 }
 
 /***********************************************************************
@@ -702,11 +550,33 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
 BOOL WINAPI ImmConfigureIMEA(
   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
 {
-  FIXME("(%p, %p, %d, %p): stub\n",
-    hKL, hWnd, dwMode, lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+
+    TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
+
+    if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
+        return FALSE;
+
+    if (immHkl->hIME && immHkl->pImeConfigure)
+    {
+        if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
+        else
+        {
+            REGISTERWORDW rww;
+            REGISTERWORDA *rwa = lpData;
+            BOOL rc;
+
+            rww.lpReading = strdupAtoW(rwa->lpReading);
+            rww.lpWord = strdupAtoW(rwa->lpWord);
+            rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
+            HeapFree(GetProcessHeap(),0,rww.lpReading);
+            HeapFree(GetProcessHeap(),0,rww.lpWord);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -715,11 +585,33 @@ BOOL WINAPI ImmConfigureIMEA(
 BOOL WINAPI ImmConfigureIMEW(
   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
 {
-  FIXME("(%p, %p, %d, %p): stub\n",
-    hKL, hWnd, dwMode, lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+
+    TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
+
+    if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
+        return FALSE;
+
+    if (immHkl->hIME && immHkl->pImeConfigure)
+    {
+        if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
+        else
+        {
+            REGISTERWORDW *rww = lpData;
+            REGISTERWORDA rwa;
+            BOOL rc;
+
+            rwa.lpReading = strdupWtoA(rww->lpReading);
+            rwa.lpWord = strdupWtoA(rww->lpWord);
+            rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
+            HeapFree(GetProcessHeap(),0,rwa.lpReading);
+            HeapFree(GetProcessHeap(),0,rwa.lpWord);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -728,54 +620,67 @@ BOOL WINAPI ImmConfigureIMEW(
 HIMC WINAPI ImmCreateContext(void)
 {
     InputContextData *new_context;
+    LPGUIDELINE gl;
+    LPCANDIDATEINFO ci;
 
     new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
 
     /* Load the IME */
     new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
 
-    /*
-     * Once we depend on the IME for all the processing like we should
-     * these will become hard errors and result in creation failures
-     */
     if (!new_context->immKbd->hIME)
+    {
         TRACE("IME dll could not be loaded\n");
+        HeapFree(GetProcessHeap(),0,new_context);
+        return 0;
+    }
 
-    /* hCompStr is never NULL */
+    /* the HIMCCs are never NULL */
     new_context->IMC.hCompStr = ImmCreateBlankCompStr();
-    new_context->IMC.hMsgBuf = ImmCreateIMCC(1);
+    new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
+    new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
+    ci = ImmLockIMCC(new_context->IMC.hCandInfo);
+    memset(ci,0,sizeof(CANDIDATEINFO));
+    ci->dwSize = sizeof(CANDIDATEINFO);
+    ImmUnlockIMCC(new_context->IMC.hCandInfo);
+    new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
+    gl = ImmLockIMCC(new_context->IMC.hGuideLine);
+    memset(gl,0,sizeof(GUIDELINE));
+    gl->dwSize = sizeof(GUIDELINE);
+    ImmUnlockIMCC(new_context->IMC.hGuideLine);
 
     /* Initialize the IME Private */
     new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
 
-    if (new_context->immKbd->hIME &&
-        !new_context->immKbd->pImeSelect(new_context, TRUE))
+    if (!new_context->immKbd->pImeSelect(new_context, TRUE))
     {
         TRACE("Selection of IME failed\n");
-        ImmDestroyContext(new_context);
+        IMM_DestroyContext(new_context);
         return 0;
     }
+    SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
 
     new_context->immKbd->uSelected++;
-    TRACE("Created context 0x%x\n",(UINT)new_context);
+    TRACE("Created context %p\n",new_context);
 
-    return (HIMC)new_context;
+    return new_context;
 }
 
-/***********************************************************************
- *             ImmDestroyContext (IMM32.@)
- */
-BOOL WINAPI ImmDestroyContext(HIMC hIMC)
+static BOOL IMM_DestroyContext(HIMC hIMC)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("Destroying %p\n",hIMC);
 
     if (hIMC)
     {
         data->immKbd->uSelected --;
-        if (data->immKbd->hIME)
-            data->immKbd->pImeSelect(hIMC, FALSE);
+        data->immKbd->pImeSelect(hIMC, FALSE);
+        SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0));
+
+        if (IMM_GetThreadData()->hwndDefault == data->imeWnd)
+            IMM_GetThreadData()->hwndDefault = NULL;
+        DestroyWindow(data->imeWnd);
 
         ImmDestroyIMCC(data->IMC.hCompStr);
         ImmDestroyIMCC(data->IMC.hCandInfo);
@@ -783,17 +688,22 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC)
         ImmDestroyIMCC(data->IMC.hPrivate);
         ImmDestroyIMCC(data->IMC.hMsgBuf);
 
-        if (data->textfont)
-        {
-            DeleteObject(data->textfont);
-            data->textfont = NULL;
-        }
-
         HeapFree(GetProcessHeap(),0,data);
     }
     return TRUE;
 }
 
+/***********************************************************************
+ *             ImmDestroyContext (IMM32.@)
+ */
+BOOL WINAPI ImmDestroyContext(HIMC hIMC)
+{
+    if (hIMC != IMM_GetThreadData()->defaultContext)
+        return IMM_DestroyContext(hIMC);
+    else
+        return FALSE;
+}
+
 /***********************************************************************
  *             ImmDisableIME (IMM32.@)
  */
@@ -811,13 +721,31 @@ UINT WINAPI ImmEnumRegisterWordA(
   LPCSTR lpszReading, DWORD dwStyle,
   LPCSTR lpszRegister, LPVOID lpData)
 {
-  FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
-    hKL, lpfnEnumProc,
-    debugstr_a(lpszReading), dwStyle,
-    debugstr_a(lpszRegister), lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
+        debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
+    if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
+    {
+        if (!is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
+                (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
+        else
+        {
+            LPWSTR lpszwReading = strdupAtoW(lpszReading);
+            LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
+            BOOL rc;
+
+            rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
+                                              lpszwReading, dwStyle, lpszwRegister,
+                                              lpData);
+
+            HeapFree(GetProcessHeap(),0,lpszwReading);
+            HeapFree(GetProcessHeap(),0,lpszwRegister);
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -828,13 +756,40 @@ UINT WINAPI ImmEnumRegisterWordW(
   LPCWSTR lpszReading, DWORD dwStyle,
   LPCWSTR lpszRegister, LPVOID lpData)
 {
-  FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
-    hKL, lpfnEnumProc,
-    debugstr_w(lpszReading), dwStyle,
-    debugstr_w(lpszRegister), lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
+        debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
+    if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
+    {
+        if (is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
+                                            lpszRegister, lpData);
+        else
+        {
+            LPSTR lpszaReading = strdupWtoA(lpszReading);
+            LPSTR lpszaRegister = strdupWtoA(lpszRegister);
+            BOOL rc;
+
+            rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
+                                              dwStyle, (LPCWSTR)lpszaRegister, lpData);
+
+            HeapFree(GetProcessHeap(),0,lpszaReading);
+            HeapFree(GetProcessHeap(),0,lpszaRegister);
+            return rc;
+        }
+    }
+    else
+        return 0;
+}
+
+static inline BOOL EscapeRequiresWA(UINT uEscape)
+{
+        if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
+            uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
+            uEscape == IME_ESC_IME_NAME ||
+            uEscape == IME_ESC_GETHELPFILENAME)
+        return TRUE;
+    return FALSE;
 }
 
 /***********************************************************************
@@ -844,11 +799,32 @@ LRESULT WINAPI ImmEscapeA(
   HKL hKL, HIMC hIMC,
   UINT uEscape, LPVOID lpData)
 {
-  FIXME("(%p, %p, %d, %p): stub\n",
-    hKL, hIMC, uEscape, lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
+
+    if (immHkl->hIME && immHkl->pImeEscape)
+    {
+        if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeEscape(hIMC,uEscape,lpData);
+        else
+        {
+            WCHAR buffer[81]; /* largest required buffer should be 80 */
+            LRESULT rc;
+            if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
+            {
+                MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
+                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
+            }
+            else
+            {
+                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
+                WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
+            }
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -858,26 +834,72 @@ LRESULT WINAPI ImmEscapeW(
   HKL hKL, HIMC hIMC,
   UINT uEscape, LPVOID lpData)
 {
-  FIXME("(%p, %p, %d, %p): stub\n",
-    hKL, hIMC, uEscape, lpData
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
+
+    if (immHkl->hIME && immHkl->pImeEscape)
+    {
+        if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeEscape(hIMC,uEscape,lpData);
+        else
+        {
+            CHAR buffer[81]; /* largest required buffer should be 80 */
+            LRESULT rc;
+            if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
+            {
+                WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
+                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
+            }
+            else
+            {
+                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
+                MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
+            }
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
  *             ImmGetCandidateListA (IMM32.@)
  */
 DWORD WINAPI ImmGetCandidateListA(
-  HIMC hIMC, DWORD deIndex,
+  HIMC hIMC, DWORD dwIndex,
   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
 {
-  FIXME("(%p, %d, %p, %d): stub\n",
-    hIMC, deIndex,
-    lpCandList, dwBufLen
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    InputContextData *data = hIMC;
+    LPCANDIDATEINFO candinfo;
+    LPCANDIDATELIST candlist;
+    DWORD ret = 0;
+
+    TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
+
+    if (!data || !data->IMC.hCandInfo)
+       return 0;
+
+    candinfo = ImmLockIMCC(data->IMC.hCandInfo);
+    if ( dwIndex >= candinfo->dwCount ||
+         dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) )
+        goto done;
+
+    candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
+    if ( !candlist->dwSize || !candlist->dwCount )
+        goto done;
+
+    if ( !is_himc_ime_unicode(data) )
+    {
+        ret = candlist->dwSize;
+        if ( lpCandList && dwBufLen >= ret )
+            memcpy(lpCandList, candlist, ret);
+    }
+    else
+        ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
+
+done:
+    ImmUnlockIMCC(data->IMC.hCandInfo);
+    return ret;
 }
 
 /***********************************************************************
@@ -886,9 +908,30 @@ DWORD WINAPI ImmGetCandidateListA(
 DWORD WINAPI ImmGetCandidateListCountA(
   HIMC hIMC, LPDWORD lpdwListCount)
 {
-  FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    InputContextData *data = hIMC;
+    LPCANDIDATEINFO candinfo;
+    DWORD ret, count;
+
+    TRACE("%p, %p\n", hIMC, lpdwListCount);
+
+    if (!data || !lpdwListCount || !data->IMC.hCandInfo)
+       return 0;
+
+    candinfo = ImmLockIMCC(data->IMC.hCandInfo);
+
+    *lpdwListCount = count = candinfo->dwCount;
+
+    if ( !is_himc_ime_unicode(data) )
+        ret = candinfo->dwSize;
+    else
+    {
+        ret = sizeof(CANDIDATEINFO);
+        while ( count-- )
+            ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
+    }
+
+    ImmUnlockIMCC(data->IMC.hCandInfo);
+    return ret;
 }
 
 /***********************************************************************
@@ -897,35 +940,91 @@ DWORD WINAPI ImmGetCandidateListCountA(
 DWORD WINAPI ImmGetCandidateListCountW(
   HIMC hIMC, LPDWORD lpdwListCount)
 {
-  FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    InputContextData *data = hIMC;
+    LPCANDIDATEINFO candinfo;
+    DWORD ret, count;
+
+    TRACE("%p, %p\n", hIMC, lpdwListCount);
+
+    if (!data || !lpdwListCount || !data->IMC.hCandInfo)
+       return 0;
+
+    candinfo = ImmLockIMCC(data->IMC.hCandInfo);
+
+    *lpdwListCount = count = candinfo->dwCount;
+
+    if ( is_himc_ime_unicode(data) )
+        ret = candinfo->dwSize;
+    else
+    {
+        ret = sizeof(CANDIDATEINFO);
+        while ( count-- )
+            ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
+    }
+
+    ImmUnlockIMCC(data->IMC.hCandInfo);
+    return ret;
 }
 
 /***********************************************************************
  *             ImmGetCandidateListW (IMM32.@)
  */
 DWORD WINAPI ImmGetCandidateListW(
-  HIMC hIMC, DWORD deIndex,
+  HIMC hIMC, DWORD dwIndex,
   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
 {
-  FIXME("(%p, %d, %p, %d): stub\n",
-    hIMC, deIndex,
-    lpCandList, dwBufLen
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    InputContextData *data = hIMC;
+    LPCANDIDATEINFO candinfo;
+    LPCANDIDATELIST candlist;
+    DWORD ret = 0;
+
+    TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
+
+    if (!data || !data->IMC.hCandInfo)
+       return 0;
+
+    candinfo = ImmLockIMCC(data->IMC.hCandInfo);
+    if ( dwIndex >= candinfo->dwCount ||
+         dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) )
+        goto done;
+
+    candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
+    if ( !candlist->dwSize || !candlist->dwCount )
+        goto done;
+
+    if ( is_himc_ime_unicode(data) )
+    {
+        ret = candlist->dwSize;
+        if ( lpCandList && dwBufLen >= ret )
+            memcpy(lpCandList, candlist, ret);
+    }
+    else
+        ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
+
+done:
+    ImmUnlockIMCC(data->IMC.hCandInfo);
+    return ret;
 }
 
 /***********************************************************************
  *             ImmGetCandidateWindow (IMM32.@)
  */
 BOOL WINAPI ImmGetCandidateWindow(
-  HIMC hIMC, DWORD dwBufLen, LPCANDIDATEFORM lpCandidate)
+  HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
 {
-  FIXME("(%p, %d, %p): stub\n", hIMC, dwBufLen, lpCandidate);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    InputContextData *data = hIMC;
+
+    TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
+
+    if (!data || !lpCandidate)
+        return FALSE;
+
+    if ( dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) )
+        return FALSE;
+
+    *lpCandidate = data->IMC.cfCandForm[dwIndex];
+
+    return TRUE;
 }
 
 /***********************************************************************
@@ -939,13 +1038,13 @@ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
     TRACE("(%p, %p):\n", hIMC, lplf);
 
     rc = ImmGetCompositionFontW(hIMC,&lfW);
-    if (rc)
-    {
-        memcpy(lplf,&lfW,sizeof(LOGFONTA));
-        WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
+    if (!rc || !lplf)
+        return FALSE;
+
+    memcpy(lplf,&lfW,sizeof(LOGFONTA));
+    WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
                         LF_FACESIZE, NULL, NULL);
-    }
-    return rc;
+    return TRUE;
 }
 
 /***********************************************************************
@@ -953,11 +1052,11 @@ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
  */
 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("(%p, %p):\n", hIMC, lplf);
 
-    if (!data)
+    if (!data || !lplf)
         return FALSE;
 
     *lplf = data->IMC.lfFont.W;
@@ -965,121 +1064,174 @@ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
     return TRUE;
 }
 
-/***********************************************************************
- *             ImmGetCompositionStringA (IMM32.@)
- */
-LONG WINAPI ImmGetCompositionStringA(
-  HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
+
+/* Helpers for the GetCompositionString functions */
+
+static INT CopyCompStringIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE target, INT tlen,
+                                     BOOL unicode )
 {
-    CHAR *buf;
-    LONG rc = 0;
-    InputContextData *data = (InputContextData*)hIMC;
-    LPCOMPOSITIONSTRING compstr;
-    LPBYTE compdata;
+    INT rc;
 
-    TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
+    if (is_himc_ime_unicode(data) && !unicode)
+        rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)source, slen, (LPSTR)target, tlen, NULL, NULL);
+    else if (!is_himc_ime_unicode(data) && unicode)
+        rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)source, slen, (LPWSTR)target, tlen) * sizeof(WCHAR);
+    else
+    {
+        int dlen = (unicode)?sizeof(WCHAR):sizeof(CHAR);
+        memcpy( target, source, min(slen,tlen)*dlen);
+        rc = slen*dlen;
+    }
 
-    if (!data)
-       return FALSE;
+    return rc;
+}
 
-    if (!data->IMC.hCompStr)
-       return FALSE;
+static INT CopyCompAttrIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, INT sslen,
+                                   LPBYTE target, INT tlen, BOOL unicode )
+{
+    INT rc;
 
-    compdata = ImmLockIMCC(data->IMC.hCompStr);
-    compstr = (LPCOMPOSITIONSTRING)compdata;
+    if (is_himc_ime_unicode(data) && !unicode)
+    {
+        rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, sslen, NULL, 0, NULL, NULL);
+        if (tlen)
+        {
+            const BYTE *src = source;
+            LPBYTE dst = target;
+            int i, j = 0, k = 0;
 
-    if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
-        compstr->dwResultStrOffset > 0)
+            if (rc < tlen)
+                tlen = rc;
+            for (i = 0; i < sslen; ++i)
+            {
+                int len;
+
+                len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)ssource + i, 1,
+                                          NULL, 0, NULL, NULL);
+                for (; len > 0; --len)
+                {
+                    dst[j++] = src[k];
+
+                    if (j >= tlen)
+                        goto end;
+                }
+                ++k;
+            }
+        end:
+            rc = j;
+        }
+    }
+    else if (!is_himc_ime_unicode(data) && unicode)
+    {
+        rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, sslen, NULL, 0);
+        if (tlen)
+        {
+            const BYTE *src = source;
+            LPBYTE dst = target;
+            int i, j = 0;
+
+            if (rc < tlen)
+                tlen = rc;
+            for (i = 0; i < sslen; ++i)
+            {
+                if (IsDBCSLeadByte(((LPSTR)ssource)[i]))
+                    continue;
+
+                dst[j++] = src[i];
+
+                if (j >= tlen)
+                    break;
+            }
+            rc = j;
+        }
+    }
+    else
     {
-        LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
+        memcpy( target, source, min(slen,tlen));
+        rc = slen;
+    }
 
-        TRACE("GSC_RESULTSTR %p %i\n",ResultStr,
-                                    compstr->dwResultStrLen);
+    return rc;
+}
 
-        buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwResultStrLen * 3 );
-        rc = WideCharToMultiByte(CP_ACP, 0, ResultStr,
-                                 compstr->dwResultStrLen , buf,
-                                 compstr->dwResultStrLen * 3, NULL, NULL);
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,buf,rc);
+static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, INT sslen,
+                                     LPBYTE target, INT tlen, BOOL unicode )
+{
+    INT rc;
 
-        data->bRead = TRUE;
-        HeapFree( GetProcessHeap(), 0, buf );
-    }
-    else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
-              compstr->dwCompStrOffset > 0)
+    if (is_himc_ime_unicode(data) && !unicode)
     {
-        LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
-
-        TRACE("GSC_COMPSTR %p %i\n", CompString, compstr->dwCompStrLen);
+        if (tlen)
+        {
+            int i;
 
-        buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwCompStrLen * 3 );
-        rc = WideCharToMultiByte(CP_ACP, 0, CompString,
-                                 compstr->dwCompStrLen, buf,
-                                 compstr->dwCompStrLen * 3, NULL, NULL);
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,buf,rc);
-        HeapFree( GetProcessHeap(), 0, buf );
+            if (slen < tlen)
+                tlen = slen;
+            tlen /= sizeof (DWORD);
+            for (i = 0; i < tlen; ++i)
+            {
+                ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
+                                                          ((DWORD *)source)[i],
+                                                          NULL, 0,
+                                                          NULL, NULL);
+            }
+            rc = sizeof (DWORD) * i;
+        }
+        else
+            rc = slen;
     }
-    else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
-             compstr->dwCompAttrOffset > 0)
+    else if (!is_himc_ime_unicode(data) && unicode)
     {
-        LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
-        TRACE("GSC_COMPATTR %p %i\n", Compattr , compstr->dwCompAttrLen);
+        if (tlen)
+        {
+            int i;
 
-        rc = compstr->dwCompAttrLen;
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,Compattr,rc);
+            if (slen < tlen)
+                tlen = slen;
+            tlen /= sizeof (DWORD);
+            for (i = 0; i < tlen; ++i)
+            {
+                ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
+                                                          ((DWORD *)source)[i],
+                                                          NULL, 0);
+            }
+            rc = sizeof (DWORD) * i;
+        }
+        else
+            rc = slen;
     }
-    else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
-             compstr->dwCompClauseOffset > 0)
+    else
     {
-        LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
-        TRACE("GSC_COMPCLAUSE %p %i\n", Compclause, compstr->dwCompClauseLen);
-
-        rc = compstr->dwCompClauseLen;
-        if (dwBufLen >= compstr->dwCompClauseLen)
-            memcpy(lpBuf,Compclause,rc);
+        memcpy( target, source, min(slen,tlen));
+        rc = slen;
     }
-    else if (dwIndex == GCS_RESULTCLAUSE && compstr->dwResultClauseLen > 0 &&
-             compstr->dwResultClauseOffset > 0)
-    {
-        LPWSTR Resultclause = (LPWSTR)(compdata + compstr->dwResultClauseOffset);
-        TRACE("GSC_RESULTCLAUSE %p %i\n", Resultclause, compstr->dwResultClauseLen);
 
-        rc = compstr->dwResultClauseLen;
-        if (dwBufLen >= compstr->dwResultClauseLen)
-            memcpy(lpBuf,Resultclause,rc);
-    }
-    else if (dwIndex == GCS_CURSORPOS)
+    return rc;
+}
+
+static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
+{
+    int rc;
+
+    if (is_himc_ime_unicode(data) && !unicode)
     {
-        TRACE("GSC_CURSORPOS\n");
-        rc = compstr->dwCursorPos;
+        rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
     }
-    else if (dwIndex == GCS_DELTASTART)
+    else if (!is_himc_ime_unicode(data) && unicode)
     {
-        TRACE("GCS_DELTASTART\n");
-        rc = compstr->dwDeltaStart;
+        rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
     }
     else
-    {
-        FIXME("Unhandled index 0x%x\n",dwIndex);
-    }
-
-    ImmUnlockIMCC(data->IMC.hCompStr);
+        rc = offset;
 
     return rc;
 }
 
-/***********************************************************************
- *             ImmGetCompositionStringW (IMM32.@)
- */
-LONG WINAPI ImmGetCompositionStringW(
-  HIMC hIMC, DWORD dwIndex,
-  LPVOID lpBuf, DWORD dwBufLen)
+static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
+                                      DWORD dwBufLen, BOOL unicode)
 {
     LONG rc = 0;
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
     LPCOMPOSITIONSTRING compstr;
     LPBYTE compdata;
 
@@ -1094,88 +1246,104 @@ LONG WINAPI ImmGetCompositionStringW(
     compdata = ImmLockIMCC(data->IMC.hCompStr);
     compstr = (LPCOMPOSITIONSTRING)compdata;
 
-    if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
-        compstr->dwResultStrOffset > 0)
-    {
-        LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
-        data->bRead = TRUE;
-        rc =  compstr->dwResultStrLen * sizeof(WCHAR);
-
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,ResultStr,rc);
-    }
-    else if (dwIndex == GCS_RESULTREADSTR && compstr->dwResultReadStrLen > 0 &&
-             compstr->dwResultReadStrOffset > 0)
-    {
-        LPWSTR ResultReadString = (LPWSTR)(compdata + compstr->dwResultReadStrOffset);
-
-        rc = compstr->dwResultReadStrLen * sizeof(WCHAR);
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,ResultReadString,rc);
-    }
-    else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
-              compstr->dwCompStrOffset > 0)
-    {
-        LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
-        rc = compstr->dwCompStrLen * sizeof(WCHAR);
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,CompString,rc);
-    }
-    else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
-             compstr->dwCompAttrOffset > 0)
-    {
-
-        LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
-
-        rc = compstr->dwCompAttrLen;
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,Compattr,rc);
-    }
-    else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
-             compstr->dwCompClauseOffset > 0)
-    {
-        LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
-
-        rc = compstr->dwCompClauseLen;
-        if (dwBufLen >= compstr->dwCompClauseLen)
-            memcpy(lpBuf,Compclause,rc);
-    }
-    else if (dwIndex == GCS_COMPREADSTR && compstr->dwCompReadStrLen > 0 &&
-              compstr->dwCompReadStrOffset > 0)
-    {
-        LPWSTR CompReadString = (LPWSTR)(compdata + compstr->dwCompReadStrOffset);
-
-        rc = compstr->dwCompReadStrLen * sizeof(WCHAR);
-
-        if (dwBufLen >= rc)
-            memcpy(lpBuf,CompReadString,rc);
-    }
-    else if (dwIndex == GCS_CURSORPOS)
-    {
-        TRACE("GSC_CURSORPOS\n");
-        rc = compstr->dwCursorPos;
-    }
-    else if (dwIndex == GCS_DELTASTART)
-    {
+    switch (dwIndex)
+    {
+    case GCS_RESULTSTR:
+        TRACE("GCS_RESULTSTR\n");
+        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPSTR:
+        TRACE("GCS_COMPSTR\n");
+        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPATTR:
+        TRACE("GCS_COMPATTR\n");
+        rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
+                                     compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
+                                     lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPCLAUSE:
+        TRACE("GCS_COMPCLAUSE\n");
+        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
+                                       compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
+                                       lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_RESULTCLAUSE:
+        TRACE("GCS_RESULTCLAUSE\n");
+        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
+                                       compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen,
+                                       lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_RESULTREADSTR:
+        TRACE("GCS_RESULTREADSTR\n");
+        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_RESULTREADCLAUSE:
+        TRACE("GCS_RESULTREADCLAUSE\n");
+        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
+                                       compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen,
+                                       lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPREADSTR:
+        TRACE("GCS_COMPREADSTR\n");
+        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPREADATTR:
+        TRACE("GCS_COMPREADATTR\n");
+        rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
+                                     compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
+                                     lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_COMPREADCLAUSE:
+        TRACE("GCS_COMPREADCLAUSE\n");
+        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
+                                       compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
+                                       lpBuf, dwBufLen, unicode);
+        break;
+    case GCS_CURSORPOS:
+        TRACE("GCS_CURSORPOS\n");
+        rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
+        break;
+    case GCS_DELTASTART:
         TRACE("GCS_DELTASTART\n");
-        rc = compstr->dwDeltaStart;
-    }
-    else
-    {
+        rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
+        break;
+    default:
         FIXME("Unhandled index 0x%x\n",dwIndex);
-    }   
+        break;
+    }
 
     ImmUnlockIMCC(data->IMC.hCompStr);
 
     return rc;
 }
 
+/***********************************************************************
+ *             ImmGetCompositionStringA (IMM32.@)
+ */
+LONG WINAPI ImmGetCompositionStringA(
+  HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
+{
+    return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
+}
+
+
+/***********************************************************************
+ *             ImmGetCompositionStringW (IMM32.@)
+ */
+LONG WINAPI ImmGetCompositionStringW(
+  HIMC hIMC, DWORD dwIndex,
+  LPVOID lpBuf, DWORD dwBufLen)
+{
+    return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
+}
+
 /***********************************************************************
  *             ImmGetCompositionWindow (IMM32.@)
  */
 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("(%p, %p)\n", hIMC, lpCompForm);
 
@@ -1195,16 +1363,18 @@ HIMC WINAPI ImmGetContext(HWND hWnd)
     HIMC rc = NULL;
 
     TRACE("%p\n", hWnd);
+    if (!IMM_GetThreadData()->defaultContext)
+        IMM_GetThreadData()->defaultContext = ImmCreateContext();
 
-    rc = (HIMC)GetPropW(hWnd,szwWineIMCProperty);
+    rc = GetPropW(hWnd,szwWineIMCProperty);
     if (rc == (HIMC)-1)
         rc = NULL;
     else if (rc == NULL)
-        rc = (HIMC)root_context;
+        rc = IMM_GetThreadData()->defaultContext;
 
     if (rc)
     {
-        InputContextData *data = (InputContextData*)rc;
+        InputContextData *data = rc;
         data->IMC.hWnd = hWnd;
     }
     TRACE("returning %p\n", rc);
@@ -1220,11 +1390,34 @@ DWORD WINAPI ImmGetConversionListA(
   LPCSTR pSrc, LPCANDIDATELIST lpDst,
   DWORD dwBufLen, UINT uFlag)
 {
-  FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
-    hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
+                dwBufLen, uFlag);
+    if (immHkl->hIME && immHkl->pImeConversionList)
+    {
+        if (!is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
+        else
+        {
+            LPCANDIDATELIST lpwDst;
+            DWORD ret = 0, len;
+            LPWSTR pwSrc = strdupAtoW(pSrc);
+
+            len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
+            lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
+            if ( lpwDst )
+            {
+                immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
+                ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
+                HeapFree(GetProcessHeap(), 0, lpwDst);
+            }
+            HeapFree(GetProcessHeap(), 0, pwSrc);
+
+            return ret;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -1235,11 +1428,34 @@ DWORD WINAPI ImmGetConversionListW(
   LPCWSTR pSrc, LPCANDIDATELIST lpDst,
   DWORD dwBufLen, UINT uFlag)
 {
-  FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
-    hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
+                dwBufLen, uFlag);
+    if (immHkl->hIME && immHkl->pImeConversionList)
+    {
+        if (is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
+        else
+        {
+            LPCANDIDATELIST lpaDst;
+            DWORD ret = 0, len;
+            LPSTR paSrc = strdupWtoA(pSrc);
+
+            len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
+            lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
+            if ( lpaDst )
+            {
+                immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
+                ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
+                HeapFree(GetProcessHeap(), 0, lpaDst);
+            }
+            HeapFree(GetProcessHeap(), 0, paSrc);
+
+            return ret;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -1248,11 +1464,18 @@ DWORD WINAPI ImmGetConversionListW(
 BOOL WINAPI ImmGetConversionStatus(
   HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
 {
-    TRACE("(%p, %p, %p): best guess\n", hIMC, lpfdwConversion, lpfdwSentence);
+    InputContextData *data = hIMC;
+
+    TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
+
+    if (!data)
+        return FALSE;
+
     if (lpfdwConversion)
-        *lpfdwConversion = IME_CMODE_NATIVE;
+        *lpfdwConversion = data->IMC.fdwConversion;
     if (lpfdwSentence)
-        *lpfdwSentence = IME_SMODE_NONE;
+        *lpfdwSentence = data->IMC.fdwSentence;
+
     return TRUE;
 }
 
@@ -1261,26 +1484,8 @@ BOOL WINAPI ImmGetConversionStatus(
  */
 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
 {
-  static int shown = 0;
-
-  if (!shown) {
-        FIXME("(%p - %p %p ): semi-stub\n", hWnd,hwndDefault, root_context);
-       shown = 1;
-  }
-
-  if (hwndDefault == NULL)
-  {
-        static const WCHAR the_name[] = {'I','M','E','\0'};
-
-        IMM_Register();
-        hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, WC_IMECLASSNAME,
-                the_name, WS_POPUP, 0, 0, 1, 1, 0, 0,
-                hImeInst, 0);
-
-        TRACE("Default created (%p)\n",hwndDefault);
-  }
-
-  return hwndDefault;
+    TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault);
+    return IMM_GetThreadData()->hwndDefault;
 }
 
 /***********************************************************************
@@ -1391,15 +1596,12 @@ UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
  */
 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
 {
-    static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
-    static const WCHAR fmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','x',0};
-
     HKEY hkey;
     DWORD length;
     DWORD rc;
-    WCHAR regKey[sizeof(fmt)/sizeof(WCHAR)+8];
+    WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8];
 
-    wsprintfW( regKey, fmt, (unsigned)hKL );
+    wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
     rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
     if (rc != ERROR_SUCCESS)
     {
@@ -1440,7 +1642,7 @@ UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
  */
 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
 {
-  InputContextData *data = (InputContextData*)hIMC;
+  InputContextData *data = hIMC;
 
     if (!data)
         return FALSE;
@@ -1455,40 +1657,24 @@ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
 {
     DWORD rc = 0;
+    ImmHkl *kbd;
+
     TRACE("(%p, %d)\n", hKL, fdwIndex);
+    kbd = IMM_GetImmHkl(hKL);
 
-    switch (fdwIndex)
+    if (kbd && kbd->hIME)
     {
-        case IGP_PROPERTY:
-            TRACE("(%s)\n", "IGP_PROPERTY");
-            rc = IME_PROP_UNICODE | IME_PROP_AT_CARET;
-            break;
-        case IGP_CONVERSION:
-            FIXME("(%s)\n", "IGP_CONVERSION");
-            rc = IME_CMODE_NATIVE;
-            break;
-        case IGP_SENTENCE:
-            FIXME("%s)\n", "IGP_SENTENCE");
-            rc = IME_SMODE_AUTOMATIC;
-            break;
-        case IGP_SETCOMPSTR:
-            TRACE("(%s)\n", "IGP_SETCOMPSTR");
-            rc = 0;
-            break;
-        case IGP_SELECT:
-            TRACE("(%s)\n", "IGP_SELECT");
-            rc = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE;
-            break;
-        case IGP_GETIMEVERSION:
-            TRACE("(%s)\n", "IGP_GETIMEVERSION");
-            rc = IMEVER_0400;
-            break;
-        case IGP_UI:
-            TRACE("(%s)\n", "IGP_UI");
-            rc = 0;
-            break;
-        default:
-            rc = 0;
+        switch (fdwIndex)
+        {
+            case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
+            case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
+            case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
+            case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
+            case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
+            case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
+            case IGP_UI: rc = 0; break;
+            default: rc = 0;
+        }
     }
     return rc;
 }
@@ -1499,9 +1685,26 @@ DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
 UINT WINAPI ImmGetRegisterWordStyleA(
   HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
 {
-  FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
+    if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
+    {
+        if (!is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
+        else
+        {
+            STYLEBUFW sbw;
+            UINT rc;
+
+            rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
+            WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
+                lpStyleBuf->szDescription, 32, NULL, NULL);
+            lpStyleBuf->dwStyle = sbw.dwStyle;
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -1510,9 +1713,26 @@ UINT WINAPI ImmGetRegisterWordStyleA(
 UINT WINAPI ImmGetRegisterWordStyleW(
   HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
 {
-  FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
+    if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
+    {
+        if (is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
+        else
+        {
+            STYLEBUFA sba;
+            UINT rc;
+
+            rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
+            MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
+                lpStyleBuf->szDescription, 32);
+            lpStyleBuf->dwStyle = sba.dwStyle;
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -1520,9 +1740,16 @@ UINT WINAPI ImmGetRegisterWordStyleW(
  */
 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
 {
-  FIXME("(%p, %p): stub\n", hIMC, lpptPos);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    InputContextData *data = hIMC;
+
+    TRACE("(%p, %p)\n", hIMC, lpptPos);
+
+    if (!data || !lpptPos)
+        return FALSE;
+
+    *lpptPos = data->IMC.ptStatusWndPos;
+
+    return TRUE;
 }
 
 /***********************************************************************
@@ -1531,7 +1758,12 @@ BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
 {
   OSVERSIONINFOA version;
-  FIXME("(%p): stub\n", hWnd);
+  InputContextData *data = ImmGetContext( hWnd );
+  TRACE("%p\n", hWnd);
+
+  if ( data )
+      return data->lastVK;
+
   GetVersionExA( &version );
   switch(version.dwPlatformId)
   {
@@ -1551,11 +1783,21 @@ UINT WINAPI ImmGetVirtualKey(HWND hWnd)
 HKL WINAPI ImmInstallIMEA(
   LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
 {
-  FIXME("(%s, %s): stub\n",
-    debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return NULL;
+    LPWSTR lpszwIMEFileName;
+    LPWSTR lpszwLayoutText;
+    HKL hkl;
+
+    TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
+                         debugstr_a(lpszLayoutText));
+
+    lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
+    lpszwLayoutText = strdupAtoW(lpszLayoutText);
+
+    hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
+
+    HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
+    HeapFree(GetProcessHeap(),0,lpszwLayoutText);
+    return hkl;
 }
 
 /***********************************************************************
@@ -1564,11 +1806,56 @@ HKL WINAPI ImmInstallIMEA(
 HKL WINAPI ImmInstallIMEW(
   LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
 {
-  FIXME("(%s, %s): stub\n",
-    debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return NULL;
+    INT lcid = GetUserDefaultLCID();
+    INT count;
+    HKL hkl;
+    DWORD rc;
+    HKEY hkey;
+    WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8];
+
+    TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
+                          debugstr_w(lpszLayoutText));
+
+    /* Start with 2.  e001 will be blank and so default to the wine internal IME */
+    count = 2;
+
+    while (count < 0xfff)
+    {
+        DWORD disposition = 0;
+
+        hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
+        wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
+
+        rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
+        if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
+            break;
+        else if (rc == ERROR_SUCCESS)
+            RegCloseKey(hkey);
+
+        count++;
+    }
+
+    if (count == 0xfff)
+    {
+        WARN("Unable to find slot to install IME\n");
+        return 0;
+    }
+
+    if (rc == ERROR_SUCCESS)
+    {
+        rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (LPBYTE)lpszIMEFileName,
+                            (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
+        if (rc == ERROR_SUCCESS)
+            rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (LPBYTE)lpszLayoutText,
+                                (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
+        RegCloseKey(hkey);
+        return hkl;
+    }
+    else
+    {
+        WARN("Unable to set IME registry values\n");
+        return 0;
+    }
 }
 
 /***********************************************************************
@@ -1576,12 +1863,10 @@ HKL WINAPI ImmInstallIMEW(
  */
 BOOL WINAPI ImmIsIME(HKL hKL)
 {
-  TRACE("(%p): semi-stub\n", hKL);
-  /*
-   * FIXME: Dead key locales will return TRUE here when they should not
-   * There is probably a more proper way to check this.
-   */
-  return (root_context != NULL);
+    ImmHkl *ptr;
+    TRACE("(%p):\n", hKL);
+    ptr = IMM_GetImmHkl(hKL);
+    return (ptr && ptr->hIME);
 }
 
 /***********************************************************************
@@ -1604,11 +1889,11 @@ BOOL WINAPI ImmIsUIMessageA(
         (msg == WM_MSIME_DOCUMENTFEED))
 
     {
-        if (!hwndDefault)
+        if (!IMM_GetThreadData()->hwndDefault)
             ImmGetDefaultIMEWnd(NULL);
 
         if (hWndIME == NULL)
-            PostMessageA(hwndDefault, msg, wParam, lParam);
+            PostMessageA(IMM_GetThreadData()->hwndDefault, msg, wParam, lParam);
 
         rc = TRUE;
     }
@@ -1622,7 +1907,7 @@ BOOL WINAPI ImmIsUIMessageW(
   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     BOOL rc = FALSE;
-    TRACE("(%p, %d, %ld, %ld): stub\n", hWndIME, msg, wParam, lParam);
+    TRACE("(%p, %d, %ld, %ld):\n", hWndIME, msg, wParam, lParam);
     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
         (msg == WM_MSIME_SERVICE) ||
@@ -1642,126 +1927,15 @@ BOOL WINAPI ImmIsUIMessageW(
 BOOL WINAPI ImmNotifyIME(
   HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
 {
-    BOOL rc = FALSE;
+    InputContextData *data = hIMC;
 
     TRACE("(%p, %d, %d, %d)\n",
         hIMC, dwAction, dwIndex, dwValue);
 
-    if (!root_context)
-        return rc;
-
-    switch(dwAction)
-    {
-        case NI_CHANGECANDIDATELIST:
-            FIXME("%s\n","NI_CHANGECANDIDATELIST");
-            break;
-        case NI_CLOSECANDIDATE:
-            FIXME("%s\n","NI_CLOSECANDIDATE");
-            break;
-        case NI_COMPOSITIONSTR:
-            switch (dwIndex)
-            {
-                case CPS_CANCEL:
-                    TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_CANCEL");
-                    {
-                        BOOL send;
-                        LPCOMPOSITIONSTRING lpCompStr;
-
-                        if (pX11DRV_ForceXIMReset)
-                            pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
-
-                        lpCompStr = ImmLockIMCC(root_context->IMC.hCompStr);
-                        send = (lpCompStr->dwCompStrLen != 0);
-                        ImmUnlockIMCC(root_context->IMC.hCompStr);
-
-                        ImmDestroyIMCC(root_context->IMC.hCompStr);
-                        root_context->IMC.hCompStr = ImmCreateBlankCompStr();
-
-                        if (send)
-                            ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
-                                                  GCS_COMPSTR);
-                        rc = TRUE;
-                    }
-                    break;
-                case CPS_COMPLETE:
-                    TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_COMPLETE");
-                    if (hIMC != (HIMC)FROM_IME && pX11DRV_ForceXIMReset)
-                        pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
-                    {
-                        HIMCC newCompStr;
-                        DWORD cplen = 0;
-                        LPWSTR cpstr;
-                        LPCOMPOSITIONSTRING cs = NULL;
-                        LPBYTE cdata = NULL;
-
-                        /* clear existing result */
-                        newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
-                        ImmDestroyIMCC(root_context->IMC.hCompStr);
-                        root_context->IMC.hCompStr = newCompStr;
-
-                        if (root_context->IMC.hCompStr)
-                        {
-                            cdata = ImmLockIMCC(root_context->IMC.hCompStr);
-                            cs = (LPCOMPOSITIONSTRING)cdata;
-                            cplen = cs->dwCompStrLen;
-                            cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
-                            ImmUnlockIMCC(root_context->IMC.hCompStr);
-                        }
-                        if (cplen > 0)
-                        {
-                            WCHAR param = cpstr[0];
-                            newCompStr = updateResultStr(root_context->IMC.hCompStr, cpstr, cplen);
-                            ImmDestroyIMCC(root_context->IMC.hCompStr);
-                            root_context->IMC.hCompStr = newCompStr;
-                            newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
-                            ImmDestroyIMCC(root_context->IMC.hCompStr);
-                            root_context->IMC.hCompStr = newCompStr;
-
-                            root_context->bRead = FALSE;
-
-                            ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
-                                                  GCS_COMPSTR);
-
-                            ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION,
-                                            param,
-                                            GCS_RESULTSTR|GCS_RESULTCLAUSE);
-                        }
-
-                        ImmInternalPostIMEMessage(root_context, WM_IME_ENDCOMPOSITION, 0, 0);
-                        root_context->bInComposition = FALSE;
-                    }
-                    break;
-                case CPS_CONVERT:
-                    FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_CONVERT");
-                    break;
-                case CPS_REVERT:
-                    FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_REVERT");
-                    break;
-                default:
-                    ERR("%s - %s (%i)\n","NI_COMPOSITIONSTR","UNKNOWN",dwIndex);
-                    break;
-            }
-            break;
-        case NI_IMEMENUSELECTED:
-            FIXME("%s\n", "NI_IMEMENUSELECTED");
-            break;
-        case NI_OPENCANDIDATE:
-            FIXME("%s\n", "NI_OPENCANDIDATE");
-            break;
-        case NI_SELECTCANDIDATESTR:
-            FIXME("%s\n", "NI_SELECTCANDIDATESTR");
-            break;
-        case NI_SETCANDIDATE_PAGESIZE:
-            FIXME("%s\n", "NI_SETCANDIDATE_PAGESIZE");
-            break;
-        case NI_SETCANDIDATE_PAGESTART:
-            FIXME("%s\n", "NI_SETCANDIDATE_PAGESTART");
-            break;
-        default:
-            ERR("Unknown\n");
-    }
+    if (!data || ! data->immKbd->pNotifyIME)
+        return FALSE;
 
-    return rc;
+    return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
 }
 
 /***********************************************************************
@@ -1770,11 +1944,28 @@ BOOL WINAPI ImmNotifyIME(
 BOOL WINAPI ImmRegisterWordA(
   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
 {
-  FIXME("(%p, %s, %d, %s): stub\n",
-    hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
+                    debugstr_a(lpszRegister));
+    if (immHkl->hIME && immHkl->pImeRegisterWord)
+    {
+        if (!is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
+                                            (LPCWSTR)lpszRegister);
+        else
+        {
+            LPWSTR lpszwReading = strdupAtoW(lpszReading);
+            LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
+            BOOL rc;
+
+            rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
+            HeapFree(GetProcessHeap(),0,lpszwReading);
+            HeapFree(GetProcessHeap(),0,lpszwRegister);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -1783,11 +1974,28 @@ BOOL WINAPI ImmRegisterWordA(
 BOOL WINAPI ImmRegisterWordW(
   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
 {
-  FIXME("(%p, %s, %d, %s): stub\n",
-    hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
+                    debugstr_w(lpszRegister));
+    if (immHkl->hIME && immHkl->pImeRegisterWord)
+    {
+        if (is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
+        else
+        {
+            LPSTR lpszaReading = strdupWtoA(lpszReading);
+            LPSTR lpszaRegister = strdupWtoA(lpszRegister);
+            BOOL rc;
+
+            rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
+                                          (LPCWSTR)lpszaRegister);
+            HeapFree(GetProcessHeap(),0,lpszaReading);
+            HeapFree(GetProcessHeap(),0,lpszaRegister);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -1795,13 +2003,43 @@ BOOL WINAPI ImmRegisterWordW(
  */
 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
 {
-  static int shown = 0;
+  static int shown = 0;
+
+  if (!shown) {
+     FIXME("(%p, %p): stub\n", hWnd, hIMC);
+     shown = 1;
+  }
+  return TRUE;
+}
+
+/***********************************************************************
+*              ImmRequestMessageA(IMM32.@)
+*/
+LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
+{
+    InputContextData *data = hIMC;
+
+    TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
+
+    if (data && IsWindow(data->IMC.hWnd))
+        return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
+
+     return 0;
+}
+
+/***********************************************************************
+*              ImmRequestMessageW(IMM32.@)
+*/
+LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
+{
+    InputContextData *data = hIMC;
 
-  if (!shown) {
-     FIXME("(%p, %p): stub\n", hWnd, hIMC);
-     shown = 1;
-  }
-  return TRUE;
+    TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
+
+    if (data && IsWindow(data->IMC.hWnd))
+        return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
+
+     return 0;
 }
 
 /***********************************************************************
@@ -1810,9 +2048,27 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
 BOOL WINAPI ImmSetCandidateWindow(
   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
 {
-  FIXME("(%p, %p): stub\n", hIMC, lpCandidate);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    InputContextData *data = hIMC;
+
+    TRACE("(%p, %p)\n", hIMC, lpCandidate);
+
+    if (!data || !lpCandidate)
+        return FALSE;
+
+    TRACE("\t%x, %x, (%i,%i), (%i,%i - %i,%i)\n",
+            lpCandidate->dwIndex, lpCandidate->dwStyle,
+            lpCandidate->ptCurrentPos.x, lpCandidate->ptCurrentPos.y,
+            lpCandidate->rcArea.top, lpCandidate->rcArea.left,
+            lpCandidate->rcArea.bottom, lpCandidate->rcArea.right);
+
+    if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) )
+        return FALSE;
+
+    data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
+    ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
+    ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
+
+    return TRUE;
 }
 
 /***********************************************************************
@@ -1820,25 +2076,18 @@ BOOL WINAPI ImmSetCandidateWindow(
  */
 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
     TRACE("(%p, %p)\n", hIMC, lplf);
 
-    if (!data)
+    if (!data || !lplf)
         return FALSE;
 
     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
                         LF_FACESIZE);
-
+    ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
 
-    if (data->textfont)
-    {
-        DeleteObject(data->textfont);
-        data->textfont = NULL;
-    }
-
-    data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
     return TRUE;
 }
 
@@ -1847,21 +2096,16 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
  */
 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
     TRACE("(%p, %p)\n", hIMC, lplf);
 
-    if (!data)
+    if (!data || !lplf)
         return FALSE;
 
     data->IMC.lfFont.W = *lplf;
+    ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
 
-    if (data->textfont)
-    {
-        DeleteObject(data->textfont);
-        data->textfont = NULL;
-    }
-    data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
     return TRUE;
 }
 
@@ -1878,10 +2122,25 @@ BOOL WINAPI ImmSetCompositionStringA(
     WCHAR *CompBuffer = NULL;
     WCHAR *ReadBuffer = NULL;
     BOOL rc;
+    InputContextData *data = hIMC;
 
-    TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
+    TRACE("(%p, %d, %p, %d, %p, %d):\n",
             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
 
+    if (!data)
+        return FALSE;
+
+    if (!(dwIndex == SCS_SETSTR ||
+          dwIndex == SCS_CHANGEATTR ||
+          dwIndex == SCS_CHANGECLAUSE ||
+          dwIndex == SCS_SETRECONVERTSTRING ||
+          dwIndex == SCS_QUERYRECONVERTSTRING))
+        return FALSE;
+
+    if (!is_himc_ime_unicode(data))
+        return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
+                        dwCompLen, lpRead, dwReadLen);
+
     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
     if (comp_len)
     {
@@ -1913,64 +2172,55 @@ BOOL WINAPI ImmSetCompositionStringW(
        LPCVOID lpComp, DWORD dwCompLen,
        LPCVOID lpRead, DWORD dwReadLen)
 {
-     DWORD flags = 0;
-     WCHAR wParam  = 0;
-
-     TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
-             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
-
+    DWORD comp_len;
+    DWORD read_len;
+    CHAR *CompBuffer = NULL;
+    CHAR *ReadBuffer = NULL;
+    BOOL rc;
+    InputContextData *data = hIMC;
 
-     if (hIMC != (HIMC)FROM_IME)
-         FIXME("PROBLEM: This only sets the wine level string\n");
+    TRACE("(%p, %d, %p, %d, %p, %d):\n",
+            hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
 
-     /*
-      * Explanation:
-      *  this sets the composition string in the imm32.dll level
-      *  of the composition buffer. we cannot manipulate the xim level
-      *  buffer, which means that once the xim level buffer changes again
-      *  any call to this function from the application will be lost
-      */
+    if (!data)
+        return FALSE;
 
-     if (lpRead && dwReadLen)
-         FIXME("Reading string unimplemented\n");
+    if (!(dwIndex == SCS_SETSTR ||
+          dwIndex == SCS_CHANGEATTR ||
+          dwIndex == SCS_CHANGECLAUSE ||
+          dwIndex == SCS_SETRECONVERTSTRING ||
+          dwIndex == SCS_QUERYRECONVERTSTRING))
+        return FALSE;
 
-     /*
-      * app operating this api to also receive the message from xim
-      */
+    if (is_himc_ime_unicode(data))
+        return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
+                        dwCompLen, lpRead, dwReadLen);
 
-    if (dwIndex == SCS_SETSTR)
+    comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
+                                   NULL);
+    if (comp_len)
     {
-        HIMCC newCompStr;
-        if (!root_context->bInComposition)
-        {
-            ImmInternalPostIMEMessage(root_context, WM_IME_STARTCOMPOSITION, 0, 0);
-            root_context->bInComposition = TRUE;
-        }
-
-        flags = GCS_COMPSTR;
-
-        if (dwCompLen && lpComp)
-        {
-            newCompStr = updateCompStr(root_context->IMC.hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
-            ImmDestroyIMCC(root_context->IMC.hCompStr);
-            root_context->IMC.hCompStr = newCompStr;
+        CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
+        WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
+                            NULL, NULL);
+    }
 
-             wParam = ((const WCHAR*)lpComp)[0];
-             flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
-        }
-        else
-        {
-            newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
-            ImmDestroyIMCC(root_context->IMC.hCompStr);
-            root_context->IMC.hCompStr = newCompStr;
-        }
+    read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
+                                   NULL);
+    if (read_len)
+    {
+        ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
+        WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
+                            NULL, NULL);
     }
 
-     UpdateDataInDefaultIMEWindow(hwndDefault,FALSE);
+    rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
+                                   ReadBuffer, read_len);
 
-     ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, wParam, flags);
+    HeapFree(GetProcessHeap(), 0, CompBuffer);
+    HeapFree(GetProcessHeap(), 0, ReadBuffer);
 
-     return TRUE;
+    return rc;
 }
 
 /***********************************************************************
@@ -1980,7 +2230,7 @@ BOOL WINAPI ImmSetCompositionWindow(
   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
 {
     BOOL reshow = FALSE;
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("(%p, %p)\n", hIMC, lpCompForm);
     TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
@@ -1992,16 +2242,16 @@ BOOL WINAPI ImmSetCompositionWindow(
 
     data->IMC.cfCompForm = *lpCompForm;
 
-    if (IsWindowVisible(hwndDefault))
+    if (IsWindowVisible(IMM_GetThreadData()->hwndDefault))
     {
         reshow = TRUE;
-        ShowWindow(hwndDefault,SW_HIDE);
+        ShowWindow(IMM_GetThreadData()->hwndDefault,SW_HIDE);
     }
 
     /* FIXME: this is a partial stub */
 
     if (reshow)
-        ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
+        ShowWindow(IMM_GetThreadData()->hwndDefault,SW_SHOWNOACTIVATE);
 
     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
     return TRUE;
@@ -2013,16 +2263,30 @@ BOOL WINAPI ImmSetCompositionWindow(
 BOOL WINAPI ImmSetConversionStatus(
   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
 {
-  static int shown = 0;
+    DWORD oldConversion, oldSentence;
+    InputContextData *data = hIMC;
 
-  if (!shown) {
-      FIXME("(%p, %d, %d): stub\n",
-          hIMC, fdwConversion, fdwSentence
-      );
-      shown = 1;
-  }
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
+
+    if (!data)
+        return FALSE;
+
+    if ( fdwConversion != data->IMC.fdwConversion )
+    {
+        oldConversion = data->IMC.fdwConversion;
+        data->IMC.fdwConversion = fdwConversion;
+        ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
+        ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
+    }
+    if ( fdwSentence != data->IMC.fdwSentence )
+    {
+        oldSentence = data->IMC.fdwSentence;
+        data->IMC.fdwSentence = fdwSentence;
+        ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
+        ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
+    }
+
+    return TRUE;
 }
 
 /***********************************************************************
@@ -2030,51 +2294,82 @@ BOOL WINAPI ImmSetConversionStatus(
  */
 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("%p %d\n", hIMC, fOpen);
 
-    if (hIMC == (HIMC)FROM_IME)
-    {
-        ImmInternalSetOpenStatus(fOpen);
-        ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
-        return TRUE;
-    }
-
     if (!data)
         return FALSE;
 
-    if (fOpen != data->bInternalState)
+    if (data->imeWnd == NULL)
     {
-        if (fOpen == FALSE && pX11DRV_ForceXIMReset)
-            pX11DRV_ForceXIMReset(data->IMC.hWnd);
+        /* create the ime window */
+        data->imeWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
+                    data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
+                    0, data->immKbd->hIME, 0);
+        SetWindowLongPtrW(data->imeWnd, IMMGWL_IMC, (LONG_PTR)data);
+        IMM_GetThreadData()->hwndDefault = data->imeWnd;
+    }
 
-        if (fOpen == FALSE)
-            ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
-        else
-            ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
+    if (!fOpen != !data->IMC.fOpen)
+    {
+        data->IMC.fOpen = fOpen;
+        ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
+        ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
+    }
 
-        ImmInternalSetOpenStatus(fOpen);
-        ImmInternalSetOpenStatus(!fOpen);
+    return TRUE;
+}
 
-        if (data->IMC.fOpen == FALSE)
-            ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
-        else
-            ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
+/***********************************************************************
+ *             ImmSetStatusWindowPos (IMM32.@)
+ */
+BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
+{
+    InputContextData *data = hIMC;
+
+    TRACE("(%p, %p)\n", hIMC, lpptPos);
 
+    if (!data || !lpptPos)
         return FALSE;
-    }
+
+    TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y);
+
+    data->IMC.ptStatusWndPos = *lpptPos;
+    ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
+    ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
+
     return TRUE;
 }
 
 /***********************************************************************
- *             ImmSetStatusWindowPos (IMM32.@)
+ *              ImmCreateSoftKeyboard(IMM32.@)
  */
-BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
+HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
 {
-  FIXME("(%p, %p): stub\n", hIMC, lpptPos);
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/***********************************************************************
+ *              ImmDestroySoftKeyboard(IMM32.@)
+ */
+BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
+{
+    FIXME("(%p): stub\n", hSoftWnd);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+/***********************************************************************
+ *              ImmShowSoftKeyboard(IMM32.@)
+ */
+BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
+{
+    FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
 }
 
 /***********************************************************************
@@ -2093,11 +2388,28 @@ BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
 BOOL WINAPI ImmUnregisterWordA(
   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
 {
-  FIXME("(%p, %s, %d, %s): stub\n",
-    hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszUnregister)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
+            debugstr_a(lpszUnregister));
+    if (immHkl->hIME && immHkl->pImeUnregisterWord)
+    {
+        if (!is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
+                                              (LPCWSTR)lpszUnregister);
+        else
+        {
+            LPWSTR lpszwReading = strdupAtoW(lpszReading);
+            LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
+            BOOL rc;
+
+            rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
+            HeapFree(GetProcessHeap(),0,lpszwReading);
+            HeapFree(GetProcessHeap(),0,lpszwUnregister);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -2106,11 +2418,28 @@ BOOL WINAPI ImmUnregisterWordA(
 BOOL WINAPI ImmUnregisterWordW(
   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
 {
-  FIXME("(%p, %s, %d, %s): stub\n",
-    hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister)
-  );
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
+    TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
+            debugstr_w(lpszUnregister));
+    if (immHkl->hIME && immHkl->pImeUnregisterWord)
+    {
+        if (is_kbd_ime_unicode(immHkl))
+            return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
+        else
+        {
+            LPSTR lpszaReading = strdupWtoA(lpszReading);
+            LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
+            BOOL rc;
+
+            rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
+                                            (LPCWSTR)lpszaUnregister);
+            HeapFree(GetProcessHeap(),0,lpszaReading);
+            HeapFree(GetProcessHeap(),0,lpszaUnregister);
+            return rc;
+        }
+    }
+    else
+        return FALSE;
 }
 
 /***********************************************************************
@@ -2120,9 +2449,61 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
     DWORD dwSize)
 {
-  FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType,
-    lpImeParentMenu, lpImeMenu, dwSize);
-  return 0;
+    InputContextData *data = hIMC;
+    TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
+        lpImeParentMenu, lpImeMenu, dwSize);
+    if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
+    {
+        if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
+            return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
+                                (IMEMENUITEMINFOW*)lpImeParentMenu,
+                                (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
+        else
+        {
+            IMEMENUITEMINFOW lpImeParentMenuW;
+            IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
+            DWORD rc;
+
+            if (lpImeParentMenu)
+                parent = &lpImeParentMenuW;
+            if (lpImeMenu)
+            {
+                int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
+                dwSize = count * sizeof(IMEMENUITEMINFOW);
+                lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
+            }
+            else
+                lpImeMenuW = NULL;
+
+            rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
+                                parent, lpImeMenuW, dwSize);
+
+            if (lpImeParentMenu)
+            {
+                memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
+                lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
+                WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
+                    -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
+                    NULL, NULL);
+            }
+            if (lpImeMenu && rc)
+            {
+                unsigned int i;
+                for (i = 0; i < rc; i++)
+                {
+                    memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
+                    lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
+                    WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
+                        -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
+                        NULL, NULL);
+                }
+            }
+            HeapFree(GetProcessHeap(),0,lpImeMenuW);
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -2132,9 +2513,59 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
    DWORD dwSize)
 {
-  FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType,
-    lpImeParentMenu, lpImeMenu, dwSize);
-  return 0;
+    InputContextData *data = hIMC;
+    TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
+        lpImeParentMenu, lpImeMenu, dwSize);
+    if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
+    {
+        if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
+            return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
+                                lpImeParentMenu, lpImeMenu, dwSize);
+        else
+        {
+            IMEMENUITEMINFOA lpImeParentMenuA;
+            IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
+            DWORD rc;
+
+            if (lpImeParentMenu)
+                parent = &lpImeParentMenuA;
+            if (lpImeMenu)
+            {
+                int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
+                dwSize = count * sizeof(IMEMENUITEMINFOA);
+                lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
+            }
+            else
+                lpImeMenuA = NULL;
+
+            rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
+                                (IMEMENUITEMINFOW*)parent,
+                                (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
+
+            if (lpImeParentMenu)
+            {
+                memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
+                lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
+                MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
+                    -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
+            }
+            if (lpImeMenu && rc)
+            {
+                unsigned int i;
+                for (i = 0; i < rc; i++)
+                {
+                    memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
+                    lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
+                    MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
+                        -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
+                }
+            }
+            HeapFree(GetProcessHeap(),0,lpImeMenuA);
+            return rc;
+        }
+    }
+    else
+        return 0;
 }
 
 /***********************************************************************
@@ -2142,7 +2573,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
 */
 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     if (!data)
         return NULL;
@@ -2155,7 +2586,7 @@ LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
 */
 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
     data->dwLock--;
     return (data->dwLock!=0);
 }
@@ -2165,7 +2596,7 @@ BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
 */
 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
     return data->dwLock;
 }
 
@@ -2182,7 +2613,7 @@ HIMCC  WINAPI ImmCreateIMCC(DWORD size)
         return NULL;
 
     internal->dwSize = size;
-    return  (HIMCC)internal;
+    return  internal;
 }
 
 /***********************************************************************
@@ -2200,7 +2631,7 @@ HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
 {
     IMCCInternal *internal;
-    internal = (IMCCInternal*) imcc;
+    internal = imcc;
 
     internal->dwLock ++;
     return internal + 1;
@@ -2212,7 +2643,7 @@ LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
 {
     IMCCInternal *internal;
-    internal = (IMCCInternal*) imcc;
+    internal = imcc;
 
     internal->dwLock --;
     return (internal->dwLock!=0);
@@ -2224,7 +2655,7 @@ BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
 {
     IMCCInternal *internal;
-    internal = (IMCCInternal*) imcc;
+    internal = imcc;
 
     return internal->dwLock;
 }
@@ -2237,7 +2668,7 @@ HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
     IMCCInternal *internal,*newone;
     int real_size = size + sizeof(IMCCInternal);
 
-    internal = (IMCCInternal*) imcc;
+    internal = imcc;
 
     newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size);
     newone->dwSize = size;
@@ -2251,7 +2682,7 @@ HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
 {
     IMCCInternal *internal;
-    internal = (IMCCInternal*) imcc;
+    internal = imcc;
 
     return internal->dwSize;
 }
@@ -2261,15 +2692,15 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
 */
 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
 {
-    InputContextData *data = (InputContextData*)hIMC;
+    InputContextData *data = hIMC;
 
     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
     if (data->IMC.dwNumMsgBuf > 0)
     {
         LPTRANSMSG lpTransMsg;
-        INT i;
+        DWORD i;
 
-        lpTransMsg = (LPTRANSMSG)ImmLockIMCC(data->IMC.hMsgBuf);
+        lpTransMsg = ImmLockIMCC(data->IMC.hMsgBuf);
         for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
             ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
 
@@ -2281,252 +2712,106 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
     return TRUE;
 }
 
-/*****
- * Internal functions to help with IME window management
- */
-static void PaintDefaultIMEWnd(HWND hwnd)
+/***********************************************************************
+*       ImmTranslateMessage(IMM32.@)
+*       ( Undocumented, call internally and from user32.dll )
+*/
+BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
 {
-    PAINTSTRUCT ps;
-    RECT rect;
-    HDC hdc = BeginPaint(hwnd,&ps);
-    LPCOMPOSITIONSTRING compstr;
-    LPBYTE compdata = NULL;
-    HMONITOR monitor;
-    MONITORINFO mon_info;
-    INT offX=0, offY=0;
-
-    GetClientRect(hwnd,&rect);
-    FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
-
-    compdata = ImmLockIMCC(root_context->IMC.hCompStr);
-    compstr = (LPCOMPOSITIONSTRING)compdata;
-
-    if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
-    {
-        SIZE size;
-        POINT pt;
-        HFONT oldfont = NULL;
-        LPWSTR CompString;
-
-        CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
-        if (root_context->textfont)
-            oldfont = SelectObject(hdc,root_context->textfont);
+    InputContextData *data;
+    HIMC imc = ImmGetContext(hwnd);
+    BYTE state[256];
+    UINT scancode;
+    LPVOID list = 0;
+    UINT msg_count;
+    UINT uVirtKey;
+    static const DWORD list_count = 10;
 
+    TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
 
-        GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
-        pt.x = size.cx;
-        pt.y = size.cy;
-        LPtoDP(hdc,&pt,1);
-
-        /*
-         * How this works based on tests on windows:
-         * CFS_POINT: then we start our window at the point and grow it as large
-         *    as it needs to be for the string.
-         * CFS_RECT:  we still use the ptCurrentPos as a starting point and our
-         *    window is only as large as we need for the string, but we do not
-         *    grow such that our window exceeds the given rect.  Wrapping if
-         *    needed and possible.   If our ptCurrentPos is outside of our rect
-         *    then no window is displayed.
-         * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
-         *    maybe becase the default MSIME does not do any IME adjusting.
-         */
-        if (root_context->IMC.cfCompForm.dwStyle != CFS_DEFAULT)
-        {
-            POINT cpt = root_context->IMC.cfCompForm.ptCurrentPos;
-            ClientToScreen(root_context->IMC.hWnd,&cpt);
-            rect.left = cpt.x;
-            rect.top = cpt.y;
-            rect.right = rect.left + pt.x;
-            rect.bottom = rect.top + pt.y;
-            monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
-        }
-        else /* CFS_DEFAULT */
-        {
-            /* Windows places the default IME window in the bottom left */
-            HWND target = root_context->IMC.hWnd;
-            if (!target) target = GetFocus();
-
-            GetWindowRect(target,&rect);
-            rect.top = rect.bottom;
-            rect.right = rect.left + pt.x + 20;
-            rect.bottom = rect.top + pt.y + 20;
-            offX=offY=10;
-            monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
-        }
-
-        if (root_context->IMC.cfCompForm.dwStyle == CFS_RECT)
-        {
-            RECT client;
-            client =root_context->IMC.cfCompForm.rcArea;
-            MapWindowPoints( root_context->IMC.hWnd, 0, (POINT *)&client, 2 );
-            IntersectRect(&rect,&rect,&client);
-            /* TODO:  Wrap the input if needed */
-        }
+    if (imc)
+        data = imc;
+    else
+        return FALSE;
 
-        if (root_context->IMC.cfCompForm.dwStyle == CFS_DEFAULT)
-        {
-            /* make sure we are on the desktop */
-            mon_info.cbSize = sizeof(mon_info);
-            GetMonitorInfoW(monitor, &mon_info);
+    if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
+        return FALSE;
 
-            if (rect.bottom > mon_info.rcWork.bottom)
-            {
-                int shift = rect.bottom - mon_info.rcWork.bottom;
-                rect.top -= shift;
-                rect.bottom -= shift;
-            }
-            if (rect.left < 0)
-            {
-                rect.right -= rect.left;
-                rect.left = 0;
-            }
-            if (rect.right > mon_info.rcWork.right)
-            {
-                int shift = rect.right - mon_info.rcWork.right;
-                rect.left -= shift;
-                rect.right -= shift;
-            }
-        }
+    GetKeyboardState(state);
+    scancode = lKeyData >> 0x10 & 0xff;
 
-        SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
+    list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
+    ((DWORD*)list)[0] = list_count;
 
-        TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
+    if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
+    {
+        WCHAR chr;
 
-        if (oldfont)
-            SelectObject(hdc,oldfont);
+        if (!is_himc_ime_unicode(data))
+            ToAscii(data->lastVK, scancode, state, &chr, 0);
+        else
+            ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
+        uVirtKey = MAKELONG(data->lastVK,chr);
     }
+    else
+        uVirtKey = data->lastVK;
 
-    ImmUnlockIMCC(root_context->IMC.hCompStr);
-
-    EndPaint(hwnd,&ps);
-}
-
-static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable)
-{
-    LPCOMPOSITIONSTRING compstr;
+    msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
+    TRACE("%i messages generated\n",msg_count);
+    if (msg_count && msg_count <= list_count)
+    {
+        UINT i;
+        LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
 
-    if (root_context->IMC.hCompStr)
-        compstr = ImmLockIMCC(root_context->IMC.hCompStr);
-    else
-        compstr = NULL;
+        for (i = 0; i < msg_count; i++)
+            ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
+    }
+    else if (msg_count > list_count)
+        ImmGenerateMessage(imc);
 
-    if (compstr == NULL || compstr->dwCompStrLen == 0)
-        ShowWindow(hwndDefault,SW_HIDE);
-    else if (showable)
-        ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
+    HeapFree(GetProcessHeap(),0,list);
 
-    RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
+    data->lastVK = VK_PROCESSKEY;
 
-    if (compstr != NULL)
-        ImmUnlockIMCC(root_context->IMC.hCompStr);
+    return (msg_count > 0);
 }
 
-/*
- * The window proc for the default IME window
- */
-static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
-                                          LPARAM lParam)
+/***********************************************************************
+*              ImmProcessKey(IMM32.@)
+*       ( Undocumented, called from user32.dll )
+*/
+BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
 {
-    LRESULT rc = 0;
+    InputContextData *data;
+    HIMC imc = ImmGetContext(hwnd);
+    BYTE state[256];
 
-    TRACE("Incoming Message 0x%x  (0x%08x, 0x%08x)\n", msg, (UINT)wParam,
-           (UINT)lParam);
+    TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
 
-    switch(msg)
-    {
-        case WM_PAINT:
-            PaintDefaultIMEWnd(hwnd);
-            return FALSE;
-
-        case WM_NCCREATE:
-            return TRUE;
+    if (imc)
+        data = imc;
+    else
+        return FALSE;
 
-        case WM_CREATE:
-            SetWindowTextA(hwnd,"Wine Ime Active");
-            return TRUE;
+    if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
+        return FALSE;
 
-        case WM_SETFOCUS:
-            if (wParam)
-                SetFocus((HWND)wParam);
-            else
-                FIXME("Received focus, should never have focus\n");
-            break;
-        case WM_IME_COMPOSITION:
-            TRACE("IME message %s, 0x%x, 0x%x (%i)\n",
-                    "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam,
-                     root_context->bRead);
-            if (lParam & GCS_RESULTSTR)
-                    IMM_PostResult(root_context);
-            else
-                 UpdateDataInDefaultIMEWindow(hwnd,TRUE);
-            break;
-        case WM_IME_STARTCOMPOSITION:
-            TRACE("IME message %s, 0x%x, 0x%x\n",
-                    "WM_IME_STARTCOMPOSITION", (UINT)wParam, (UINT)lParam);
-            root_context->IMC.hWnd = GetFocus();
-            ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
-            break;
-        case WM_IME_ENDCOMPOSITION:
-            TRACE("IME message %s, 0x%x, 0x%x\n",
-                    "WM_IME_ENDCOMPOSITION", (UINT)wParam, (UINT)lParam);
-            ShowWindow(hwndDefault,SW_HIDE);
-            break;
-        case WM_IME_SELECT:
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_SELECT",
-                (UINT)wParam, (UINT)lParam);
-            break;
-        case WM_IME_CONTROL:
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_CONTROL",
-                (UINT)wParam, (UINT)lParam);
-            rc = 1;
-            break;
-        case WM_IME_NOTIFY:
-            TRACE("!! IME NOTIFY\n");
-            break;
-       default:
-            TRACE("Non-standard message 0x%x\n",msg);
-    }
-    /* check the MSIME messages */
-    if (msg == WM_MSIME_SERVICE)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_SERVICE",
-                (UINT)wParam, (UINT)lParam);
-            rc = FALSE;
-    }
-    else if (msg == WM_MSIME_RECONVERTOPTIONS)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTOPTIONS",
-                (UINT)wParam, (UINT)lParam);
-    }
-    else if (msg == WM_MSIME_MOUSE)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_MOUSE",
-                (UINT)wParam, (UINT)lParam);
-    }
-    else if (msg == WM_MSIME_RECONVERTREQUEST)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTREQUEST",
-                (UINT)wParam, (UINT)lParam);
-    }
-    else if (msg == WM_MSIME_RECONVERT)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERT",
-                (UINT)wParam, (UINT)lParam);
-    }
-    else if (msg == WM_MSIME_QUERYPOSITION)
-    {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_QUERYPOSITION",
-                (UINT)wParam, (UINT)lParam);
-    }
-    else if (msg == WM_MSIME_DOCUMENTFEED)
+    GetKeyboardState(state);
+    if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
     {
-            TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_DOCUMENTFEED",
-                (UINT)wParam, (UINT)lParam);
+        data->lastVK = vKey;
+        return TRUE;
     }
-    /* DefWndProc if not an IME message */
-    else if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
-                      (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
-        rc = DefWindowProcW(hwnd,msg,wParam,lParam);
 
-    return rc;
+    data->lastVK = VK_PROCESSKEY;
+    return FALSE;
+}
+
+/***********************************************************************
+*              ImmDisableTextFrameService(IMM32.@)
+*/
+BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
+{
+    FIXME("Stub\n");
+    return FALSE;
 }