Aric Stewart : user: Make the edit control IME aware and implement inline editing.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Dec 19 14:22:10 CST 2005


Module: wine
Branch: refs/heads/master
Commit: 314f45dcdb866a813800b315aadfb1a72bb6a9ff
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=314f45dcdb866a813800b315aadfb1a72bb6a9ff

Author: Aric Stewart <aric at codeweavers.com>
Date:   Mon Dec 19 18:17:51 2005 +0100

user: Make the edit control IME aware and implement inline editing.
Makes for a significantly better user experience for CJK users.

---

 dlls/user/Makefile.in |    1 
 dlls/user/edit.c      |  222 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 217 insertions(+), 6 deletions(-)

diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index 2999fd3..fea90ac 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -6,6 +6,7 @@ VPATH     = @srcdir@
 MODULE    = user32.dll
 IMPORTLIB = libuser32.$(IMPLIBEXT)
 IMPORTS   = gdi32 advapi32 kernel32 ntdll
+DELAYIMPORTS = imm32
 EXTRALIBS = $(LIBUNICODE)
 
 SPEC_SRCS16 = \
diff --git a/dlls/user/edit.c b/dlls/user/edit.c
index bc67e43..05575bd 100644
--- a/dlls/user/edit.c
+++ b/dlls/user/edit.c
@@ -53,6 +53,7 @@
 #include "winnt.h"
 #include "wownt32.h"
 #include "win.h"
+#include "imm.h"
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
 #include "wine/unicode.h"
@@ -151,6 +152,11 @@ typedef struct
 				   	   or EM_SETHANDLE16 */
 	HLOCAL hloc32A;			/* alias for ANSI control receiving EM_GETHANDLE
 				   	   or EM_SETHANDLE */
+	/*
+	 * IME Data
+	 */
+	UINT composition_len;   /* lenght of composition, 0 == no composition */
+	int composition_start;  /* the character position for the composition */
 } EDITSTATE;
 
 
@@ -280,6 +286,7 @@ static void	EDIT_WM_Timer(EDITSTATE *es)
 static LRESULT	EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos);
 static void	EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase);
 static void	EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase);
+static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es);
 
 LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
@@ -993,6 +1000,52 @@ static LRESULT WINAPI EditWndProc_common
                     }
                 }
                 break;
+
+            
+	/* IME messages to make the edit control IME aware */           
+	case WM_IME_SETCONTEXT:
+		break;
+
+	case WM_IME_STARTCOMPOSITION:
+	/* 
+	 * FIXME in IME: This message is not always sent like it should be
+	 */
+		if (es->selection_start != es->selection_end)
+		{
+			static const WCHAR empty_stringW[] = {0};
+			EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
+		}
+		es->composition_start = es->selection_end;
+		es->composition_len = 0;
+		break;
+
+	case WM_IME_COMPOSITION:
+		if (es->composition_len == 0)
+		{
+			if (es->selection_start != es->selection_end)
+			{    
+				static const WCHAR empty_stringW[] = {0};
+				EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
+			}
+
+			es->composition_start = es->selection_end;
+		}
+		EDIT_ImeComposition(hwnd,lParam,es);
+		break;
+
+	case WM_IME_ENDCOMPOSITION:
+		es->composition_len= 0;
+		break;
+
+	case WM_IME_COMPOSITIONFULL:
+		break;
+
+	case WM_IME_SELECT:
+		break;
+
+	case WM_IME_CONTROL:
+		break;
+                
 	default:
 		result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
 		break;
@@ -2188,6 +2241,9 @@ static INT EDIT_PaintText(EDITSTATE *es,
 {
 	COLORREF BkColor;
 	COLORREF TextColor;
+	LOGFONTW underline_font;
+	HFONT hUnderline = 0;
+	HFONT old_font = 0;
 	INT ret;
 	INT li;
 	INT BkMode;
@@ -2199,9 +2255,20 @@ static INT EDIT_PaintText(EDITSTATE *es,
 	BkColor = GetBkColor(dc);
 	TextColor = GetTextColor(dc);
 	if (rev) {
-		SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
-		SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
-		SetBkMode( dc, OPAQUE);
+	        if (es->composition_len == 0)
+	        {
+			SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
+			SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+			SetBkMode( dc, OPAQUE);
+	        }
+		else
+		{
+			HFONT current = GetCurrentObject(dc,OBJ_FONT);
+			GetObjectW(current,sizeof(LOGFONTW),&underline_font);
+			underline_font.lfUnderline = TRUE;
+	            	hUnderline = CreateFontIndirectW(&underline_font);
+			old_font = SelectObject(dc,hUnderline);
+	        }
 	}
 	li = EDIT_EM_LineIndex(es, line);
 	if (es->style & ES_MULTILINE) {
@@ -2216,9 +2283,19 @@ static INT EDIT_PaintText(EDITSTATE *es,
 			HeapFree(GetProcessHeap(), 0, text);
 	}
 	if (rev) {
-		SetBkColor(dc, BkColor);
-		SetTextColor(dc, TextColor);
-		SetBkMode( dc, BkMode);
+		if (es->composition_len == 0)
+		{
+			SetBkColor(dc, BkColor);
+			SetTextColor(dc, TextColor);
+			SetBkMode( dc, BkMode);
+		}
+		else
+		{
+			if (old_font)
+				SelectObject(dc,old_font);
+			if (hUnderline)
+				DeleteObject(hUnderline);
+	        }
 	}
 	return ret;
 }
@@ -5216,3 +5293,136 @@ static void EDIT_UpdateText(EDITSTATE *e
     }
     InvalidateRect(es->hwndSelf, rc, bErase);
 }
+
+/********************************************************************
+ * 
+ * The Following code is to handle inline editing from IMEs
+ */
+
+static void EDIT_GetCompositionStr(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
+{
+    DWORD dwBufLen;
+    LPWSTR lpCompStr = NULL;
+    HIMC hIMC;
+    LPSTR lpCompStrAttr = NULL;
+    DWORD dwBufLenAttr;
+
+    if (!(hIMC = ImmGetContext(hwnd)))
+        return;
+
+    dwBufLen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
+
+    if (dwBufLen <= 0)
+    {
+        ImmReleaseContext(hwnd, hIMC);
+        return;
+    }
+
+    lpCompStr = HeapAlloc(GetProcessHeap(),0,dwBufLen);
+    if (!lpCompStr)
+    {
+        ERR("Unable to allocate IME CompositionString\n");
+        ImmReleaseContext(hwnd,hIMC);
+        return;
+    }
+
+    ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
+    lpCompStr[dwBufLen/sizeof(WCHAR)] = 0;
+
+    if (CompFlag & GCS_COMPATTR)
+    {
+        /* 
+         * We do not use the attributes yet. it would tell us what characters
+         * are in transition and which are converted or decided upon
+         */
+        dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
+        if (dwBufLenAttr)
+        {
+            dwBufLenAttr ++;
+            lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr);
+            if (!lpCompStrAttr)
+            {
+                ERR("Unable to allocate IME Attribute String\n");
+                HeapFree(GetProcessHeap(),0,lpCompStr);
+                ImmReleaseContext(hwnd,hIMC);
+                return;
+            }
+            ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr, 
+                    dwBufLenAttr);
+            lpCompStrAttr[dwBufLenAttr] = 0;
+        }
+        else
+            lpCompStrAttr = NULL;
+    }
+
+    /* check for change in composition start */
+    if (es->selection_end < es->composition_start)
+        es->composition_start = es->selection_end;
+    
+    /* replace existing selection string */
+    es->selection_start = es->composition_start;
+
+    if (es->composition_len > 0)
+        es->selection_end = es->composition_start + es->composition_len;
+    else
+        es->selection_end = es->selection_start;
+
+    EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, TRUE, TRUE);
+    es->composition_len = abs(es->composition_start - es->selection_end);
+
+    es->selection_start = es->composition_start;
+    es->selection_end = es->selection_start + es->composition_len;
+
+    HeapFree(GetProcessHeap(),0,lpCompStrAttr);
+    HeapFree(GetProcessHeap(),0,lpCompStr);
+    ImmReleaseContext(hwnd,hIMC);
+}
+
+static void EDIT_GetResultStr(HWND hwnd, EDITSTATE *es)
+{
+    DWORD dwBufLen;
+    LPWSTR lpResultStr;
+    HIMC    hIMC;
+
+    if ( !(hIMC = ImmGetContext(hwnd)))
+        return;
+
+    dwBufLen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
+    if (dwBufLen <= 0)
+    {
+        ImmReleaseContext(hwnd, hIMC);
+        return;
+    }
+
+    lpResultStr = HeapAlloc(GetProcessHeap(),0, dwBufLen);
+    if (!lpResultStr)
+    {
+        ERR("Unable to alloc buffer for IME string\n");
+        ImmReleaseContext(hwnd, hIMC);
+        return;
+    }
+
+    ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, dwBufLen);
+    lpResultStr[dwBufLen/sizeof(WCHAR)] = 0;
+
+    /* check for change in composition start */
+    if (es->selection_end < es->composition_start)
+        es->composition_start = es->selection_end;
+
+    es->selection_start = es->composition_start;
+    es->selection_end = es->composition_start + es->composition_len;
+    EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, TRUE, TRUE);
+    es->composition_start = es->selection_end;
+    es->composition_len = 0;
+
+    HeapFree(GetProcessHeap(),0,lpResultStr);
+    ImmReleaseContext(hwnd, hIMC);
+}
+
+static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
+{
+    if (CompFlag & GCS_RESULTSTR)
+        EDIT_GetResultStr(hwnd,es);
+    if (CompFlag & GCS_COMPSTR)
+        EDIT_GetCompositionStr(hwnd, CompFlag, es);
+}




More information about the wine-cvs mailing list