From 7f0a19c7439ac2eb4fe22ab7f108ede92f9468f4 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 26 Jun 2006 09:20:47 +0000 Subject: [PATCH] - Sync edit control with Wine code - Add imm32 dependency to user32, which is needed for edit control. This may not be a good solution, since Windows XP's user32.dll doesn't import imm32.dll. So maybe in future this should change to dynamic binding instead. But for now it works - Update Wine-sync doc This update reduces number of failing "user32_winetest.exe edit" tests from 44 to 43. svn path=/trunk/; revision=22631 --- reactos/dll/win32/user32/controls/edit.c | 252 ++++++++++++++++++++--- reactos/dll/win32/user32/user32.rbuild | 1 + reactos/media/doc/README.WINE | 2 +- 3 files changed, 225 insertions(+), 30 deletions(-) diff --git a/reactos/dll/win32/user32/controls/edit.c b/reactos/dll/win32/user32/controls/edit.c index a9d7a0269a6..2ac0b2e6381 100644 --- a/reactos/dll/win32/user32/controls/edit.c +++ b/reactos/dll/win32/user32/controls/edit.c @@ -141,6 +141,11 @@ typedef struct #endif HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE or EM_SETHANDLE */ + /* + * IME Data + */ + UINT composition_len; /* length of composition, 0 == no composition */ + int composition_start; /* the character position for the composition */ } EDITSTATE; @@ -203,6 +208,7 @@ static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend); static void EDIT_PaintLine(EDITSTATE *es, HDC hdc, INT line, BOOL rev); static INT EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev); static void EDIT_SetCaretPos(EDITSTATE *es, INT pos, BOOL after_wrap); +static void EDIT_AdjustFormatRect(EDITSTATE *es); static void EDIT_SetRectNP(EDITSTATE *es, LPRECT lprc); static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force); static void EDIT_UpdateScrollInfo(EDITSTATE *es); @@ -277,6 +283,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); @@ -1048,6 +1055,52 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg, } } 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; @@ -1055,6 +1108,8 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg, if (es) EDIT_UnlockBuffer(es, FALSE); + //TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result); + return result; } @@ -1300,7 +1355,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta es->line_count--; } } - else + else if (delta != 0) { while (current_line) { @@ -1401,17 +1456,9 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es) */ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action) { -#ifdef __REACTOS__ INT ret; -#else - INT ret, iWndsLocks; -#endif - /* To avoid any deadlocks, all the locks on the window structures - must be suspended before the control is passed to the application */ #ifndef __REACTOS__ - iWndsLocks = WIN_SuspendWndsLock(); - if (es->word_break_proc16) { HGLOBAL16 hglob16; SEGPTR segptr; @@ -1464,9 +1511,6 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count else ret = EDIT_WordBreakProc(es->text + start, index, count, action); -#ifndef __REACTOS__ - WIN_RestoreWndsLock(iWndsLocks); -#endif return ret; } @@ -1680,7 +1724,7 @@ static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es) * * Initially the edit control allocates a HLOCAL32 buffer * (32 bit linear memory handler). However, 16 bit application - * might send a EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF + * might send an EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF * handler). From that moment on we have to keep using this 16 bit memory * handler, because it is supposed to be valid at all times after EM_GETHANDLE. * What we do is create a HLOCAL16 buffer, copy the text, and do pointer @@ -1846,7 +1890,7 @@ static void EDIT_ML_InvalidateText(EDITSTATE *es, INT start, INT end) * * EDIT_InvalidateText * - * Invalidate the text from offset start upto, but not including, + * Invalidate the text from offset start up to, but not including, * offset end. Useful for (re)painting the selection. * Regions outside the linewidth are not invalidated. * end == -1 means end == TextLength. @@ -2254,6 +2298,9 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col { COLORREF BkColor; COLORREF TextColor; + LOGFONTW underline_font; + HFONT hUnderline = 0; + HFONT old_font = 0; INT ret; INT li; INT BkMode; @@ -2265,9 +2312,20 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col BkColor = GetBkColor(dc); TextColor = GetTextColor(dc); if (rev) { + 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) { @@ -2282,9 +2340,19 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col HeapFree(GetProcessHeap(), 0, text); } if (rev) { + 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; } @@ -2408,9 +2476,6 @@ static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc) */ static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force) { -#ifndef __REACTOS__ - HINSTANCE16 hInstance = GetWindowLongW( es->hwndSelf, GWL_HINSTANCE ); -#endif /* Edit window might be already destroyed */ if(!IsWindow(es->hwndSelf)) @@ -2431,11 +2496,12 @@ static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force) if (force || (es->lock_count == 1)) { if (es->hloc32W) { CHAR *textA = NULL; -#ifndef __REACTOS__ - BOOL _16bit = FALSE; -#endif UINT countA = 0; UINT countW = strlenW(es->text) + 1; +#ifndef __REACTOS__ + STACK16FRAME* stack16 = NULL; + HANDLE16 oldDS = 0; +#endif if(es->hloc32A) { @@ -2552,7 +2618,7 @@ static void EDIT_UpdateScrollInfo(EDITSTATE *es) * * Find the beginning of words. * Note: unlike the specs for a WordBreakProc, this function only - * allows to be called without linebreaks between s[0] upto + * allows to be called without linebreaks between s[0] up to * s[count - 1]. Remember it is only called * internally, so we can decide this for ourselves. * @@ -3006,7 +3072,7 @@ static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy) dx = es->text_width - x_offset_in_pixels; nyoff = max(0, es->y_offset + dy); if (nyoff >= es->line_count - lines_per_page) - nyoff = max(0,es->line_count - lines_per_page); + nyoff = max(0, es->line_count - lines_per_page); dy = (es->y_offset - nyoff) * es->line_height; if (dx || dy) { RECT rc1; @@ -3469,10 +3535,6 @@ static void EDIT_EM_ScrollCaret(EDITSTATE *es) */ static void EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc) { -#ifndef __REACTOS__ - HINSTANCE16 hInstance = GetWindowLongW( es->hwndSelf, GWL_HINSTANCE ); -#endif - if (!(es->style & ES_MULTILINE)) return; @@ -4142,7 +4204,7 @@ static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name) EDIT_SetRectNP(es, &clientRect); if (name && *name) { - EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, TRUE); + EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE); /* if we insert text to the editline, the text scrolls out * of the window, as the caret is placed after the insert * pos normally; thus we reset es->selection... to 0 and @@ -4242,7 +4304,6 @@ static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode) } } - /********************************************************************* * * WM_HSCROLL @@ -4706,7 +4767,7 @@ static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode) if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es)))) return FALSE; - SetWindowLongPtrW( hwnd, 0, (LONG)es ); + SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es ); /* * Note: since the EDITSTATE has not been fully initialized yet, @@ -5304,3 +5365,136 @@ static void EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase) } 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); +} diff --git a/reactos/dll/win32/user32/user32.rbuild b/reactos/dll/win32/user32/user32.rbuild index 7df7fe60edf..1e15f0f2df4 100644 --- a/reactos/dll/win32/user32/user32.rbuild +++ b/reactos/dll/win32/user32/user32.rbuild @@ -14,6 +14,7 @@ gdi32 kernel32 advapi32 + imm32 user32.h diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 126fa5b68f2..f26b67f8e07 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -116,7 +116,7 @@ msvcrt - User32 - reactos/dll/win32/user32/controls/button.c # Synced at 20060621 reactos/dll/win32/user32/controls/combo.c # Synced at 20060617 - reactos/dll/win32/user32/controls/edit.c # Synced at 20051210 + reactos/dll/win32/user32/controls/edit.c # Synced at 20060623 reactos/dll/win32/user32/controls/icontitle.c # Synced at 20060617 reactos/dll/win32/user32/controls/listbox.c # Synced at 20060616 reactos/dll/win32/user32/controls/scrollbar.c # Forked