diff options
| -rw-r--r-- | win32/ScintillaWin.cxx | 932 | 
1 files changed, 521 insertions, 411 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 4ed03c787..f95b89ab7 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -421,6 +421,16 @@ class ScintillaWin :  	void ChangeScrollPos(int barType, Sci::Position pos);  	sptr_t GetTextLength();  	sptr_t GetText(uptr_t wParam, sptr_t lParam); +	Window::Cursor ContextCursor(); +	sptr_t ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	void SizeWindow(); +	sptr_t MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +	sptr_t SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);  public:  	~ScintillaWin() override; @@ -1315,6 +1325,492 @@ sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) {  	}  } +Window::Cursor ScintillaWin::ContextCursor() { +	if (inDragDrop == ddDragging) { +		return Window::cursorUp; +	} else { +		// Display regular (drag) cursor over selection +		POINT pt; +		if (0 != ::GetCursorPos(&pt)) { +			::ScreenToClient(MainHWND(), &pt); +			if (PointInSelMargin(PointFromPOINT(pt))) { +				return GetMarginCursor(PointFromPOINT(pt)); +			} else if (PointInSelection(PointFromPOINT(pt)) && !SelectionEmpty()) { +				return Window::cursorArrow; +			} else if (PointIsHotspot(PointFromPOINT(pt))) { +				return Window::cursorHand; +			} +		} +	} +	return Window::cursorText; +} + +sptr_t ScintillaWin::ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	Point pt = PointFromLParam(lParam); +	POINT rpt = { static_cast<int>(pt.x), static_cast<int>(pt.y) }; +	::ScreenToClient(MainHWND(), &rpt); +	const Point ptClient = PointFromPOINT(rpt); +	if (ShouldDisplayPopup(ptClient)) { +		if ((pt.x == -1) && (pt.y == -1)) { +			// Caused by keyboard so display menu near caret +			pt = PointMainCaret(); +			POINT spt = POINTFromPoint(pt); +			::ClientToScreen(MainHWND(), &spt); +			pt = PointFromPOINT(spt); +		} +		ContextMenu(pt); +		return 0; +	} +	return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +} + +void ScintillaWin::SizeWindow() { +#if defined(USE_D2D) +	if (paintState == notPainting) { +		DropRenderTarget(); +	} else { +		renderTargetValid = false; +	} +#endif +	//Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam)); +	ChangeSize(); +} + +sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { +	case WM_LBUTTONDOWN: { +			// For IME, set the composition string as the result string. +			IMContext imc(MainHWND()); +			if (imc.hIMC) { +				::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); +			} +			// +			//Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam, +			//	KeyboardIsKeyDown(VK_SHIFT), +			//	KeyboardIsKeyDown(VK_CONTROL), +			//	KeyboardIsKeyDown(VK_MENU)); +			::SetFocus(MainHWND()); +			ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(), +						MouseModifiers(wParam)); +		} +		break; + +	case WM_LBUTTONUP: +		ButtonUpWithModifiers(PointFromLParam(lParam), +				      ::GetMessageTime(), MouseModifiers(wParam)); +		break; + +	case WM_RBUTTONDOWN: { +			::SetFocus(MainHWND()); +			const Point pt = PointFromLParam(lParam); +			if (!PointInSelection(pt)) { +				CancelModes(); +				SetEmptySelection(PositionFromLocation(PointFromLParam(lParam))); +			} + +			RightButtonDownWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); +		} +		break; + +	case WM_MOUSEMOVE: { +			const Point pt = PointFromLParam(lParam); + +			// Windows might send WM_MOUSEMOVE even though the mouse has not been moved: +			// http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx +			if (ptMouseLast != pt) { +				SetTrackMouseLeaveEvent(true); +				ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); +			} +		} +		break; + +	case WM_MOUSELEAVE: +		SetTrackMouseLeaveEvent(false); +		MouseLeave(); +		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + +	case WM_MOUSEWHEEL: +		if (!mouseWheelCaptures) { +			// if the mouse wheel is not captured, test if the mouse +			// pointer is over the editor window and if not, don't +			// handle the message but pass it on. +			RECT rc; +			GetWindowRect(MainHWND(), &rc); +			POINT pt; +			pt.x = GET_X_LPARAM(lParam); +			pt.y = GET_Y_LPARAM(lParam); +			if (!PtInRect(&rc, pt)) +				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		} +		// if autocomplete list active then send mousewheel message to it +		if (ac.Active()) { +			HWND hWnd = static_cast<HWND>(ac.lb->GetID()); +			::SendMessage(hWnd, iMessage, wParam, lParam); +			break; +		} + +		// Don't handle datazoom. +		// (A good idea for datazoom would be to "fold" or "unfold" details. +		// i.e. if datazoomed out only class structures are visible, when datazooming in the control +		// structures appear, then eventually the individual statements...) +		if (wParam & MK_SHIFT) { +			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		} +		// Either SCROLL or ZOOM. We handle the wheel steppings calculation +		wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam); +		if (std::abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) { +			Sci::Line linesToScroll = linesPerScroll; +			if (linesPerScroll == WHEEL_PAGESCROLL) +				linesToScroll = LinesOnScreen() - 1; +			if (linesToScroll == 0) { +				linesToScroll = 1; +			} +			linesToScroll *= (wheelDelta / WHEEL_DELTA); +			if (wheelDelta >= 0) +				wheelDelta = wheelDelta % WHEEL_DELTA; +			else +				wheelDelta = -(-wheelDelta % WHEEL_DELTA); + +			if (wParam & MK_CONTROL) { +				// Zoom! We play with the font sizes in the styles. +				// Number of steps/line is ignored, we just care if sizing up or down +				if (linesToScroll < 0) { +					KeyCommand(SCI_ZOOMIN); +				} else { +					KeyCommand(SCI_ZOOMOUT); +				} +			} else { +				// Scroll +				ScrollTo(topLine + linesToScroll); +			} +		} +		return 0; +	} +	return 0; +} + +sptr_t ScintillaWin::KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { + +	case WM_SYSKEYDOWN: +	case WM_KEYDOWN: { +			// Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n", +			// iMessage == WM_KEYDOWN ? 'K' : 'S', +			// (lParam & (1 << 24)) ? 'E' : '-', +			// KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-', +			// KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-', +			// KeyboardIsKeyDown(VK_MENU) ? 'A' : '-', +			// wParam, lParam); +			lastKeyDownConsumed = false; +			const bool altDown = KeyboardIsKeyDown(VK_MENU); +			if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) { +				// Don't interpret these as they may be characters entered by number. +				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +			} +			const int ret = KeyDownWithModifiers(KeyTranslate(static_cast<int>(wParam)), +							     ModifierFlags(KeyboardIsKeyDown(VK_SHIFT), +									     KeyboardIsKeyDown(VK_CONTROL), +									     altDown), +							     &lastKeyDownConsumed); +			if (!ret && !lastKeyDownConsumed) { +				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +			} +			break; +		} + +	case WM_KEYUP: +		//Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam); +		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + +	case WM_CHAR: +		if (((wParam >= 128) || !iscntrl(static_cast<int>(wParam))) || !lastKeyDownConsumed) { +			wchar_t wcs[3] = { static_cast<wchar_t>(wParam), 0 }; +			unsigned int wclen = 1; +			if (IS_HIGH_SURROGATE(wcs[0])) { +				// If this is a high surrogate character, we need a second one +				lastHighSurrogateChar = wcs[0]; +				return 0; +			} else if (IS_LOW_SURROGATE(wcs[0])) { +				wcs[1] = wcs[0]; +				wcs[0] = lastHighSurrogateChar; +				lastHighSurrogateChar = 0; +				wclen = 2; +			} +			AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput); +		} +		return 0; + +	case WM_UNICHAR: +		if (wParam == UNICODE_NOCHAR) { +			return TRUE; +		} else if (lastKeyDownConsumed) { +			return 1; +		} else { +			wchar_t wcs[3] = { 0 }; +			const unsigned int wclen = UTF16FromUTF32Character(static_cast<unsigned int>(wParam), wcs); +			AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput); +			return FALSE; +		} +	} + +	return 0; +} + +sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) { +	switch (iMessage) { +	case WM_KILLFOCUS: { +		HWND wOther = reinterpret_cast<HWND>(wParam); +		HWND wThis = MainHWND(); +		const HWND wCT = static_cast<HWND>(ct.wCallTip.GetID()); +		if (!wParam || +			!(::IsChild(wThis, wOther) || (wOther == wCT))) { +			SetFocusState(false); +			DestroySystemCaret(); +		} +		// Explicitly complete any IME composition +		IMContext imc(MainHWND()); +		if (imc.hIMC) { +			::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); +		} +		break; +	} + +	case WM_SETFOCUS: +		SetFocusState(true); +		DestroySystemCaret(); +		CreateSystemCaret(); +		break; +	} +	return 0; +} + +sptr_t ScintillaWin::IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { + +	case WM_IME_KEYDOWN: { +			if (wParam == VK_HANJA) { +				ToggleHanja(); +			} +			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		} + +	case WM_IME_REQUEST: { +			if (wParam == IMR_RECONVERTSTRING) { +				return ImeOnReconvert(lParam); +			} +			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		} + +	case WM_IME_STARTCOMPOSITION: 	// dbcs +		if (KoreanIME() || imeInteraction == imeInline) { +			return 0; +		} else { +			ImeStartComposition(); +			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		} + +	case WM_IME_ENDCOMPOSITION: 	// dbcs +		ImeEndComposition(); +		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + +	case WM_IME_COMPOSITION: +		if (KoreanIME() || imeInteraction == imeInline) { +			return HandleCompositionInline(wParam, lParam); +		} else { +			return HandleCompositionWindowed(wParam, lParam); +		} + +	case WM_IME_SETCONTEXT: +		if (KoreanIME() || imeInteraction == imeInline) { +			if (wParam) { +				LPARAM NoImeWin = lParam; +				NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW); +				return ::DefWindowProc(MainHWND(), iMessage, wParam, NoImeWin); +			} +		} +		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + +	case WM_IME_NOTIFY: +		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + +	} +	return 0; +} + +sptr_t ScintillaWin::EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { + +	case EM_LINEFROMCHAR: +		if (static_cast<int>(wParam) < 0) { +			wParam = SelectionStart().Position(); +		} +		return pdoc->LineFromPosition(static_cast<int>(wParam)); + +	case EM_EXLINEFROMCHAR: +		return pdoc->LineFromPosition(static_cast<int>(lParam)); + +	case EM_GETSEL: +		if (wParam) { +			*reinterpret_cast<int *>(wParam) = static_cast<int>(SelectionStart().Position()); +		} +		if (lParam) { +			*reinterpret_cast<int *>(lParam) = static_cast<int>(SelectionEnd().Position()); +		} +		return MAKELRESULT(SelectionStart().Position(), SelectionEnd().Position()); + +	case EM_EXGETSEL: { +			if (lParam == 0) { +				return 0; +			} +			Sci_CharacterRange *pCR = reinterpret_cast<Sci_CharacterRange *>(lParam); +			pCR->cpMin = static_cast<Sci_PositionCR>(SelectionStart().Position()); +			pCR->cpMax = static_cast<Sci_PositionCR>(SelectionEnd().Position()); +		} +		break; + +	case EM_SETSEL: { +			Sci::Position nStart = static_cast<Sci::Position>(wParam); +			Sci::Position nEnd = lParam; +			if (nStart == 0 && nEnd == -1) { +				nEnd = pdoc->Length(); +			} +			if (nStart == -1) { +				nStart = nEnd;	// Remove selection +			} +			SetSelection(nEnd, nStart); +			EnsureCaretVisible(); +		} +		break; + +	case EM_EXSETSEL: { +			if (lParam == 0) { +				return 0; +			} +			const Sci_CharacterRange *pCR = reinterpret_cast<const Sci_CharacterRange *>(lParam); +			sel.selType = Selection::selStream; +			if (pCR->cpMin == 0 && pCR->cpMax == -1) { +				SetSelection(pCR->cpMin, pdoc->Length()); +			} else { +				SetSelection(pCR->cpMin, pCR->cpMax); +			} +			EnsureCaretVisible(); +			return pdoc->LineFromPosition(SelectionStart().Position()); +		} +	} +	return 0; +} + +sptr_t ScintillaWin::IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { +	case SC_WIN_IDLE: +		// wParam=dwTickCountInitial, or 0 to initialize.  lParam=bSkipUserInputTest +		if (idler.state) { +			if (lParam || (WAIT_TIMEOUT == MsgWaitForMultipleObjects(0, nullptr, 0, 0, QS_INPUT | QS_HOTKEY))) { +				if (Idle()) { +					// User input was given priority above, but all events do get a turn.  Other +					// messages, notifications, etc. will get interleaved with the idle messages. + +					// However, some things like WM_PAINT are a lower priority, and will not fire +					// when there's a message posted.  So, several times a second, we stop and let +					// the low priority events have a turn (after which the timer will fire again). + +					// Suppress a warning from Code Analysis that the GetTickCount function +					// wraps after 49 days. The WM_TIMER will kick off another SC_WIN_IDLE +					// after the wrap. +#ifdef _MSC_VER +#pragma warning(suppress: 28159) +#endif +					const DWORD dwCurrent = GetTickCount(); +					const DWORD dwStart = wParam ? static_cast<DWORD>(wParam) : dwCurrent; +					const DWORD maxWorkTime = 50; + +					if (dwCurrent >= dwStart && dwCurrent > maxWorkTime &&dwCurrent - maxWorkTime < dwStart) +						PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0); +				} else { +					SetIdle(false); +				} +			} +		} +		break; + +	case SC_WORK_IDLE: +		IdleWork(); +		break; +	} +	return 0; +} + +sptr_t ScintillaWin::SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { +	switch (iMessage) { +	case SCI_GETDIRECTFUNCTION: +		return reinterpret_cast<sptr_t>(DirectFunction); + +	case SCI_GETDIRECTPOINTER: +		return reinterpret_cast<sptr_t>(this); + +	case SCI_GRABFOCUS: +		::SetFocus(MainHWND()); +		break; + +#ifdef INCLUDE_DEPRECATED_FEATURES +	case SCI_SETKEYSUNICODE: +		break; + +	case SCI_GETKEYSUNICODE: +		return true; +#endif + +	case SCI_SETTECHNOLOGY: +		if ((wParam == SC_TECHNOLOGY_DEFAULT) || +			(wParam == SC_TECHNOLOGY_DIRECTWRITERETAIN) || +			(wParam == SC_TECHNOLOGY_DIRECTWRITEDC) || +			(wParam == SC_TECHNOLOGY_DIRECTWRITE)) { +			const int technologyNew = static_cast<int>(wParam); +			if (technology != technologyNew) { +				if (technologyNew > SC_TECHNOLOGY_DEFAULT) { +#if defined(USE_D2D) +					if (!LoadD2D()) +						// Failed to load Direct2D or DirectWrite so no effect +						return 0; +#else +					return 0; +#endif +				} else { +					bidirectional = EditModel::Bidirectional::bidiDisabled; +				} +#if defined(USE_D2D) +				DropRenderTarget(); +#endif +				technology = technologyNew; +				// Invalidate all cached information including layout. +				DropGraphics(true); +				InvalidateStyleRedraw(); +			} +		} +		break; + +	case SCI_SETBIDIRECTIONAL: +		if (technology == SC_TECHNOLOGY_DEFAULT) { +			bidirectional = EditModel::Bidirectional::bidiDisabled; +		} else if (wParam <= SC_BIDIRECTIONAL_R2L) { +			bidirectional = static_cast<EditModel::Bidirectional>(wParam); +		} +		// Invalidate all cached information including layout. +		DropGraphics(true); +		InvalidateStyleRedraw(); +		break; + +	case SCI_TARGETASUTF8: +		return TargetAsUTF8(CharPtrFromSPtr(lParam)); + +	case SCI_ENCODEDFROMUTF8: +		return EncodedFromUTF8(ConstCharPtrFromUPtr(wParam), +			CharPtrFromSPtr(lParam)); + +	} +	return 0; +} +  sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  	try {  		//Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam); @@ -1327,9 +1823,11 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			GetIntelliMouseParameters();  			::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget *>(&dt));  			break; +  		case WM_COMMAND:  			Command(LOWORD(wParam));  			break; +  		case WM_PAINT:  			return WndPaint(); @@ -1350,76 +1848,10 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			HorizontalScrollMessage(wParam);  			break; -		case WM_SIZE: { -#if defined(USE_D2D) -				if (paintState == notPainting) { -					DropRenderTarget(); -				} else { -					renderTargetValid = false; -				} -#endif -				//Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam)); -				ChangeSize(); -			} +		case WM_SIZE: +			SizeWindow();  			break; -		case WM_MOUSEWHEEL: -			if (!mouseWheelCaptures) { -				// if the mouse wheel is not captured, test if the mouse -				// pointer is over the editor window and if not, don't -				// handle the message but pass it on. -				RECT rc; -				GetWindowRect(MainHWND(), &rc); -				POINT pt; -				pt.x = GET_X_LPARAM(lParam); -				pt.y = GET_Y_LPARAM(lParam); -				if (!PtInRect(&rc, pt)) -					return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -			} -			// if autocomplete list active then send mousewheel message to it -			if (ac.Active()) { -				HWND hWnd = static_cast<HWND>(ac.lb->GetID()); -				::SendMessage(hWnd, iMessage, wParam, lParam); -				break; -			} - -			// Don't handle datazoom. -			// (A good idea for datazoom would be to "fold" or "unfold" details. -			// i.e. if datazoomed out only class structures are visible, when datazooming in the control -			// structures appear, then eventually the individual statements...) -			if (wParam & MK_SHIFT) { -				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -			} -			// Either SCROLL or ZOOM. We handle the wheel steppings calculation -			wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam); -			if (std::abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) { -				Sci::Line linesToScroll = linesPerScroll; -				if (linesPerScroll == WHEEL_PAGESCROLL) -					linesToScroll = LinesOnScreen() - 1; -				if (linesToScroll == 0) { -					linesToScroll = 1; -				} -				linesToScroll *= (wheelDelta / WHEEL_DELTA); -				if (wheelDelta >= 0) -					wheelDelta = wheelDelta % WHEEL_DELTA; -				else -					wheelDelta = - (-wheelDelta % WHEEL_DELTA); - -				if (wParam & MK_CONTROL) { -					// Zoom! We play with the font sizes in the styles. -					// Number of steps/line is ignored, we just care if sizing up or down -					if (linesToScroll < 0) { -						KeyCommand(SCI_ZOOMIN); -					} else { -						KeyCommand(SCI_ZOOMOUT); -					} -				} else { -					// Scroll -					ScrollTo(topLine + linesToScroll); -				} -			} -			return 0; -  		case WM_TIMER:  			if (wParam == idleTimerID && idler.state) {  				SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1); @@ -1429,191 +1861,34 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			break;  		case SC_WIN_IDLE: -			// wParam=dwTickCountInitial, or 0 to initialize.  lParam=bSkipUserInputTest -			if (idler.state) { -				if (lParam || (WAIT_TIMEOUT == MsgWaitForMultipleObjects(0, nullptr, 0, 0, QS_INPUT|QS_HOTKEY))) { -					if (Idle()) { -						// User input was given priority above, but all events do get a turn.  Other -						// messages, notifications, etc. will get interleaved with the idle messages. - -						// However, some things like WM_PAINT are a lower priority, and will not fire -						// when there's a message posted.  So, several times a second, we stop and let -						// the low priority events have a turn (after which the timer will fire again). - -						// Suppress a warning from Code Analysis that the GetTickCount function -						// wraps after 49 days. The WM_TIMER will kick off another SC_WIN_IDLE -						// after the wrap. -#ifdef _MSC_VER -#pragma warning(suppress: 28159) -#endif -						const DWORD dwCurrent = GetTickCount(); -						const DWORD dwStart = wParam ? static_cast<DWORD>(wParam) : dwCurrent; -						const DWORD maxWorkTime = 50; - -						if (dwCurrent >= dwStart && dwCurrent > maxWorkTime && dwCurrent - maxWorkTime < dwStart) -							PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0); -					} else { -						SetIdle(false); -					} -				} -			} -			break; -  		case SC_WORK_IDLE: -			IdleWork(); -			break; +			return IdleMessage(iMessage, wParam, lParam);  		case WM_GETMINMAXINFO:  			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -		case WM_LBUTTONDOWN: { -			// For IME, set the composition string as the result string. -			IMContext imc(MainHWND()); -			if (imc.hIMC) { -				::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); -			} -			// -			//Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam, -			//	KeyboardIsKeyDown(VK_SHIFT), -			//	KeyboardIsKeyDown(VK_CONTROL), -			//	KeyboardIsKeyDown(VK_MENU)); -			::SetFocus(MainHWND()); -			ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(), -				MouseModifiers(wParam)); -			} -			break; - -		case WM_MOUSEMOVE: { -				const Point pt = PointFromLParam(lParam); - -				// Windows might send WM_MOUSEMOVE even though the mouse has not been moved: -				// http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx -				if (ptMouseLast != pt) { -					SetTrackMouseLeaveEvent(true); -					ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); -				} -			} -			break; - -		case WM_MOUSELEAVE: -			SetTrackMouseLeaveEvent(false); -			MouseLeave(); -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); - +		case WM_LBUTTONDOWN:  		case WM_LBUTTONUP: -			ButtonUpWithModifiers(PointFromLParam(lParam), -				::GetMessageTime(), MouseModifiers(wParam)); -			break; - -		case WM_RBUTTONDOWN: { -				::SetFocus(MainHWND()); -				const Point pt = PointFromLParam(lParam); -				if (!PointInSelection(pt)) { -					CancelModes(); -					SetEmptySelection(PositionFromLocation(PointFromLParam(lParam))); -				} +		case WM_RBUTTONDOWN: +		case WM_MOUSEMOVE: +		case WM_MOUSELEAVE: +		case WM_MOUSEWHEEL: +			return MouseMessage(iMessage, wParam, lParam); -				RightButtonDownWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); -			} -			break;  		case WM_SETCURSOR:  			if (LOWORD(lParam) == HTCLIENT) { -				if (inDragDrop == ddDragging) { -					DisplayCursor(Window::cursorUp); -				} else { -					// Display regular (drag) cursor over selection -					POINT pt; -					if (0 != ::GetCursorPos(&pt)) { -						::ScreenToClient(MainHWND(), &pt); -						if (PointInSelMargin(PointFromPOINT(pt))) { -							DisplayCursor(GetMarginCursor(PointFromPOINT(pt))); -						} else if (PointInSelection(PointFromPOINT(pt)) && !SelectionEmpty()) { -							DisplayCursor(Window::cursorArrow); -						} else if (PointIsHotspot(PointFromPOINT(pt))) { -							DisplayCursor(Window::cursorHand); -						} else { -							DisplayCursor(Window::cursorText); -						} -					} -				} +				DisplayCursor(ContextCursor());  				return TRUE;  			} else {  				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);  			} -		case WM_CHAR: -			if (((wParam >= 128) || !iscntrl(static_cast<int>(wParam))) || !lastKeyDownConsumed) { -				wchar_t wcs[3] = {static_cast<wchar_t>(wParam), 0}; -				unsigned int wclen = 1; -				if (IS_HIGH_SURROGATE(wcs[0])) { -					// If this is a high surrogate character, we need a second one -					lastHighSurrogateChar = wcs[0]; -					return 0; -				} else if (IS_LOW_SURROGATE(wcs[0])) { -					wcs[1] = wcs[0]; -					wcs[0] = lastHighSurrogateChar; -					lastHighSurrogateChar = 0; -					wclen = 2; -				} -				AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput); -			} -			return 0; - -		case WM_UNICHAR: -			if (wParam == UNICODE_NOCHAR) { -				return TRUE; -			} else if (lastKeyDownConsumed) { -				return 1; -			} else { -				wchar_t wcs[3] = {0}; -				const unsigned int wclen = UTF16FromUTF32Character(static_cast<unsigned int>(wParam), wcs); -				AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput); -				return FALSE; -			} -  		case WM_SYSKEYDOWN: -		case WM_KEYDOWN: { -				// Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n", -				// iMessage == WM_KEYDOWN ? 'K' : 'S', -				// (lParam & (1 << 24)) ? 'E' : '-', -				// KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-', -				// KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-', -				// KeyboardIsKeyDown(VK_MENU) ? 'A' : '-', -				// wParam, lParam); -				lastKeyDownConsumed = false; -				const bool altDown = KeyboardIsKeyDown(VK_MENU); -				if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) { -					// Don't interpret these as they may be characters entered by number. -					return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -				} -				const int ret = KeyDownWithModifiers(KeyTranslate(static_cast<int>(wParam)), -					ModifierFlags(KeyboardIsKeyDown(VK_SHIFT), -					KeyboardIsKeyDown(VK_CONTROL), -					altDown), -					&lastKeyDownConsumed); -				if (!ret && !lastKeyDownConsumed) { -					return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -				} -				break; -			} - -		case WM_IME_KEYDOWN: { -				if (wParam == VK_HANJA) { -					ToggleHanja(); -				} -				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -			} - -		case WM_IME_REQUEST: { -			if (wParam == IMR_RECONVERTSTRING) { -				return ImeOnReconvert(lParam); -			} -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -		} - +		case WM_KEYDOWN:  		case WM_KEYUP: -			//Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam); -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		case WM_CHAR: +		case WM_UNICHAR: +			return KeyMessage(iMessage, wParam, lParam);  		case WM_SETTINGCHANGE:  			//Platform::DebugPrintf("Setting Changed\n"); @@ -1625,71 +1900,18 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  		case WM_GETDLGCODE:  			return DLGC_HASSETSEL | DLGC_WANTALLKEYS; -		case WM_KILLFOCUS: { -				HWND wOther = reinterpret_cast<HWND>(wParam); -				HWND wThis = MainHWND(); -				const HWND wCT = static_cast<HWND>(ct.wCallTip.GetID()); -				if (!wParam || -					!(::IsChild(wThis, wOther) || (wOther == wCT))) { -					SetFocusState(false); -					DestroySystemCaret(); -				} -				// Explicitly complete any IME composition -				IMContext imc(MainHWND()); -				if (imc.hIMC) { -					::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); -				} -			} -			break; - +		case WM_KILLFOCUS:  		case WM_SETFOCUS: -			SetFocusState(true); -			DestroySystemCaret(); -			CreateSystemCaret(); -			break; +			return FocusMessage(iMessage, wParam, lParam);  		case WM_SYSCOLORCHANGE:  			//Platform::DebugPrintf("Setting Changed\n");  			InvalidateStyleData();  			break; -		case WM_IME_STARTCOMPOSITION: 	// dbcs -			if (KoreanIME() || imeInteraction == imeInline) { -				return 0; -			} else { -				ImeStartComposition(); -				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -			} - -		case WM_IME_ENDCOMPOSITION: 	// dbcs -			ImeEndComposition(); -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); +		case WM_CONTEXTMENU: +			return ShowContextMenu(iMessage, wParam, lParam); -		case WM_IME_COMPOSITION: -			if (KoreanIME() || imeInteraction == imeInline) { -				return HandleCompositionInline(wParam, lParam); -			} else { -				return HandleCompositionWindowed(wParam, lParam); -			} - -		case WM_CONTEXTMENU: { -				Point pt = PointFromLParam(lParam); -				POINT rpt = {static_cast<int>(pt.x), static_cast<int>(pt.y)}; -				::ScreenToClient(MainHWND(), &rpt); -				const Point ptClient = PointFromPOINT(rpt); -				if (ShouldDisplayPopup(ptClient)) { -					if ((pt.x == -1) && (pt.y == -1)) { -						// Caused by keyboard so display menu near caret -						pt = PointMainCaret(); -						POINT spt = POINTFromPoint(pt); -						::ClientToScreen(MainHWND(), &spt); -						pt = PointFromPOINT(spt); -					} -					ContextMenu(pt); -					return 0; -				} -			} -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);  		case WM_INPUTLANGCHANGE:  			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);  		case WM_INPUTLANGCHANGEREQUEST: @@ -1702,16 +1924,6 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			capturedMouse = false;  			return 0; -		case WM_IME_SETCONTEXT: -			if (KoreanIME() || imeInteraction == imeInline) { -				if (wParam) { -					LPARAM NoImeWin = lParam; -					NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW); -					return ::DefWindowProc(MainHWND(), iMessage, wParam, NoImeWin); -				} -			} -			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); -  		// These are not handled in Scintilla and its faster to dispatch them here.  		// Also moves time out to here so profile doesn't count lots of empty message calls. @@ -1722,7 +1934,6 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  		case WM_NCPAINT:  		case WM_NCMOUSEMOVE:  		case WM_NCLBUTTONDOWN: -		case WM_IME_NOTIFY:  		case WM_SYSCOMMAND:  		case WM_WINDOWPOSCHANGING:  		case WM_WINDOWPOSCHANGED: @@ -1735,126 +1946,25 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  			return GetText(wParam, lParam);  		case EM_LINEFROMCHAR: -			if (static_cast<int>(wParam) < 0) { -				wParam = SelectionStart().Position(); -			} -			return pdoc->LineFromPosition(static_cast<int>(wParam)); -  		case EM_EXLINEFROMCHAR: -			return pdoc->LineFromPosition(static_cast<int>(lParam)); -  		case EM_GETSEL: -			if (wParam) { -				*reinterpret_cast<int *>(wParam) = static_cast<int>(SelectionStart().Position()); -			} -			if (lParam) { -				*reinterpret_cast<int *>(lParam) = static_cast<int>(SelectionEnd().Position()); -			} -			return MAKELRESULT(SelectionStart().Position(), SelectionEnd().Position()); - -		case EM_EXGETSEL: { -				if (lParam == 0) { -					return 0; -				} -				Sci_CharacterRange *pCR = reinterpret_cast<Sci_CharacterRange *>(lParam); -				pCR->cpMin = static_cast<Sci_PositionCR>(SelectionStart().Position()); -				pCR->cpMax = static_cast<Sci_PositionCR>(SelectionEnd().Position()); -			} -			break; - -		case EM_SETSEL: { -				Sci::Position nStart = static_cast<Sci::Position>(wParam); -				Sci::Position nEnd = lParam; -				if (nStart == 0 && nEnd == -1) { -					nEnd = pdoc->Length(); -				} -				if (nStart == -1) { -					nStart = nEnd;	// Remove selection -				} -				SetSelection(nEnd, nStart); -				EnsureCaretVisible(); -			} -			break; - -		case EM_EXSETSEL: { -				if (lParam == 0) { -					return 0; -				} -				const Sci_CharacterRange *pCR = reinterpret_cast<const Sci_CharacterRange *>(lParam); -				sel.selType = Selection::selStream; -				if (pCR->cpMin == 0 && pCR->cpMax == -1) { -					SetSelection(pCR->cpMin, pdoc->Length()); -				} else { -					SetSelection(pCR->cpMin, pCR->cpMax); -				} -				EnsureCaretVisible(); -				return pdoc->LineFromPosition(SelectionStart().Position()); -			} +		case EM_EXGETSEL: +		case EM_SETSEL: +		case EM_EXSETSEL: +			return EditMessage(iMessage, wParam, lParam);  		case SCI_GETDIRECTFUNCTION: -			return reinterpret_cast<sptr_t>(DirectFunction); -  		case SCI_GETDIRECTPOINTER: -			return reinterpret_cast<sptr_t>(this); -  		case SCI_GRABFOCUS: -			::SetFocus(MainHWND()); -			break; -  #ifdef INCLUDE_DEPRECATED_FEATURES  		case SCI_SETKEYSUNICODE: -			break; -  		case SCI_GETKEYSUNICODE: -			return true;  #endif -  		case SCI_SETTECHNOLOGY: -			if ((wParam == SC_TECHNOLOGY_DEFAULT) || -				(wParam == SC_TECHNOLOGY_DIRECTWRITERETAIN) || -				(wParam == SC_TECHNOLOGY_DIRECTWRITEDC) || -				(wParam == SC_TECHNOLOGY_DIRECTWRITE)) { -				const int technologyNew = static_cast<int>(wParam); -				if (technology != technologyNew) { -					if (technologyNew > SC_TECHNOLOGY_DEFAULT) { -#if defined(USE_D2D) -						if (!LoadD2D()) -							// Failed to load Direct2D or DirectWrite so no effect -							return 0; -#else -						return 0; -#endif -					} else { -						bidirectional = EditModel::Bidirectional::bidiDisabled; -					} -#if defined(USE_D2D) -					DropRenderTarget(); -#endif -					technology = technologyNew; -					// Invalidate all cached information including layout. -					DropGraphics(true); -					InvalidateStyleRedraw(); -				} -			} -			break; -  		case SCI_SETBIDIRECTIONAL: -			if (technology == SC_TECHNOLOGY_DEFAULT) { -				bidirectional = EditModel::Bidirectional::bidiDisabled; -			} else if (wParam <= SC_BIDIRECTIONAL_R2L) { -				bidirectional = static_cast<EditModel::Bidirectional>(wParam); -			} -			// Invalidate all cached information including layout. -			DropGraphics(true); -			InvalidateStyleRedraw(); -			break; -  		case SCI_TARGETASUTF8: -			return TargetAsUTF8(CharPtrFromSPtr(lParam)); -  		case SCI_ENCODEDFROMUTF8: -			return EncodedFromUTF8(ConstCharPtrFromUPtr(wParam), -				CharPtrFromSPtr(lParam)); +			return SciMessage(iMessage, wParam, lParam);  		default:  			return ScintillaBase::WndProc(iMessage, wParam, lParam);  | 
