xref: /MusicPlayer2/scintilla/win32/ScintillaWin.cxx (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file ScintillaWin.cxx
3*8af74909SZhong Yang  ** Windows specific subclass of ScintillaBase.
4*8af74909SZhong Yang  **/
5*8af74909SZhong Yang // Copyright 1998-2003 by Neil Hodgson <[email protected]>
6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
7*8af74909SZhong Yang 
8*8af74909SZhong Yang #include <cstddef>
9*8af74909SZhong Yang #include <cstdlib>
10*8af74909SZhong Yang #include <cassert>
11*8af74909SZhong Yang #include <cstring>
12*8af74909SZhong Yang #include <cstdio>
13*8af74909SZhong Yang #include <cmath>
14*8af74909SZhong Yang #include <climits>
15*8af74909SZhong Yang 
16*8af74909SZhong Yang #include <stdexcept>
17*8af74909SZhong Yang #include <new>
18*8af74909SZhong Yang #include <string>
19*8af74909SZhong Yang #include <string_view>
20*8af74909SZhong Yang #include <vector>
21*8af74909SZhong Yang #include <map>
22*8af74909SZhong Yang #include <algorithm>
23*8af74909SZhong Yang #include <memory>
24*8af74909SZhong Yang #include <chrono>
25*8af74909SZhong Yang #include <mutex>
26*8af74909SZhong Yang 
27*8af74909SZhong Yang // Want to use std::min and std::max so don't want Windows.h version of min and max
28*8af74909SZhong Yang #if !defined(NOMINMAX)
29*8af74909SZhong Yang #define NOMINMAX
30*8af74909SZhong Yang #endif
31*8af74909SZhong Yang #undef _WIN32_WINNT
32*8af74909SZhong Yang #define _WIN32_WINNT 0x0500
33*8af74909SZhong Yang #undef WINVER
34*8af74909SZhong Yang #define WINVER 0x0500
35*8af74909SZhong Yang #include <windows.h>
36*8af74909SZhong Yang #include <commctrl.h>
37*8af74909SZhong Yang #include <richedit.h>
38*8af74909SZhong Yang #include <windowsx.h>
39*8af74909SZhong Yang #include <zmouse.h>
40*8af74909SZhong Yang #include <ole2.h>
41*8af74909SZhong Yang 
42*8af74909SZhong Yang #if !defined(DISABLE_D2D)
43*8af74909SZhong Yang #define USE_D2D 1
44*8af74909SZhong Yang #endif
45*8af74909SZhong Yang 
46*8af74909SZhong Yang #if defined(USE_D2D)
47*8af74909SZhong Yang #include <d2d1.h>
48*8af74909SZhong Yang #include <dwrite.h>
49*8af74909SZhong Yang #endif
50*8af74909SZhong Yang 
51*8af74909SZhong Yang #include "Platform.h"
52*8af74909SZhong Yang 
53*8af74909SZhong Yang #include "ILoader.h"
54*8af74909SZhong Yang #include "ILexer.h"
55*8af74909SZhong Yang #include "Scintilla.h"
56*8af74909SZhong Yang 
57*8af74909SZhong Yang #include "CharacterCategory.h"
58*8af74909SZhong Yang #include "Position.h"
59*8af74909SZhong Yang #include "UniqueString.h"
60*8af74909SZhong Yang #include "SplitVector.h"
61*8af74909SZhong Yang #include "Partitioning.h"
62*8af74909SZhong Yang #include "RunStyles.h"
63*8af74909SZhong Yang #include "ContractionState.h"
64*8af74909SZhong Yang #include "CellBuffer.h"
65*8af74909SZhong Yang #include "CallTip.h"
66*8af74909SZhong Yang #include "KeyMap.h"
67*8af74909SZhong Yang #include "Indicator.h"
68*8af74909SZhong Yang #include "LineMarker.h"
69*8af74909SZhong Yang #include "Style.h"
70*8af74909SZhong Yang #include "ViewStyle.h"
71*8af74909SZhong Yang #include "CharClassify.h"
72*8af74909SZhong Yang #include "Decoration.h"
73*8af74909SZhong Yang #include "CaseFolder.h"
74*8af74909SZhong Yang #include "Document.h"
75*8af74909SZhong Yang #include "CaseConvert.h"
76*8af74909SZhong Yang #include "UniConversion.h"
77*8af74909SZhong Yang #include "Selection.h"
78*8af74909SZhong Yang #include "PositionCache.h"
79*8af74909SZhong Yang #include "EditModel.h"
80*8af74909SZhong Yang #include "MarginView.h"
81*8af74909SZhong Yang #include "EditView.h"
82*8af74909SZhong Yang #include "Editor.h"
83*8af74909SZhong Yang #include "ElapsedPeriod.h"
84*8af74909SZhong Yang 
85*8af74909SZhong Yang #include "AutoComplete.h"
86*8af74909SZhong Yang #include "ScintillaBase.h"
87*8af74909SZhong Yang 
88*8af74909SZhong Yang #include "PlatWin.h"
89*8af74909SZhong Yang #include "HanjaDic.h"
90*8af74909SZhong Yang #include "ScintillaWin.h"
91*8af74909SZhong Yang 
92*8af74909SZhong Yang #ifndef SPI_GETWHEELSCROLLLINES
93*8af74909SZhong Yang #define SPI_GETWHEELSCROLLLINES   104
94*8af74909SZhong Yang #endif
95*8af74909SZhong Yang 
96*8af74909SZhong Yang #ifndef WM_UNICHAR
97*8af74909SZhong Yang #define WM_UNICHAR                      0x0109
98*8af74909SZhong Yang #endif
99*8af74909SZhong Yang 
100*8af74909SZhong Yang #ifndef WM_DPICHANGED
101*8af74909SZhong Yang #define WM_DPICHANGED 0x02E0
102*8af74909SZhong Yang #endif
103*8af74909SZhong Yang #ifndef WM_DPICHANGED_AFTERPARENT
104*8af74909SZhong Yang #define WM_DPICHANGED_AFTERPARENT 0x02E3
105*8af74909SZhong Yang #endif
106*8af74909SZhong Yang 
107*8af74909SZhong Yang #ifndef UNICODE_NOCHAR
108*8af74909SZhong Yang #define UNICODE_NOCHAR                  0xFFFF
109*8af74909SZhong Yang #endif
110*8af74909SZhong Yang 
111*8af74909SZhong Yang #ifndef IS_HIGH_SURROGATE
112*8af74909SZhong Yang #define IS_HIGH_SURROGATE(x)            ((x) >= SURROGATE_LEAD_FIRST && (x) <= SURROGATE_LEAD_LAST)
113*8af74909SZhong Yang #endif
114*8af74909SZhong Yang 
115*8af74909SZhong Yang #ifndef IS_LOW_SURROGATE
116*8af74909SZhong Yang #define IS_LOW_SURROGATE(x)             ((x) >= SURROGATE_TRAIL_FIRST && (x) <= SURROGATE_TRAIL_LAST)
117*8af74909SZhong Yang #endif
118*8af74909SZhong Yang 
119*8af74909SZhong Yang #ifndef MK_ALT
120*8af74909SZhong Yang #define MK_ALT 32
121*8af74909SZhong Yang #endif
122*8af74909SZhong Yang 
123*8af74909SZhong Yang // Two idle messages SC_WIN_IDLE and SC_WORK_IDLE.
124*8af74909SZhong Yang 
125*8af74909SZhong Yang // SC_WIN_IDLE is low priority so should occur after the next WM_PAINT
126*8af74909SZhong Yang // It is for lengthy actions like wrapping and background styling
127*8af74909SZhong Yang constexpr UINT SC_WIN_IDLE = 5001;
128*8af74909SZhong Yang // SC_WORK_IDLE is high priority and should occur before the next WM_PAINT
129*8af74909SZhong Yang // It is for shorter actions like restyling the text just inserted
130*8af74909SZhong Yang // and delivering SCN_UPDATEUI
131*8af74909SZhong Yang constexpr UINT SC_WORK_IDLE = 5002;
132*8af74909SZhong Yang 
133*8af74909SZhong Yang #define SC_INDICATOR_INPUT INDICATOR_IME
134*8af74909SZhong Yang #define SC_INDICATOR_TARGET INDICATOR_IME+1
135*8af74909SZhong Yang #define SC_INDICATOR_CONVERTED INDICATOR_IME+2
136*8af74909SZhong Yang #define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX
137*8af74909SZhong Yang 
138*8af74909SZhong Yang #ifndef SCS_CAP_SETRECONVERTSTRING
139*8af74909SZhong Yang #define SCS_CAP_SETRECONVERTSTRING 0x00000004
140*8af74909SZhong Yang #define SCS_QUERYRECONVERTSTRING 0x00020000
141*8af74909SZhong Yang #define SCS_SETRECONVERTSTRING 0x00010000
142*8af74909SZhong Yang #endif
143*8af74909SZhong Yang 
144*8af74909SZhong Yang typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent,
145*8af74909SZhong Yang 	UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
146*8af74909SZhong Yang 
147*8af74909SZhong Yang // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
148*8af74909SZhong Yang 
149*8af74909SZhong Yang using namespace Scintilla;
150*8af74909SZhong Yang 
151*8af74909SZhong Yang namespace {
152*8af74909SZhong Yang 
153*8af74909SZhong Yang const TCHAR callClassName[] = TEXT("CallTip");
154*8af74909SZhong Yang 
155*8af74909SZhong Yang void SetWindowID(HWND hWnd, int identifier) noexcept {
156*8af74909SZhong Yang 	::SetWindowLongPtr(hWnd, GWLP_ID, identifier);
157*8af74909SZhong Yang }
158*8af74909SZhong Yang 
159*8af74909SZhong Yang Point PointFromLParam(sptr_t lpoint) noexcept {
160*8af74909SZhong Yang 	return Point::FromInts(GET_X_LPARAM(lpoint), GET_Y_LPARAM(lpoint));
161*8af74909SZhong Yang }
162*8af74909SZhong Yang 
163*8af74909SZhong Yang bool KeyboardIsKeyDown(int key) noexcept {
164*8af74909SZhong Yang 	return (::GetKeyState(key) & 0x80000000) != 0;
165*8af74909SZhong Yang }
166*8af74909SZhong Yang 
167*8af74909SZhong Yang constexpr bool KeyboardIsNumericKeypadFunction(uptr_t wParam, sptr_t lParam) {
168*8af74909SZhong Yang 	// Bit 24 is the extended keyboard flag and the numeric keypad is non-extended
169*8af74909SZhong Yang 	if ((lParam & (1 << 24)) != 0) {
170*8af74909SZhong Yang 		// Not from the numeric keypad
171*8af74909SZhong Yang 		return false;
172*8af74909SZhong Yang 	}
173*8af74909SZhong Yang 
174*8af74909SZhong Yang 	switch (wParam) {
175*8af74909SZhong Yang 	case VK_INSERT:	// 0
176*8af74909SZhong Yang 	case VK_END:	// 1
177*8af74909SZhong Yang 	case VK_DOWN:	// 2
178*8af74909SZhong Yang 	case VK_NEXT:	// 3
179*8af74909SZhong Yang 	case VK_LEFT:	// 4
180*8af74909SZhong Yang 	case VK_CLEAR:	// 5
181*8af74909SZhong Yang 	case VK_RIGHT:	// 6
182*8af74909SZhong Yang 	case VK_HOME:	// 7
183*8af74909SZhong Yang 	case VK_UP:		// 8
184*8af74909SZhong Yang 	case VK_PRIOR:	// 9
185*8af74909SZhong Yang 		return true;
186*8af74909SZhong Yang 	default:
187*8af74909SZhong Yang 		return false;
188*8af74909SZhong Yang 	}
189*8af74909SZhong Yang }
190*8af74909SZhong Yang 
191*8af74909SZhong Yang }
192*8af74909SZhong Yang 
193*8af74909SZhong Yang class ScintillaWin; 	// Forward declaration for COM interface subobjects
194*8af74909SZhong Yang 
195*8af74909SZhong Yang typedef void VFunction(void);
196*8af74909SZhong Yang 
197*8af74909SZhong Yang 
198*8af74909SZhong Yang /**
199*8af74909SZhong Yang  */
200*8af74909SZhong Yang class FormatEnumerator {
201*8af74909SZhong Yang public:
202*8af74909SZhong Yang 	VFunction **vtbl;
203*8af74909SZhong Yang 	ULONG ref;
204*8af74909SZhong Yang 	ULONG pos;
205*8af74909SZhong Yang 	std::vector<CLIPFORMAT> formats;
206*8af74909SZhong Yang 	FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_);
207*8af74909SZhong Yang };
208*8af74909SZhong Yang 
209*8af74909SZhong Yang /**
210*8af74909SZhong Yang  */
211*8af74909SZhong Yang class DropSource {
212*8af74909SZhong Yang public:
213*8af74909SZhong Yang 	VFunction **vtbl;
214*8af74909SZhong Yang 	ScintillaWin *sci;
215*8af74909SZhong Yang 	DropSource() noexcept;
216*8af74909SZhong Yang };
217*8af74909SZhong Yang 
218*8af74909SZhong Yang /**
219*8af74909SZhong Yang  */
220*8af74909SZhong Yang class DataObject {
221*8af74909SZhong Yang public:
222*8af74909SZhong Yang 	VFunction **vtbl;
223*8af74909SZhong Yang 	ScintillaWin *sci;
224*8af74909SZhong Yang 	DataObject() noexcept;
225*8af74909SZhong Yang };
226*8af74909SZhong Yang 
227*8af74909SZhong Yang /**
228*8af74909SZhong Yang  */
229*8af74909SZhong Yang class DropTarget {
230*8af74909SZhong Yang public:
231*8af74909SZhong Yang 	VFunction **vtbl;
232*8af74909SZhong Yang 	ScintillaWin *sci;
233*8af74909SZhong Yang 	DropTarget() noexcept;
234*8af74909SZhong Yang };
235*8af74909SZhong Yang 
236*8af74909SZhong Yang namespace {
237*8af74909SZhong Yang 
238*8af74909SZhong Yang class IMContext {
239*8af74909SZhong Yang 	HWND hwnd;
240*8af74909SZhong Yang public:
241*8af74909SZhong Yang 	HIMC hIMC;
242*8af74909SZhong Yang 	IMContext(HWND hwnd_) noexcept :
243*8af74909SZhong Yang 		hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) {
244*8af74909SZhong Yang 	}
245*8af74909SZhong Yang 	// Deleted so IMContext objects can not be copied.
246*8af74909SZhong Yang 	IMContext(const IMContext &) = delete;
247*8af74909SZhong Yang 	IMContext(IMContext &&) = delete;
248*8af74909SZhong Yang 	IMContext &operator=(const IMContext &) = delete;
249*8af74909SZhong Yang 	IMContext &operator=(IMContext &&) = delete;
250*8af74909SZhong Yang 	~IMContext() {
251*8af74909SZhong Yang 		if (hIMC)
252*8af74909SZhong Yang 			::ImmReleaseContext(hwnd, hIMC);
253*8af74909SZhong Yang 	}
254*8af74909SZhong Yang 
255*8af74909SZhong Yang 	unsigned int GetImeCaretPos() const noexcept {
256*8af74909SZhong Yang 		return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0);
257*8af74909SZhong Yang 	}
258*8af74909SZhong Yang 
259*8af74909SZhong Yang 	std::vector<BYTE> GetImeAttributes() {
260*8af74909SZhong Yang 		const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, nullptr, 0);
261*8af74909SZhong Yang 		std::vector<BYTE> attr(attrLen, 0);
262*8af74909SZhong Yang 		::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast<DWORD>(attr.size()));
263*8af74909SZhong Yang 		return attr;
264*8af74909SZhong Yang 	}
265*8af74909SZhong Yang 
266*8af74909SZhong Yang 	std::wstring GetCompositionString(DWORD dwIndex) {
267*8af74909SZhong Yang 		const LONG byteLen = ::ImmGetCompositionStringW(hIMC, dwIndex, nullptr, 0);
268*8af74909SZhong Yang 		std::wstring wcs(byteLen / 2, 0);
269*8af74909SZhong Yang 		::ImmGetCompositionStringW(hIMC, dwIndex, &wcs[0], byteLen);
270*8af74909SZhong Yang 		return wcs;
271*8af74909SZhong Yang 	}
272*8af74909SZhong Yang };
273*8af74909SZhong Yang 
274*8af74909SZhong Yang class GlobalMemory;
275*8af74909SZhong Yang 
276*8af74909SZhong Yang class ReverseArrowCursor {
277*8af74909SZhong Yang 	UINT dpi = USER_DEFAULT_SCREEN_DPI;
278*8af74909SZhong Yang 	HCURSOR cursor {};
279*8af74909SZhong Yang 
280*8af74909SZhong Yang public:
281*8af74909SZhong Yang 	ReverseArrowCursor() noexcept {}
282*8af74909SZhong Yang 	// Deleted so ReverseArrowCursor objects can not be copied.
283*8af74909SZhong Yang 	ReverseArrowCursor(const ReverseArrowCursor &) = delete;
284*8af74909SZhong Yang 	ReverseArrowCursor(ReverseArrowCursor &&) = delete;
285*8af74909SZhong Yang 	ReverseArrowCursor &operator=(const ReverseArrowCursor &) = delete;
286*8af74909SZhong Yang 	ReverseArrowCursor &operator=(ReverseArrowCursor &&) = delete;
287*8af74909SZhong Yang 	~ReverseArrowCursor() {
288*8af74909SZhong Yang 		if (cursor) {
289*8af74909SZhong Yang 			::DestroyCursor(cursor);
290*8af74909SZhong Yang 		}
291*8af74909SZhong Yang 	}
292*8af74909SZhong Yang 
293*8af74909SZhong Yang 	HCURSOR Load(UINT dpi_) noexcept {
294*8af74909SZhong Yang 		if (cursor)	 {
295*8af74909SZhong Yang 			if (dpi == dpi_) {
296*8af74909SZhong Yang 				return cursor;
297*8af74909SZhong Yang 			}
298*8af74909SZhong Yang 			::DestroyCursor(cursor);
299*8af74909SZhong Yang 		}
300*8af74909SZhong Yang 
301*8af74909SZhong Yang 		dpi = dpi_;
302*8af74909SZhong Yang 		cursor = LoadReverseArrowCursor(dpi_);
303*8af74909SZhong Yang 		return cursor ? cursor : ::LoadCursor({}, IDC_ARROW);
304*8af74909SZhong Yang 	}
305*8af74909SZhong Yang };
306*8af74909SZhong Yang 
307*8af74909SZhong Yang }
308*8af74909SZhong Yang 
309*8af74909SZhong Yang /**
310*8af74909SZhong Yang  */
311*8af74909SZhong Yang class ScintillaWin :
312*8af74909SZhong Yang 	public ScintillaBase {
313*8af74909SZhong Yang 
314*8af74909SZhong Yang 	bool lastKeyDownConsumed;
315*8af74909SZhong Yang 	wchar_t lastHighSurrogateChar;
316*8af74909SZhong Yang 
317*8af74909SZhong Yang 	bool capturedMouse;
318*8af74909SZhong Yang 	bool trackedMouseLeave;
319*8af74909SZhong Yang 	SetCoalescableTimerSig SetCoalescableTimerFn;
320*8af74909SZhong Yang 
321*8af74909SZhong Yang 	unsigned int linesPerScroll;	///< Intellimouse support
322*8af74909SZhong Yang 	int wheelDelta; ///< Wheel delta from roll
323*8af74909SZhong Yang 
324*8af74909SZhong Yang 	UINT dpi = USER_DEFAULT_SCREEN_DPI;
325*8af74909SZhong Yang 	ReverseArrowCursor reverseArrowCursor;
326*8af74909SZhong Yang 
327*8af74909SZhong Yang 	HRGN hRgnUpdate;
328*8af74909SZhong Yang 
329*8af74909SZhong Yang 	bool hasOKText;
330*8af74909SZhong Yang 
331*8af74909SZhong Yang 	CLIPFORMAT cfColumnSelect;
332*8af74909SZhong Yang 	CLIPFORMAT cfBorlandIDEBlockType;
333*8af74909SZhong Yang 	CLIPFORMAT cfLineSelect;
334*8af74909SZhong Yang 	CLIPFORMAT cfVSLineTag;
335*8af74909SZhong Yang 
336*8af74909SZhong Yang 	HRESULT hrOle;
337*8af74909SZhong Yang 	DropSource ds;
338*8af74909SZhong Yang 	DataObject dob;
339*8af74909SZhong Yang 	DropTarget dt;
340*8af74909SZhong Yang 
341*8af74909SZhong Yang 	static HINSTANCE hInstance;
342*8af74909SZhong Yang 	static ATOM scintillaClassAtom;
343*8af74909SZhong Yang 	static ATOM callClassAtom;
344*8af74909SZhong Yang 
345*8af74909SZhong Yang #if defined(USE_D2D)
346*8af74909SZhong Yang 	ID2D1RenderTarget *pRenderTarget;
347*8af74909SZhong Yang 	bool renderTargetValid;
348*8af74909SZhong Yang #endif
349*8af74909SZhong Yang 
350*8af74909SZhong Yang 	explicit ScintillaWin(HWND hwnd);
351*8af74909SZhong Yang 	// Deleted so ScintillaWin objects can not be copied.
352*8af74909SZhong Yang 	ScintillaWin(const ScintillaWin &) = delete;
353*8af74909SZhong Yang 	ScintillaWin(ScintillaWin &&) = delete;
354*8af74909SZhong Yang 	ScintillaWin &operator=(const ScintillaWin &) = delete;
355*8af74909SZhong Yang 	ScintillaWin &operator=(ScintillaWin &&) = delete;
356*8af74909SZhong Yang 	// ~ScintillaWin() in public section
357*8af74909SZhong Yang 
358*8af74909SZhong Yang 	void Init();
359*8af74909SZhong Yang 	void Finalise() override;
360*8af74909SZhong Yang #if defined(USE_D2D)
361*8af74909SZhong Yang 	void EnsureRenderTarget(HDC hdc);
362*8af74909SZhong Yang 	void DropRenderTarget();
363*8af74909SZhong Yang #endif
364*8af74909SZhong Yang 	HWND MainHWND() const noexcept;
365*8af74909SZhong Yang 
366*8af74909SZhong Yang 	static sptr_t DirectFunction(
367*8af74909SZhong Yang 		    sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam);
368*8af74909SZhong Yang 	static LRESULT PASCAL SWndProc(
369*8af74909SZhong Yang 		    HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
370*8af74909SZhong Yang 	static LRESULT PASCAL CTWndProc(
371*8af74909SZhong Yang 		    HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
372*8af74909SZhong Yang 
373*8af74909SZhong Yang 	enum : UINT_PTR { invalidTimerID, standardTimerID, idleTimerID, fineTimerStart };
374*8af74909SZhong Yang 
375*8af74909SZhong Yang 	void DisplayCursor(Window::Cursor c) override;
376*8af74909SZhong Yang 	bool DragThreshold(Point ptStart, Point ptNow) override;
377*8af74909SZhong Yang 	void StartDrag() override;
378*8af74909SZhong Yang 	static int MouseModifiers(uptr_t wParam) noexcept;
379*8af74909SZhong Yang 
380*8af74909SZhong Yang 	Sci::Position TargetAsUTF8(char *text) const;
381*8af74909SZhong Yang 	Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
382*8af74909SZhong Yang 
383*8af74909SZhong Yang 	bool PaintDC(HDC hdc);
384*8af74909SZhong Yang 	sptr_t WndPaint();
385*8af74909SZhong Yang 
386*8af74909SZhong Yang 	// DBCS
387*8af74909SZhong Yang 	void ImeStartComposition();
388*8af74909SZhong Yang 	void ImeEndComposition();
389*8af74909SZhong Yang 	LRESULT ImeOnReconvert(LPARAM lParam);
390*8af74909SZhong Yang 	sptr_t HandleCompositionWindowed(uptr_t wParam, sptr_t lParam);
391*8af74909SZhong Yang 	sptr_t HandleCompositionInline(uptr_t wParam, sptr_t lParam);
392*8af74909SZhong Yang 	static bool KoreanIME() noexcept;
393*8af74909SZhong Yang 	void MoveImeCarets(Sci::Position offset);
394*8af74909SZhong Yang 	void DrawImeIndicator(int indicator, Sci::Position len);
395*8af74909SZhong Yang 	void SetCandidateWindowPos();
396*8af74909SZhong Yang 	void SelectionToHangul();
397*8af74909SZhong Yang 	void EscapeHanja();
398*8af74909SZhong Yang 	void ToggleHanja();
399*8af74909SZhong Yang 	void AddWString(std::wstring_view wsv, CharacterSource charSource);
400*8af74909SZhong Yang 
401*8af74909SZhong Yang 	UINT CodePageOfDocument() const noexcept;
402*8af74909SZhong Yang 	bool ValidCodePage(int codePage) const override;
403*8af74909SZhong Yang 	std::string EncodeWString(std::wstring_view wsv);
404*8af74909SZhong Yang 	sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
405*8af74909SZhong Yang 	void IdleWork() override;
406*8af74909SZhong Yang 	void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) override;
407*8af74909SZhong Yang 	bool SetIdle(bool on) override;
408*8af74909SZhong Yang 	UINT_PTR timers[tickDwell+1] {};
409*8af74909SZhong Yang 	bool FineTickerRunning(TickReason reason) override;
410*8af74909SZhong Yang 	void FineTickerStart(TickReason reason, int millis, int tolerance) override;
411*8af74909SZhong Yang 	void FineTickerCancel(TickReason reason) override;
412*8af74909SZhong Yang 	void SetMouseCapture(bool on) override;
413*8af74909SZhong Yang 	bool HaveMouseCapture() override;
414*8af74909SZhong Yang 	void SetTrackMouseLeaveEvent(bool on) noexcept;
415*8af74909SZhong Yang 	bool PaintContains(PRectangle rc) override;
416*8af74909SZhong Yang 	void ScrollText(Sci::Line linesToMove) override;
417*8af74909SZhong Yang 	void NotifyCaretMove() override;
418*8af74909SZhong Yang 	void UpdateSystemCaret() override;
419*8af74909SZhong Yang 	void SetVerticalScrollPos() override;
420*8af74909SZhong Yang 	void SetHorizontalScrollPos() override;
421*8af74909SZhong Yang 	bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override;
422*8af74909SZhong Yang 	void NotifyChange() override;
423*8af74909SZhong Yang 	void NotifyFocus(bool focus) override;
424*8af74909SZhong Yang 	void SetCtrlID(int identifier) override;
425*8af74909SZhong Yang 	int GetCtrlID() override;
426*8af74909SZhong Yang 	void NotifyParent(SCNotification scn) override;
427*8af74909SZhong Yang 	void NotifyDoubleClick(Point pt, int modifiers) override;
428*8af74909SZhong Yang 	CaseFolder *CaseFolderForEncoding() override;
429*8af74909SZhong Yang 	std::string CaseMapString(const std::string &s, int caseMapping) override;
430*8af74909SZhong Yang 	void Copy() override;
431*8af74909SZhong Yang 	bool CanPaste() override;
432*8af74909SZhong Yang 	void Paste() override;
433*8af74909SZhong Yang 	void CreateCallTipWindow(PRectangle rc) override;
434*8af74909SZhong Yang 	void AddToPopUp(LPCTSTR label, int cmd = 0, bool enabled = true) override;
435*8af74909SZhong Yang 	void ClaimSelection() override;
436*8af74909SZhong Yang 
437*8af74909SZhong Yang 	void GetIntelliMouseParameters() noexcept;
438*8af74909SZhong Yang 	void CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText);
439*8af74909SZhong Yang 	void CopyToClipboard(const SelectionText &selectedText) override;
440*8af74909SZhong Yang 	void ScrollMessage(WPARAM wParam);
441*8af74909SZhong Yang 	void HorizontalScrollMessage(WPARAM wParam);
442*8af74909SZhong Yang 	void FullPaint();
443*8af74909SZhong Yang 	void FullPaintDC(HDC hdc);
444*8af74909SZhong Yang 	bool IsCompatibleDC(HDC hOtherDC) noexcept;
445*8af74909SZhong Yang 	DWORD EffectFromState(DWORD grfKeyState) const noexcept;
446*8af74909SZhong Yang 
447*8af74909SZhong Yang 	int SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept;
448*8af74909SZhong Yang 	bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept;
449*8af74909SZhong Yang 	void ChangeScrollPos(int barType, Sci::Position pos);
450*8af74909SZhong Yang 	sptr_t GetTextLength();
451*8af74909SZhong Yang 	sptr_t GetText(uptr_t wParam, sptr_t lParam);
452*8af74909SZhong Yang 	Window::Cursor ContextCursor(Point pt);
453*8af74909SZhong Yang 	sptr_t ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
454*8af74909SZhong Yang 	void SizeWindow();
455*8af74909SZhong Yang 	sptr_t MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
456*8af74909SZhong Yang 	sptr_t KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
457*8af74909SZhong Yang 	sptr_t FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
458*8af74909SZhong Yang 	sptr_t IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
459*8af74909SZhong Yang 	sptr_t EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
460*8af74909SZhong Yang 	sptr_t IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
461*8af74909SZhong Yang 	sptr_t SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
462*8af74909SZhong Yang 
463*8af74909SZhong Yang public:
464*8af74909SZhong Yang 	~ScintillaWin() override;
465*8af74909SZhong Yang 
466*8af74909SZhong Yang 	// Public for benefit of Scintilla_DirectFunction
467*8af74909SZhong Yang 	sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
468*8af74909SZhong Yang 
469*8af74909SZhong Yang 	/// Implement IUnknown
470*8af74909SZhong Yang 	STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv);
471*8af74909SZhong Yang 	STDMETHODIMP_(ULONG)AddRef();
472*8af74909SZhong Yang 	STDMETHODIMP_(ULONG)Release();
473*8af74909SZhong Yang 
474*8af74909SZhong Yang 	/// Implement IDropTarget
475*8af74909SZhong Yang 	STDMETHODIMP DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
476*8af74909SZhong Yang 	                       POINTL pt, PDWORD pdwEffect);
477*8af74909SZhong Yang 	STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect);
478*8af74909SZhong Yang 	STDMETHODIMP DragLeave();
479*8af74909SZhong Yang 	STDMETHODIMP Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
480*8af74909SZhong Yang 	                  POINTL pt, PDWORD pdwEffect);
481*8af74909SZhong Yang 
482*8af74909SZhong Yang 	/// Implement important part of IDataObject
483*8af74909SZhong Yang 	STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM);
484*8af74909SZhong Yang 
485*8af74909SZhong Yang 	static void Prepare() noexcept;
486*8af74909SZhong Yang 	static bool Register(HINSTANCE hInstance_) noexcept;
487*8af74909SZhong Yang 	static bool Unregister() noexcept;
488*8af74909SZhong Yang 
489*8af74909SZhong Yang 	friend class DropSource;
490*8af74909SZhong Yang 	friend class DataObject;
491*8af74909SZhong Yang 	friend class DropTarget;
492*8af74909SZhong Yang 	bool DragIsRectangularOK(CLIPFORMAT fmt) const noexcept {
493*8af74909SZhong Yang 		return drag.rectangular && (fmt == cfColumnSelect);
494*8af74909SZhong Yang 	}
495*8af74909SZhong Yang 
496*8af74909SZhong Yang private:
497*8af74909SZhong Yang 	// For use in creating a system caret
498*8af74909SZhong Yang 	bool HasCaretSizeChanged() const noexcept;
499*8af74909SZhong Yang 	BOOL CreateSystemCaret();
500*8af74909SZhong Yang 	BOOL DestroySystemCaret() noexcept;
501*8af74909SZhong Yang 	HBITMAP sysCaretBitmap;
502*8af74909SZhong Yang 	int sysCaretWidth;
503*8af74909SZhong Yang 	int sysCaretHeight;
504*8af74909SZhong Yang 	bool styleIdleInQueue;
505*8af74909SZhong Yang };
506*8af74909SZhong Yang 
507*8af74909SZhong Yang HINSTANCE ScintillaWin::hInstance {};
508*8af74909SZhong Yang ATOM ScintillaWin::scintillaClassAtom = 0;
509*8af74909SZhong Yang ATOM ScintillaWin::callClassAtom = 0;
510*8af74909SZhong Yang 
511*8af74909SZhong Yang ScintillaWin::ScintillaWin(HWND hwnd) {
512*8af74909SZhong Yang 
513*8af74909SZhong Yang 	lastKeyDownConsumed = false;
514*8af74909SZhong Yang 	lastHighSurrogateChar = 0;
515*8af74909SZhong Yang 
516*8af74909SZhong Yang 	capturedMouse = false;
517*8af74909SZhong Yang 	trackedMouseLeave = false;
518*8af74909SZhong Yang 	SetCoalescableTimerFn = nullptr;
519*8af74909SZhong Yang 
520*8af74909SZhong Yang 	linesPerScroll = 0;
521*8af74909SZhong Yang 	wheelDelta = 0;   // Wheel delta from roll
522*8af74909SZhong Yang 
523*8af74909SZhong Yang 	dpi = DpiForWindow(hwnd);
524*8af74909SZhong Yang 
525*8af74909SZhong Yang 	hRgnUpdate = {};
526*8af74909SZhong Yang 
527*8af74909SZhong Yang 	hasOKText = false;
528*8af74909SZhong Yang 
529*8af74909SZhong Yang 	// There does not seem to be a real standard for indicating that the clipboard
530*8af74909SZhong Yang 	// contains a rectangular selection, so copy Developer Studio and Borland Delphi.
531*8af74909SZhong Yang 	cfColumnSelect = static_cast<CLIPFORMAT>(
532*8af74909SZhong Yang 		::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
533*8af74909SZhong Yang 	cfBorlandIDEBlockType = static_cast<CLIPFORMAT>(
534*8af74909SZhong Yang 		::RegisterClipboardFormat(TEXT("Borland IDE Block Type")));
535*8af74909SZhong Yang 
536*8af74909SZhong Yang 	// Likewise for line-copy (copies a full line when no text is selected)
537*8af74909SZhong Yang 	cfLineSelect = static_cast<CLIPFORMAT>(
538*8af74909SZhong Yang 		::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
539*8af74909SZhong Yang 	cfVSLineTag = static_cast<CLIPFORMAT>(
540*8af74909SZhong Yang 		::RegisterClipboardFormat(TEXT("VisualStudioEditorOperationsLineCutCopyClipboardTag")));
541*8af74909SZhong Yang 	hrOle = E_FAIL;
542*8af74909SZhong Yang 
543*8af74909SZhong Yang 	wMain = hwnd;
544*8af74909SZhong Yang 
545*8af74909SZhong Yang 	dob.sci = this;
546*8af74909SZhong Yang 	ds.sci = this;
547*8af74909SZhong Yang 	dt.sci = this;
548*8af74909SZhong Yang 
549*8af74909SZhong Yang 	sysCaretBitmap = {};
550*8af74909SZhong Yang 	sysCaretWidth = 0;
551*8af74909SZhong Yang 	sysCaretHeight = 0;
552*8af74909SZhong Yang 
553*8af74909SZhong Yang 	styleIdleInQueue = false;
554*8af74909SZhong Yang 
555*8af74909SZhong Yang #if defined(USE_D2D)
556*8af74909SZhong Yang 	pRenderTarget = nullptr;
557*8af74909SZhong Yang 	renderTargetValid = true;
558*8af74909SZhong Yang #endif
559*8af74909SZhong Yang 
560*8af74909SZhong Yang 	caret.period = ::GetCaretBlinkTime();
561*8af74909SZhong Yang 	if (caret.period < 0)
562*8af74909SZhong Yang 		caret.period = 0;
563*8af74909SZhong Yang 
564*8af74909SZhong Yang 	Init();
565*8af74909SZhong Yang }
566*8af74909SZhong Yang 
567*8af74909SZhong Yang ScintillaWin::~ScintillaWin() {}
568*8af74909SZhong Yang 
569*8af74909SZhong Yang void ScintillaWin::Init() {
570*8af74909SZhong Yang 	// Initialize COM.  If the app has already done this it will have
571*8af74909SZhong Yang 	// no effect.  If the app hasn't, we really shouldn't ask them to call
572*8af74909SZhong Yang 	// it just so this internal feature works.
573*8af74909SZhong Yang 	hrOle = ::OleInitialize(nullptr);
574*8af74909SZhong Yang 
575*8af74909SZhong Yang 	// Find SetCoalescableTimer which is only available from Windows 8+
576*8af74909SZhong Yang 	HMODULE user32 = ::GetModuleHandleW(L"user32.dll");
577*8af74909SZhong Yang 	SetCoalescableTimerFn = DLLFunction<SetCoalescableTimerSig>(user32, "SetCoalescableTimer");
578*8af74909SZhong Yang 
579*8af74909SZhong Yang 	vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(INDIC_HIDDEN, ColourDesired(0, 0, 0xff));
580*8af74909SZhong Yang 	vs.indicators[SC_INDICATOR_INPUT] = Indicator(INDIC_DOTS, ColourDesired(0, 0, 0xff));
581*8af74909SZhong Yang 	vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(INDIC_COMPOSITIONTHICK, ColourDesired(0, 0, 0xff));
582*8af74909SZhong Yang 	vs.indicators[SC_INDICATOR_TARGET] = Indicator(INDIC_STRAIGHTBOX, ColourDesired(0, 0, 0xff));
583*8af74909SZhong Yang }
584*8af74909SZhong Yang 
585*8af74909SZhong Yang void ScintillaWin::Finalise() {
586*8af74909SZhong Yang 	ScintillaBase::Finalise();
587*8af74909SZhong Yang 	for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
588*8af74909SZhong Yang 		FineTickerCancel(tr);
589*8af74909SZhong Yang 	}
590*8af74909SZhong Yang 	SetIdle(false);
591*8af74909SZhong Yang #if defined(USE_D2D)
592*8af74909SZhong Yang 	DropRenderTarget();
593*8af74909SZhong Yang #endif
594*8af74909SZhong Yang 	::RevokeDragDrop(MainHWND());
595*8af74909SZhong Yang 	if (SUCCEEDED(hrOle)) {
596*8af74909SZhong Yang 		::OleUninitialize();
597*8af74909SZhong Yang 	}
598*8af74909SZhong Yang }
599*8af74909SZhong Yang 
600*8af74909SZhong Yang #if defined(USE_D2D)
601*8af74909SZhong Yang 
602*8af74909SZhong Yang void ScintillaWin::EnsureRenderTarget(HDC hdc) {
603*8af74909SZhong Yang 	if (!renderTargetValid) {
604*8af74909SZhong Yang 		DropRenderTarget();
605*8af74909SZhong Yang 		renderTargetValid = true;
606*8af74909SZhong Yang 	}
607*8af74909SZhong Yang 	if (pD2DFactory && !pRenderTarget) {
608*8af74909SZhong Yang 		HWND hw = MainHWND();
609*8af74909SZhong Yang 		RECT rc;
610*8af74909SZhong Yang 		GetClientRect(hw, &rc);
611*8af74909SZhong Yang 
612*8af74909SZhong Yang 		const D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
613*8af74909SZhong Yang 
614*8af74909SZhong Yang 		// Create a Direct2D render target.
615*8af74909SZhong Yang #if 1
616*8af74909SZhong Yang 		D2D1_RENDER_TARGET_PROPERTIES drtp;
617*8af74909SZhong Yang 		drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
618*8af74909SZhong Yang 		drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
619*8af74909SZhong Yang 		drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
620*8af74909SZhong Yang 		drtp.dpiX = 96.0;
621*8af74909SZhong Yang 		drtp.dpiY = 96.0;
622*8af74909SZhong Yang 		drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
623*8af74909SZhong Yang 		drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
624*8af74909SZhong Yang 
625*8af74909SZhong Yang 		if (technology == SC_TECHNOLOGY_DIRECTWRITEDC) {
626*8af74909SZhong Yang 			// Explicit pixel format needed.
627*8af74909SZhong Yang 			drtp.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
628*8af74909SZhong Yang 				D2D1_ALPHA_MODE_IGNORE);
629*8af74909SZhong Yang 
630*8af74909SZhong Yang 			ID2D1DCRenderTarget *pDCRT = nullptr;
631*8af74909SZhong Yang 			const HRESULT hr = pD2DFactory->CreateDCRenderTarget(&drtp, &pDCRT);
632*8af74909SZhong Yang 			if (SUCCEEDED(hr)) {
633*8af74909SZhong Yang 				pRenderTarget = pDCRT;
634*8af74909SZhong Yang 			} else {
635*8af74909SZhong Yang 				Platform::DebugPrintf("Failed CreateDCRenderTarget 0x%lx\n", hr);
636*8af74909SZhong Yang 				pRenderTarget = nullptr;
637*8af74909SZhong Yang 			}
638*8af74909SZhong Yang 
639*8af74909SZhong Yang 		} else {
640*8af74909SZhong Yang 			D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp;
641*8af74909SZhong Yang 			dhrtp.hwnd = hw;
642*8af74909SZhong Yang 			dhrtp.pixelSize = size;
643*8af74909SZhong Yang 			dhrtp.presentOptions = (technology == SC_TECHNOLOGY_DIRECTWRITERETAIN) ?
644*8af74909SZhong Yang 			D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE;
645*8af74909SZhong Yang 
646*8af74909SZhong Yang 			ID2D1HwndRenderTarget *pHwndRenderTarget = nullptr;
647*8af74909SZhong Yang 			const HRESULT hr = pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pHwndRenderTarget);
648*8af74909SZhong Yang 			if (SUCCEEDED(hr)) {
649*8af74909SZhong Yang 				pRenderTarget = pHwndRenderTarget;
650*8af74909SZhong Yang 			} else {
651*8af74909SZhong Yang 				Platform::DebugPrintf("Failed CreateHwndRenderTarget 0x%lx\n", hr);
652*8af74909SZhong Yang 				pRenderTarget = nullptr;
653*8af74909SZhong Yang 			}
654*8af74909SZhong Yang 		}
655*8af74909SZhong Yang #else
656*8af74909SZhong Yang 		pD2DFactory->CreateHwndRenderTarget(
657*8af74909SZhong Yang 			D2D1::RenderTargetProperties(
658*8af74909SZhong Yang 				D2D1_RENDER_TARGET_TYPE_DEFAULT ,
659*8af74909SZhong Yang 				D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
660*8af74909SZhong Yang 				96.0f, 96.0f, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT),
661*8af74909SZhong Yang 			D2D1::HwndRenderTargetProperties(hw, size),
662*8af74909SZhong Yang 			&pRenderTarget);
663*8af74909SZhong Yang #endif
664*8af74909SZhong Yang 		// Pixmaps were created to be compatible with previous render target so
665*8af74909SZhong Yang 		// need to be recreated.
666*8af74909SZhong Yang 		DropGraphics(false);
667*8af74909SZhong Yang 	}
668*8af74909SZhong Yang 
669*8af74909SZhong Yang 	if ((technology == SC_TECHNOLOGY_DIRECTWRITEDC) && pRenderTarget) {
670*8af74909SZhong Yang 		RECT rcWindow;
671*8af74909SZhong Yang 		GetClientRect(MainHWND(), &rcWindow);
672*8af74909SZhong Yang 		const HRESULT hr = static_cast<ID2D1DCRenderTarget*>(pRenderTarget)->BindDC(hdc, &rcWindow);
673*8af74909SZhong Yang 		if (FAILED(hr)) {
674*8af74909SZhong Yang 			Platform::DebugPrintf("BindDC failed 0x%lx\n", hr);
675*8af74909SZhong Yang 			DropRenderTarget();
676*8af74909SZhong Yang 		}
677*8af74909SZhong Yang 	}
678*8af74909SZhong Yang }
679*8af74909SZhong Yang 
680*8af74909SZhong Yang void ScintillaWin::DropRenderTarget() {
681*8af74909SZhong Yang 	ReleaseUnknown(pRenderTarget);
682*8af74909SZhong Yang }
683*8af74909SZhong Yang 
684*8af74909SZhong Yang #endif
685*8af74909SZhong Yang 
686*8af74909SZhong Yang HWND ScintillaWin::MainHWND() const noexcept {
687*8af74909SZhong Yang 	return HwndFromWindow(wMain);
688*8af74909SZhong Yang }
689*8af74909SZhong Yang 
690*8af74909SZhong Yang void ScintillaWin::DisplayCursor(Window::Cursor c) {
691*8af74909SZhong Yang 	if (cursorMode != SC_CURSORNORMAL) {
692*8af74909SZhong Yang 		c = static_cast<Window::Cursor>(cursorMode);
693*8af74909SZhong Yang 	}
694*8af74909SZhong Yang 	if (c == Window::cursorReverseArrow) {
695*8af74909SZhong Yang 		::SetCursor(reverseArrowCursor.Load(dpi));
696*8af74909SZhong Yang 	} else {
697*8af74909SZhong Yang 		wMain.SetCursor(c);
698*8af74909SZhong Yang 	}
699*8af74909SZhong Yang }
700*8af74909SZhong Yang 
701*8af74909SZhong Yang bool ScintillaWin::DragThreshold(Point ptStart, Point ptNow) {
702*8af74909SZhong Yang 	const Point ptDifference = ptStart - ptNow;
703*8af74909SZhong Yang 	const XYPOSITION xMove = std::trunc(std::abs(ptDifference.x));
704*8af74909SZhong Yang 	const XYPOSITION yMove = std::trunc(std::abs(ptDifference.y));
705*8af74909SZhong Yang 	return (xMove > SystemMetricsForDpi(SM_CXDRAG, dpi)) ||
706*8af74909SZhong Yang 		(yMove > SystemMetricsForDpi(SM_CYDRAG, dpi));
707*8af74909SZhong Yang }
708*8af74909SZhong Yang 
709*8af74909SZhong Yang void ScintillaWin::StartDrag() {
710*8af74909SZhong Yang 	inDragDrop = ddDragging;
711*8af74909SZhong Yang 	DWORD dwEffect = 0;
712*8af74909SZhong Yang 	dropWentOutside = true;
713*8af74909SZhong Yang 	IDataObject *pDataObject = reinterpret_cast<IDataObject *>(&dob);
714*8af74909SZhong Yang 	IDropSource *pDropSource = reinterpret_cast<IDropSource *>(&ds);
715*8af74909SZhong Yang 	//Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
716*8af74909SZhong Yang 	const HRESULT hr = ::DoDragDrop(
717*8af74909SZhong Yang 	                 pDataObject,
718*8af74909SZhong Yang 	                 pDropSource,
719*8af74909SZhong Yang 	                 DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
720*8af74909SZhong Yang 	//Platform::DebugPrintf("DoDragDrop = %x\n", hr);
721*8af74909SZhong Yang 	if (SUCCEEDED(hr)) {
722*8af74909SZhong Yang 		if ((hr == DRAGDROP_S_DROP) && (dwEffect == DROPEFFECT_MOVE) && dropWentOutside) {
723*8af74909SZhong Yang 			// Remove dragged out text
724*8af74909SZhong Yang 			ClearSelection();
725*8af74909SZhong Yang 		}
726*8af74909SZhong Yang 	}
727*8af74909SZhong Yang 	inDragDrop = ddNone;
728*8af74909SZhong Yang 	SetDragPosition(SelectionPosition(Sci::invalidPosition));
729*8af74909SZhong Yang }
730*8af74909SZhong Yang 
731*8af74909SZhong Yang int ScintillaWin::MouseModifiers(uptr_t wParam) noexcept {
732*8af74909SZhong Yang 	return ModifierFlags((wParam & MK_SHIFT) != 0,
733*8af74909SZhong Yang 		(wParam & MK_CONTROL) != 0,
734*8af74909SZhong Yang 		KeyboardIsKeyDown(VK_MENU));
735*8af74909SZhong Yang }
736*8af74909SZhong Yang 
737*8af74909SZhong Yang namespace {
738*8af74909SZhong Yang 
739*8af74909SZhong Yang int InputCodePage() noexcept {
740*8af74909SZhong Yang 	HKL inputLocale = ::GetKeyboardLayout(0);
741*8af74909SZhong Yang 	const LANGID inputLang = LOWORD(inputLocale);
742*8af74909SZhong Yang 	char sCodePage[10];
743*8af74909SZhong Yang 	const int res = ::GetLocaleInfoA(MAKELCID(inputLang, SORT_DEFAULT),
744*8af74909SZhong Yang 	  LOCALE_IDEFAULTANSICODEPAGE, sCodePage, sizeof(sCodePage));
745*8af74909SZhong Yang 	if (!res)
746*8af74909SZhong Yang 		return 0;
747*8af74909SZhong Yang 	return atoi(sCodePage);
748*8af74909SZhong Yang }
749*8af74909SZhong Yang 
750*8af74909SZhong Yang /** Map the key codes to their equivalent SCK_ form. */
751*8af74909SZhong Yang int KeyTranslate(int keyIn) noexcept {
752*8af74909SZhong Yang //PLATFORM_ASSERT(!keyIn);
753*8af74909SZhong Yang 	switch (keyIn) {
754*8af74909SZhong Yang 		case VK_DOWN:		return SCK_DOWN;
755*8af74909SZhong Yang 		case VK_UP:		return SCK_UP;
756*8af74909SZhong Yang 		case VK_LEFT:		return SCK_LEFT;
757*8af74909SZhong Yang 		case VK_RIGHT:		return SCK_RIGHT;
758*8af74909SZhong Yang 		case VK_HOME:		return SCK_HOME;
759*8af74909SZhong Yang 		case VK_END:		return SCK_END;
760*8af74909SZhong Yang 		case VK_PRIOR:		return SCK_PRIOR;
761*8af74909SZhong Yang 		case VK_NEXT:		return SCK_NEXT;
762*8af74909SZhong Yang 		case VK_DELETE:	return SCK_DELETE;
763*8af74909SZhong Yang 		case VK_INSERT:		return SCK_INSERT;
764*8af74909SZhong Yang 		case VK_ESCAPE:	return SCK_ESCAPE;
765*8af74909SZhong Yang 		case VK_BACK:		return SCK_BACK;
766*8af74909SZhong Yang 		case VK_TAB:		return SCK_TAB;
767*8af74909SZhong Yang 		case VK_RETURN:	return SCK_RETURN;
768*8af74909SZhong Yang 		case VK_ADD:		return SCK_ADD;
769*8af74909SZhong Yang 		case VK_SUBTRACT:	return SCK_SUBTRACT;
770*8af74909SZhong Yang 		case VK_DIVIDE:		return SCK_DIVIDE;
771*8af74909SZhong Yang 		case VK_LWIN:		return SCK_WIN;
772*8af74909SZhong Yang 		case VK_RWIN:		return SCK_RWIN;
773*8af74909SZhong Yang 		case VK_APPS:		return SCK_MENU;
774*8af74909SZhong Yang 		case VK_OEM_2:		return '/';
775*8af74909SZhong Yang 		case VK_OEM_3:		return '`';
776*8af74909SZhong Yang 		case VK_OEM_4:		return '[';
777*8af74909SZhong Yang 		case VK_OEM_5:		return '\\';
778*8af74909SZhong Yang 		case VK_OEM_6:		return ']';
779*8af74909SZhong Yang 		default:			return keyIn;
780*8af74909SZhong Yang 	}
781*8af74909SZhong Yang }
782*8af74909SZhong Yang 
783*8af74909SZhong Yang bool BoundsContains(PRectangle rcBounds, HRGN hRgnBounds, PRectangle rcCheck) noexcept {
784*8af74909SZhong Yang 	bool contains = true;
785*8af74909SZhong Yang 	if (!rcCheck.Empty()) {
786*8af74909SZhong Yang 		if (!rcBounds.Contains(rcCheck)) {
787*8af74909SZhong Yang 			contains = false;
788*8af74909SZhong Yang 		} else if (hRgnBounds) {
789*8af74909SZhong Yang 			// In bounding rectangle so check more accurately using region
790*8af74909SZhong Yang 			const RECT rcw = RectFromPRectangle(rcCheck);
791*8af74909SZhong Yang 			HRGN hRgnCheck = ::CreateRectRgnIndirect(&rcw);
792*8af74909SZhong Yang 			if (hRgnCheck) {
793*8af74909SZhong Yang 				HRGN hRgnDifference = ::CreateRectRgn(0, 0, 0, 0);
794*8af74909SZhong Yang 				if (hRgnDifference) {
795*8af74909SZhong Yang 					const int combination = ::CombineRgn(hRgnDifference, hRgnCheck, hRgnBounds, RGN_DIFF);
796*8af74909SZhong Yang 					if (combination != NULLREGION) {
797*8af74909SZhong Yang 						contains = false;
798*8af74909SZhong Yang 					}
799*8af74909SZhong Yang 					::DeleteRgn(hRgnDifference);
800*8af74909SZhong Yang 				}
801*8af74909SZhong Yang 				::DeleteRgn(hRgnCheck);
802*8af74909SZhong Yang 			}
803*8af74909SZhong Yang 		}
804*8af74909SZhong Yang 	}
805*8af74909SZhong Yang 	return contains;
806*8af74909SZhong Yang }
807*8af74909SZhong Yang 
808*8af74909SZhong Yang // Simplify calling WideCharToMultiByte and MultiByteToWideChar by providing default parameters and using string view.
809*8af74909SZhong Yang 
810*8af74909SZhong Yang int MultiByteFromWideChar(UINT codePage, std::wstring_view wsv, LPSTR lpMultiByteStr, ptrdiff_t cbMultiByte) noexcept {
811*8af74909SZhong Yang 	return ::WideCharToMultiByte(codePage, 0, wsv.data(), static_cast<int>(wsv.length()), lpMultiByteStr, static_cast<int>(cbMultiByte), nullptr, nullptr);
812*8af74909SZhong Yang }
813*8af74909SZhong Yang 
814*8af74909SZhong Yang int MultiByteLenFromWideChar(UINT codePage, std::wstring_view wsv) noexcept {
815*8af74909SZhong Yang 	return MultiByteFromWideChar(codePage, wsv, nullptr, 0);
816*8af74909SZhong Yang }
817*8af74909SZhong Yang 
818*8af74909SZhong Yang int WideCharFromMultiByte(UINT codePage, std::string_view sv, LPWSTR lpWideCharStr, ptrdiff_t cchWideChar) noexcept {
819*8af74909SZhong Yang 	return ::MultiByteToWideChar(codePage, 0, sv.data(), static_cast<int>(sv.length()), lpWideCharStr, static_cast<int>(cchWideChar));
820*8af74909SZhong Yang }
821*8af74909SZhong Yang 
822*8af74909SZhong Yang int WideCharLenFromMultiByte(UINT codePage, std::string_view sv) noexcept {
823*8af74909SZhong Yang 	return WideCharFromMultiByte(codePage, sv, nullptr, 0);
824*8af74909SZhong Yang }
825*8af74909SZhong Yang 
826*8af74909SZhong Yang std::string StringEncode(std::wstring_view wsv, int codePage) {
827*8af74909SZhong Yang 	const int cchMulti = wsv.length() ? MultiByteLenFromWideChar(codePage, wsv) : 0;
828*8af74909SZhong Yang 	std::string sMulti(cchMulti, 0);
829*8af74909SZhong Yang 	if (cchMulti) {
830*8af74909SZhong Yang 		MultiByteFromWideChar(codePage, wsv, sMulti.data(), cchMulti);
831*8af74909SZhong Yang 	}
832*8af74909SZhong Yang 	return sMulti;
833*8af74909SZhong Yang }
834*8af74909SZhong Yang 
835*8af74909SZhong Yang std::wstring StringDecode(std::string_view sv, int codePage) {
836*8af74909SZhong Yang 	const int cchWide = sv.length() ? WideCharLenFromMultiByte(codePage, sv) : 0;
837*8af74909SZhong Yang 	std::wstring sWide(cchWide, 0);
838*8af74909SZhong Yang 	if (cchWide) {
839*8af74909SZhong Yang 		WideCharFromMultiByte(codePage, sv, sWide.data(), cchWide);
840*8af74909SZhong Yang 	}
841*8af74909SZhong Yang 	return sWide;
842*8af74909SZhong Yang }
843*8af74909SZhong Yang 
844*8af74909SZhong Yang std::wstring StringMapCase(std::wstring_view wsv, DWORD mapFlags) {
845*8af74909SZhong Yang 	const int charsConverted = ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags,
846*8af74909SZhong Yang 		wsv.data(), static_cast<int>(wsv.length()), nullptr, 0);
847*8af74909SZhong Yang 	std::wstring wsConverted(charsConverted, 0);
848*8af74909SZhong Yang 	if (charsConverted) {
849*8af74909SZhong Yang 		::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags,
850*8af74909SZhong Yang 			wsv.data(), static_cast<int>(wsv.length()), wsConverted.data(), charsConverted);
851*8af74909SZhong Yang 	}
852*8af74909SZhong Yang 	return wsConverted;
853*8af74909SZhong Yang }
854*8af74909SZhong Yang 
855*8af74909SZhong Yang }
856*8af74909SZhong Yang 
857*8af74909SZhong Yang // Returns the target converted to UTF8.
858*8af74909SZhong Yang // Return the length in bytes.
859*8af74909SZhong Yang Sci::Position ScintillaWin::TargetAsUTF8(char *text) const {
860*8af74909SZhong Yang 	const Sci::Position targetLength = targetRange.Length();
861*8af74909SZhong Yang 	if (IsUnicodeMode()) {
862*8af74909SZhong Yang 		if (text) {
863*8af74909SZhong Yang 			pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
864*8af74909SZhong Yang 		}
865*8af74909SZhong Yang 	} else {
866*8af74909SZhong Yang 		// Need to convert
867*8af74909SZhong Yang 		const std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position());
868*8af74909SZhong Yang 		const std::wstring characters = StringDecode(s, CodePageOfDocument());
869*8af74909SZhong Yang 		const int utf8Len = MultiByteLenFromWideChar(CP_UTF8, characters);
870*8af74909SZhong Yang 		if (text) {
871*8af74909SZhong Yang 			MultiByteFromWideChar(CP_UTF8, characters, text, utf8Len);
872*8af74909SZhong Yang 			text[utf8Len] = '\0';
873*8af74909SZhong Yang 		}
874*8af74909SZhong Yang 		return utf8Len;
875*8af74909SZhong Yang 	}
876*8af74909SZhong Yang 	return targetLength;
877*8af74909SZhong Yang }
878*8af74909SZhong Yang 
879*8af74909SZhong Yang // Translates a nul terminated UTF8 string into the document encoding.
880*8af74909SZhong Yang // Return the length of the result in bytes.
881*8af74909SZhong Yang Sci::Position ScintillaWin::EncodedFromUTF8(const char *utf8, char *encoded) const {
882*8af74909SZhong Yang 	const Sci::Position inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
883*8af74909SZhong Yang 	if (IsUnicodeMode()) {
884*8af74909SZhong Yang 		if (encoded) {
885*8af74909SZhong Yang 			memcpy(encoded, utf8, inputLength);
886*8af74909SZhong Yang 		}
887*8af74909SZhong Yang 		return inputLength;
888*8af74909SZhong Yang 	} else {
889*8af74909SZhong Yang 		// Need to convert
890*8af74909SZhong Yang 		const std::string_view utf8Input(utf8, inputLength);
891*8af74909SZhong Yang 		const int charsLen = WideCharLenFromMultiByte(CP_UTF8, utf8Input);
892*8af74909SZhong Yang 		std::wstring characters(charsLen, L'\0');
893*8af74909SZhong Yang 		WideCharFromMultiByte(CP_UTF8, utf8Input, &characters[0], charsLen);
894*8af74909SZhong Yang 
895*8af74909SZhong Yang 		const int encodedLen = MultiByteLenFromWideChar(CodePageOfDocument(), characters);
896*8af74909SZhong Yang 		if (encoded) {
897*8af74909SZhong Yang 			MultiByteFromWideChar(CodePageOfDocument(), characters, encoded, encodedLen);
898*8af74909SZhong Yang 			encoded[encodedLen] = '\0';
899*8af74909SZhong Yang 		}
900*8af74909SZhong Yang 		return encodedLen;
901*8af74909SZhong Yang 	}
902*8af74909SZhong Yang }
903*8af74909SZhong Yang 
904*8af74909SZhong Yang bool ScintillaWin::PaintDC(HDC hdc) {
905*8af74909SZhong Yang 	if (technology == SC_TECHNOLOGY_DEFAULT) {
906*8af74909SZhong Yang 		AutoSurface surfaceWindow(hdc, this);
907*8af74909SZhong Yang 		if (surfaceWindow) {
908*8af74909SZhong Yang 			Paint(surfaceWindow, rcPaint);
909*8af74909SZhong Yang 			surfaceWindow->Release();
910*8af74909SZhong Yang 		}
911*8af74909SZhong Yang 	} else {
912*8af74909SZhong Yang #if defined(USE_D2D)
913*8af74909SZhong Yang 		EnsureRenderTarget(hdc);
914*8af74909SZhong Yang 		if (pRenderTarget) {
915*8af74909SZhong Yang 			AutoSurface surfaceWindow(pRenderTarget, this);
916*8af74909SZhong Yang 			if (surfaceWindow) {
917*8af74909SZhong Yang 				pRenderTarget->BeginDraw();
918*8af74909SZhong Yang 				Paint(surfaceWindow, rcPaint);
919*8af74909SZhong Yang 				surfaceWindow->Release();
920*8af74909SZhong Yang 				const HRESULT hr = pRenderTarget->EndDraw();
921*8af74909SZhong Yang 				if (hr == static_cast<HRESULT>(D2DERR_RECREATE_TARGET)) {
922*8af74909SZhong Yang 					DropRenderTarget();
923*8af74909SZhong Yang 					return false;
924*8af74909SZhong Yang 				}
925*8af74909SZhong Yang 			}
926*8af74909SZhong Yang 		}
927*8af74909SZhong Yang #endif
928*8af74909SZhong Yang 	}
929*8af74909SZhong Yang 
930*8af74909SZhong Yang 	return true;
931*8af74909SZhong Yang }
932*8af74909SZhong Yang 
933*8af74909SZhong Yang sptr_t ScintillaWin::WndPaint() {
934*8af74909SZhong Yang 	//ElapsedPeriod ep;
935*8af74909SZhong Yang 
936*8af74909SZhong Yang 	// Redirect assertions to debug output and save current state
937*8af74909SZhong Yang 	const bool assertsPopup = Platform::ShowAssertionPopUps(false);
938*8af74909SZhong Yang 	paintState = painting;
939*8af74909SZhong Yang 	PAINTSTRUCT ps = {};
940*8af74909SZhong Yang 
941*8af74909SZhong Yang 	// Removed since this interferes with reporting other assertions as it occurs repeatedly
942*8af74909SZhong Yang 	//PLATFORM_ASSERT(hRgnUpdate == NULL);
943*8af74909SZhong Yang 	hRgnUpdate = ::CreateRectRgn(0, 0, 0, 0);
944*8af74909SZhong Yang 	::GetUpdateRgn(MainHWND(), hRgnUpdate, FALSE);
945*8af74909SZhong Yang 	::BeginPaint(MainHWND(), &ps);
946*8af74909SZhong Yang 	rcPaint = PRectangle::FromInts(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
947*8af74909SZhong Yang 	const PRectangle rcClient = GetClientRectangle();
948*8af74909SZhong Yang 	paintingAllText = BoundsContains(rcPaint, hRgnUpdate, rcClient);
949*8af74909SZhong Yang 	if (!PaintDC(ps.hdc)) {
950*8af74909SZhong Yang 		paintState = paintAbandoned;
951*8af74909SZhong Yang 	}
952*8af74909SZhong Yang 	if (hRgnUpdate) {
953*8af74909SZhong Yang 		::DeleteRgn(hRgnUpdate);
954*8af74909SZhong Yang 		hRgnUpdate = {};
955*8af74909SZhong Yang 	}
956*8af74909SZhong Yang 
957*8af74909SZhong Yang 	::EndPaint(MainHWND(), &ps);
958*8af74909SZhong Yang 	if (paintState == paintAbandoned) {
959*8af74909SZhong Yang 		// Painting area was insufficient to cover new styling or brace highlight positions
960*8af74909SZhong Yang 		FullPaint();
961*8af74909SZhong Yang 		::ValidateRect(MainHWND(), nullptr);
962*8af74909SZhong Yang 	}
963*8af74909SZhong Yang 	paintState = notPainting;
964*8af74909SZhong Yang 
965*8af74909SZhong Yang 	// Restore debug output state
966*8af74909SZhong Yang 	Platform::ShowAssertionPopUps(assertsPopup);
967*8af74909SZhong Yang 
968*8af74909SZhong Yang 	//Platform::DebugPrintf("Paint took %g\n", ep.Duration());
969*8af74909SZhong Yang 	return 0;
970*8af74909SZhong Yang }
971*8af74909SZhong Yang 
972*8af74909SZhong Yang sptr_t ScintillaWin::HandleCompositionWindowed(uptr_t wParam, sptr_t lParam) {
973*8af74909SZhong Yang 	if (lParam & GCS_RESULTSTR) {
974*8af74909SZhong Yang 		IMContext imc(MainHWND());
975*8af74909SZhong Yang 		if (imc.hIMC) {
976*8af74909SZhong Yang 			AddWString(imc.GetCompositionString(GCS_RESULTSTR), CharacterSource::imeResult);
977*8af74909SZhong Yang 
978*8af74909SZhong Yang 			// Set new position after converted
979*8af74909SZhong Yang 			const Point pos = PointMainCaret();
980*8af74909SZhong Yang 			COMPOSITIONFORM CompForm;
981*8af74909SZhong Yang 			CompForm.dwStyle = CFS_POINT;
982*8af74909SZhong Yang 			CompForm.ptCurrentPos = POINTFromPoint(pos);
983*8af74909SZhong Yang 			::ImmSetCompositionWindow(imc.hIMC, &CompForm);
984*8af74909SZhong Yang 		}
985*8af74909SZhong Yang 		return 0;
986*8af74909SZhong Yang 	}
987*8af74909SZhong Yang 	return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
988*8af74909SZhong Yang }
989*8af74909SZhong Yang 
990*8af74909SZhong Yang bool ScintillaWin::KoreanIME() noexcept {
991*8af74909SZhong Yang 	const int codePage = InputCodePage();
992*8af74909SZhong Yang 	return codePage == 949 || codePage == 1361;
993*8af74909SZhong Yang }
994*8af74909SZhong Yang 
995*8af74909SZhong Yang void ScintillaWin::MoveImeCarets(Sci::Position offset) {
996*8af74909SZhong Yang 	// Move carets relatively by bytes.
997*8af74909SZhong Yang 	for (size_t r=0; r<sel.Count(); r++) {
998*8af74909SZhong Yang 		const Sci::Position positionInsert = sel.Range(r).Start().Position();
999*8af74909SZhong Yang 		sel.Range(r).caret.SetPosition(positionInsert + offset);
1000*8af74909SZhong Yang 		sel.Range(r).anchor.SetPosition(positionInsert + offset);
1001*8af74909SZhong Yang 	}
1002*8af74909SZhong Yang }
1003*8af74909SZhong Yang 
1004*8af74909SZhong Yang void ScintillaWin::DrawImeIndicator(int indicator, Sci::Position len) {
1005*8af74909SZhong Yang 	// Emulate the visual style of IME characters with indicators.
1006*8af74909SZhong Yang 	// Draw an indicator on the character before caret by the character bytes of len
1007*8af74909SZhong Yang 	// so it should be called after InsertCharacter().
1008*8af74909SZhong Yang 	// It does not affect caret positions.
1009*8af74909SZhong Yang 	if (indicator < 8 || indicator > INDICATOR_MAX) {
1010*8af74909SZhong Yang 		return;
1011*8af74909SZhong Yang 	}
1012*8af74909SZhong Yang 	pdoc->DecorationSetCurrentIndicator(indicator);
1013*8af74909SZhong Yang 	for (size_t r=0; r<sel.Count(); r++) {
1014*8af74909SZhong Yang 		const Sci::Position positionInsert = sel.Range(r).Start().Position();
1015*8af74909SZhong Yang 		pdoc->DecorationFillRange(positionInsert - len, 1, len);
1016*8af74909SZhong Yang 	}
1017*8af74909SZhong Yang }
1018*8af74909SZhong Yang 
1019*8af74909SZhong Yang void ScintillaWin::SetCandidateWindowPos() {
1020*8af74909SZhong Yang 	IMContext imc(MainHWND());
1021*8af74909SZhong Yang 	if (imc.hIMC) {
1022*8af74909SZhong Yang 		const Point pos = PointMainCaret();
1023*8af74909SZhong Yang 		const PRectangle rcClient = GetTextRectangle();
1024*8af74909SZhong Yang 		CANDIDATEFORM CandForm{};
1025*8af74909SZhong Yang 		CandForm.dwIndex = 0;
1026*8af74909SZhong Yang 		CandForm.dwStyle = CFS_EXCLUDE;
1027*8af74909SZhong Yang 		CandForm.ptCurrentPos.x = static_cast<int>(pos.x);
1028*8af74909SZhong Yang 		CandForm.ptCurrentPos.y = static_cast<int>(pos.y + std::max(4, vs.lineHeight/4));
1029*8af74909SZhong Yang 		// Exclude the area of the whole caret line
1030*8af74909SZhong Yang 		CandForm.rcArea.top = static_cast<int>(pos.y);
1031*8af74909SZhong Yang 		CandForm.rcArea.bottom = static_cast<int>(pos.y + vs.lineHeight);
1032*8af74909SZhong Yang 		CandForm.rcArea.left = static_cast<int>(rcClient.left);
1033*8af74909SZhong Yang 		CandForm.rcArea.right = static_cast<int>(rcClient.right);
1034*8af74909SZhong Yang 		::ImmSetCandidateWindow(imc.hIMC, &CandForm);
1035*8af74909SZhong Yang 	}
1036*8af74909SZhong Yang }
1037*8af74909SZhong Yang 
1038*8af74909SZhong Yang void ScintillaWin::SelectionToHangul() {
1039*8af74909SZhong Yang 	// Convert every hanja to hangul within the main range.
1040*8af74909SZhong Yang 	const Sci::Position selStart = sel.RangeMain().Start().Position();
1041*8af74909SZhong Yang 	const Sci::Position documentStrLen = sel.RangeMain().Length();
1042*8af74909SZhong Yang 	const Sci::Position selEnd = selStart + documentStrLen;
1043*8af74909SZhong Yang 	const Sci::Position utf16Len = pdoc->CountUTF16(selStart, selEnd);
1044*8af74909SZhong Yang 
1045*8af74909SZhong Yang 	if (utf16Len > 0) {
1046*8af74909SZhong Yang 		std::string documentStr(documentStrLen, '\0');
1047*8af74909SZhong Yang 		pdoc->GetCharRange(&documentStr[0], selStart, documentStrLen);
1048*8af74909SZhong Yang 
1049*8af74909SZhong Yang 		std::wstring uniStr = StringDecode(documentStr, CodePageOfDocument());
1050*8af74909SZhong Yang 		const int converted = HanjaDict::GetHangulOfHanja(&uniStr[0]);
1051*8af74909SZhong Yang 		documentStr = StringEncode(uniStr, CodePageOfDocument());
1052*8af74909SZhong Yang 
1053*8af74909SZhong Yang 		if (converted > 0) {
1054*8af74909SZhong Yang 			pdoc->BeginUndoAction();
1055*8af74909SZhong Yang 			ClearSelection();
1056*8af74909SZhong Yang 			InsertPaste(&documentStr[0], documentStr.size());
1057*8af74909SZhong Yang 			pdoc->EndUndoAction();
1058*8af74909SZhong Yang 		}
1059*8af74909SZhong Yang 	}
1060*8af74909SZhong Yang }
1061*8af74909SZhong Yang 
1062*8af74909SZhong Yang void ScintillaWin::EscapeHanja() {
1063*8af74909SZhong Yang 	// The candidate box pops up to user to select a hanja.
1064*8af74909SZhong Yang 	// It comes into WM_IME_COMPOSITION with GCS_RESULTSTR.
1065*8af74909SZhong Yang 	// The existing hangul or hanja is replaced with it.
1066*8af74909SZhong Yang 	if (sel.Count() > 1) {
1067*8af74909SZhong Yang 		return; // Do not allow multi carets.
1068*8af74909SZhong Yang 	}
1069*8af74909SZhong Yang 	const Sci::Position currentPos = CurrentPosition();
1070*8af74909SZhong Yang 	const int oneCharLen = pdoc->LenChar(currentPos);
1071*8af74909SZhong Yang 
1072*8af74909SZhong Yang 	if (oneCharLen < 2) {
1073*8af74909SZhong Yang 		return; // No need to handle SBCS.
1074*8af74909SZhong Yang 	}
1075*8af74909SZhong Yang 
1076*8af74909SZhong Yang 	// ImmEscapeW() may overwrite uniChar[] with a null terminated string.
1077*8af74909SZhong Yang 	// So enlarge it enough to Maximum 4 as in UTF-8.
1078*8af74909SZhong Yang 	constexpr size_t safeLength = UTF8MaxBytes + 1;
1079*8af74909SZhong Yang 	std::string oneChar(safeLength, '\0');
1080*8af74909SZhong Yang 	pdoc->GetCharRange(&oneChar[0], currentPos, oneCharLen);
1081*8af74909SZhong Yang 
1082*8af74909SZhong Yang 	std::wstring uniChar = StringDecode(oneChar, CodePageOfDocument());
1083*8af74909SZhong Yang 
1084*8af74909SZhong Yang 	IMContext imc(MainHWND());
1085*8af74909SZhong Yang 	if (imc.hIMC) {
1086*8af74909SZhong Yang 		// Set the candidate box position since IME may show it.
1087*8af74909SZhong Yang 		SetCandidateWindowPos();
1088*8af74909SZhong Yang 		// IME_ESC_HANJA_MODE appears to receive the first character only.
1089*8af74909SZhong Yang 		if (::ImmEscapeW(GetKeyboardLayout(0), imc.hIMC, IME_ESC_HANJA_MODE, &uniChar[0])) {
1090*8af74909SZhong Yang 			SetSelection(currentPos, currentPos + oneCharLen);
1091*8af74909SZhong Yang 		}
1092*8af74909SZhong Yang 	}
1093*8af74909SZhong Yang }
1094*8af74909SZhong Yang 
1095*8af74909SZhong Yang void ScintillaWin::ToggleHanja() {
1096*8af74909SZhong Yang 	// If selection, convert every hanja to hangul within the main range.
1097*8af74909SZhong Yang 	// If no selection, commit to IME.
1098*8af74909SZhong Yang 	if (sel.Count() > 1) {
1099*8af74909SZhong Yang 		return; // Do not allow multi carets.
1100*8af74909SZhong Yang 	}
1101*8af74909SZhong Yang 
1102*8af74909SZhong Yang 	if (sel.Empty()) {
1103*8af74909SZhong Yang 		EscapeHanja();
1104*8af74909SZhong Yang 	} else {
1105*8af74909SZhong Yang 		SelectionToHangul();
1106*8af74909SZhong Yang 	}
1107*8af74909SZhong Yang }
1108*8af74909SZhong Yang 
1109*8af74909SZhong Yang namespace {
1110*8af74909SZhong Yang 
1111*8af74909SZhong Yang std::vector<int> MapImeIndicators(std::vector<BYTE> inputStyle) {
1112*8af74909SZhong Yang 	std::vector<int> imeIndicator(inputStyle.size(), SC_INDICATOR_UNKNOWN);
1113*8af74909SZhong Yang 	for (size_t i = 0; i < inputStyle.size(); i++) {
1114*8af74909SZhong Yang 		switch (static_cast<int>(inputStyle.at(i))) {
1115*8af74909SZhong Yang 		case ATTR_INPUT:
1116*8af74909SZhong Yang 			imeIndicator[i] = SC_INDICATOR_INPUT;
1117*8af74909SZhong Yang 			break;
1118*8af74909SZhong Yang 		case ATTR_TARGET_NOTCONVERTED:
1119*8af74909SZhong Yang 		case ATTR_TARGET_CONVERTED:
1120*8af74909SZhong Yang 			imeIndicator[i] = SC_INDICATOR_TARGET;
1121*8af74909SZhong Yang 			break;
1122*8af74909SZhong Yang 		case ATTR_CONVERTED:
1123*8af74909SZhong Yang 			imeIndicator[i] = SC_INDICATOR_CONVERTED;
1124*8af74909SZhong Yang 			break;
1125*8af74909SZhong Yang 		default:
1126*8af74909SZhong Yang 			imeIndicator[i] = SC_INDICATOR_UNKNOWN;
1127*8af74909SZhong Yang 			break;
1128*8af74909SZhong Yang 		}
1129*8af74909SZhong Yang 	}
1130*8af74909SZhong Yang 	return imeIndicator;
1131*8af74909SZhong Yang }
1132*8af74909SZhong Yang 
1133*8af74909SZhong Yang }
1134*8af74909SZhong Yang 
1135*8af74909SZhong Yang void ScintillaWin::AddWString(std::wstring_view wsv, CharacterSource charSource) {
1136*8af74909SZhong Yang 	if (wsv.empty())
1137*8af74909SZhong Yang 		return;
1138*8af74909SZhong Yang 
1139*8af74909SZhong Yang 	const int codePage = CodePageOfDocument();
1140*8af74909SZhong Yang 	for (size_t i = 0; i < wsv.size(); ) {
1141*8af74909SZhong Yang 		const size_t ucWidth = UTF16CharLength(wsv[i]);
1142*8af74909SZhong Yang 		const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage);
1143*8af74909SZhong Yang 
1144*8af74909SZhong Yang 		InsertCharacter(docChar, charSource);
1145*8af74909SZhong Yang 		i += ucWidth;
1146*8af74909SZhong Yang 	}
1147*8af74909SZhong Yang }
1148*8af74909SZhong Yang 
1149*8af74909SZhong Yang sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) {
1150*8af74909SZhong Yang 	// Copy & paste by johnsonj with a lot of helps of Neil.
1151*8af74909SZhong Yang 	// Great thanks for my foreruners, jiniya and BLUEnLIVE.
1152*8af74909SZhong Yang 
1153*8af74909SZhong Yang 	IMContext imc(MainHWND());
1154*8af74909SZhong Yang 	if (!imc.hIMC)
1155*8af74909SZhong Yang 		return 0;
1156*8af74909SZhong Yang 	if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
1157*8af74909SZhong Yang 		::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
1158*8af74909SZhong Yang 		return 0;
1159*8af74909SZhong Yang 	}
1160*8af74909SZhong Yang 
1161*8af74909SZhong Yang 	bool initialCompose = false;
1162*8af74909SZhong Yang 	if (pdoc->TentativeActive()) {
1163*8af74909SZhong Yang 		pdoc->TentativeUndo();
1164*8af74909SZhong Yang 	} else {
1165*8af74909SZhong Yang 		// No tentative undo means start of this composition so
1166*8af74909SZhong Yang 		// fill in any virtual spaces.
1167*8af74909SZhong Yang 		initialCompose = true;
1168*8af74909SZhong Yang 	}
1169*8af74909SZhong Yang 
1170*8af74909SZhong Yang 	view.imeCaretBlockOverride = false;
1171*8af74909SZhong Yang 
1172*8af74909SZhong Yang 	if (lParam & GCS_RESULTSTR) {
1173*8af74909SZhong Yang 		AddWString(imc.GetCompositionString(GCS_RESULTSTR), CharacterSource::imeResult);
1174*8af74909SZhong Yang 	}
1175*8af74909SZhong Yang 
1176*8af74909SZhong Yang 	if (lParam & GCS_COMPSTR) {
1177*8af74909SZhong Yang 		const std::wstring wcs = imc.GetCompositionString(GCS_COMPSTR);
1178*8af74909SZhong Yang 		if (wcs.empty()) {
1179*8af74909SZhong Yang 			ShowCaretAtCurrentPosition();
1180*8af74909SZhong Yang 			return 0;
1181*8af74909SZhong Yang 		}
1182*8af74909SZhong Yang 
1183*8af74909SZhong Yang 		if (initialCompose) {
1184*8af74909SZhong Yang 			ClearBeforeTentativeStart();
1185*8af74909SZhong Yang 		}
1186*8af74909SZhong Yang 
1187*8af74909SZhong Yang 		// Set candidate window left aligned to beginning of preedit string.
1188*8af74909SZhong Yang 		SetCandidateWindowPos();
1189*8af74909SZhong Yang 		pdoc->TentativeStart(); // TentativeActive from now on.
1190*8af74909SZhong Yang 
1191*8af74909SZhong Yang 		std::vector<int> imeIndicator = MapImeIndicators(imc.GetImeAttributes());
1192*8af74909SZhong Yang 
1193*8af74909SZhong Yang 		const int codePage = CodePageOfDocument();
1194*8af74909SZhong Yang 		const std::wstring_view wsv = wcs;
1195*8af74909SZhong Yang 		for (size_t i = 0; i < wsv.size(); ) {
1196*8af74909SZhong Yang 			const size_t ucWidth = UTF16CharLength(wsv[i]);
1197*8af74909SZhong Yang 			const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage);
1198*8af74909SZhong Yang 
1199*8af74909SZhong Yang 			InsertCharacter(docChar, CharacterSource::tentativeInput);
1200*8af74909SZhong Yang 
1201*8af74909SZhong Yang 			DrawImeIndicator(imeIndicator[i], docChar.size());
1202*8af74909SZhong Yang 			i += ucWidth;
1203*8af74909SZhong Yang 		}
1204*8af74909SZhong Yang 
1205*8af74909SZhong Yang 		// Japanese IME after pressing Tab replaces input string with first candidate item (target string);
1206*8af74909SZhong Yang 		// when selecting other candidate item, previous item will be replaced with current one.
1207*8af74909SZhong Yang 		// After candidate item been added, it's looks like been full selected, it's better to keep caret
1208*8af74909SZhong Yang 		// at end of "selection" (end of input) instead of jump to beginning of input ("selection").
1209*8af74909SZhong Yang 		const bool onlyTarget = std::all_of(imeIndicator.begin(), imeIndicator.end(), [](int i) noexcept {
1210*8af74909SZhong Yang 			return i == SC_INDICATOR_TARGET;
1211*8af74909SZhong Yang 		});
1212*8af74909SZhong Yang 		if (!onlyTarget) {
1213*8af74909SZhong Yang 			// CS_NOMOVECARET: keep caret at beginning of composition string which already moved in InsertCharacter().
1214*8af74909SZhong Yang 			// GCS_CURSORPOS: current caret position is provided by IME.
1215*8af74909SZhong Yang 			Sci::Position imeEndToImeCaretU16 = -static_cast<Sci::Position>(wcs.size());
1216*8af74909SZhong Yang 			if (!(lParam & CS_NOMOVECARET) && (lParam & GCS_CURSORPOS)) {
1217*8af74909SZhong Yang 				imeEndToImeCaretU16 += imc.GetImeCaretPos();
1218*8af74909SZhong Yang 			}
1219*8af74909SZhong Yang 			if (imeEndToImeCaretU16 != 0) {
1220*8af74909SZhong Yang 				// Move back IME caret from current last position to imeCaretPos.
1221*8af74909SZhong Yang 				const Sci::Position currentPos = CurrentPosition();
1222*8af74909SZhong Yang 				const Sci::Position imeCaretPosDoc = pdoc->GetRelativePositionUTF16(currentPos, imeEndToImeCaretU16);
1223*8af74909SZhong Yang 
1224*8af74909SZhong Yang 				MoveImeCarets(-currentPos + imeCaretPosDoc);
1225*8af74909SZhong Yang 
1226*8af74909SZhong Yang 				if (std::find(imeIndicator.begin(), imeIndicator.end(), SC_INDICATOR_TARGET) != imeIndicator.end()) {
1227*8af74909SZhong Yang 					// set candidate window left aligned to beginning of target string.
1228*8af74909SZhong Yang 					SetCandidateWindowPos();
1229*8af74909SZhong Yang 				}
1230*8af74909SZhong Yang 			}
1231*8af74909SZhong Yang 		}
1232*8af74909SZhong Yang 
1233*8af74909SZhong Yang 		if (KoreanIME()) {
1234*8af74909SZhong Yang 			view.imeCaretBlockOverride = true;
1235*8af74909SZhong Yang 		}
1236*8af74909SZhong Yang 	}
1237*8af74909SZhong Yang 	EnsureCaretVisible();
1238*8af74909SZhong Yang 	ShowCaretAtCurrentPosition();
1239*8af74909SZhong Yang 	return 0;
1240*8af74909SZhong Yang }
1241*8af74909SZhong Yang 
1242*8af74909SZhong Yang namespace {
1243*8af74909SZhong Yang 
1244*8af74909SZhong Yang // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
1245*8af74909SZhong Yang unsigned int SciMessageFromEM(unsigned int iMessage) noexcept {
1246*8af74909SZhong Yang 	switch (iMessage) {
1247*8af74909SZhong Yang 	case EM_CANPASTE: return SCI_CANPASTE;
1248*8af74909SZhong Yang 	case EM_CANUNDO: return SCI_CANUNDO;
1249*8af74909SZhong Yang 	case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER;
1250*8af74909SZhong Yang 	case EM_FINDTEXTEX: return SCI_FINDTEXT;
1251*8af74909SZhong Yang 	case EM_FORMATRANGE: return SCI_FORMATRANGE;
1252*8af74909SZhong Yang 	case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE;
1253*8af74909SZhong Yang 	case EM_GETLINECOUNT: return SCI_GETLINECOUNT;
1254*8af74909SZhong Yang 	case EM_GETSELTEXT: return SCI_GETSELTEXT;
1255*8af74909SZhong Yang 	case EM_GETTEXTRANGE: return SCI_GETTEXTRANGE;
1256*8af74909SZhong Yang 	case EM_HIDESELECTION: return SCI_HIDESELECTION;
1257*8af74909SZhong Yang 	case EM_LINEINDEX: return SCI_POSITIONFROMLINE;
1258*8af74909SZhong Yang 	case EM_LINESCROLL: return SCI_LINESCROLL;
1259*8af74909SZhong Yang 	case EM_REPLACESEL: return SCI_REPLACESEL;
1260*8af74909SZhong Yang 	case EM_SCROLLCARET: return SCI_SCROLLCARET;
1261*8af74909SZhong Yang 	case EM_SETREADONLY: return SCI_SETREADONLY;
1262*8af74909SZhong Yang 	case WM_CLEAR: return SCI_CLEAR;
1263*8af74909SZhong Yang 	case WM_COPY: return SCI_COPY;
1264*8af74909SZhong Yang 	case WM_CUT: return SCI_CUT;
1265*8af74909SZhong Yang 	case WM_SETTEXT: return SCI_SETTEXT;
1266*8af74909SZhong Yang 	case WM_PASTE: return SCI_PASTE;
1267*8af74909SZhong Yang 	case WM_UNDO: return SCI_UNDO;
1268*8af74909SZhong Yang 	}
1269*8af74909SZhong Yang 	return iMessage;
1270*8af74909SZhong Yang }
1271*8af74909SZhong Yang 
1272*8af74909SZhong Yang }
1273*8af74909SZhong Yang 
1274*8af74909SZhong Yang namespace Scintilla {
1275*8af74909SZhong Yang 
1276*8af74909SZhong Yang UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept {
1277*8af74909SZhong Yang 	if (documentCodePage == SC_CP_UTF8) {
1278*8af74909SZhong Yang 		return SC_CP_UTF8;
1279*8af74909SZhong Yang 	}
1280*8af74909SZhong Yang 	switch (characterSet) {
1281*8af74909SZhong Yang 	case SC_CHARSET_ANSI: return 1252;
1282*8af74909SZhong Yang 	case SC_CHARSET_DEFAULT: return documentCodePage ? documentCodePage : 1252;
1283*8af74909SZhong Yang 	case SC_CHARSET_BALTIC: return 1257;
1284*8af74909SZhong Yang 	case SC_CHARSET_CHINESEBIG5: return 950;
1285*8af74909SZhong Yang 	case SC_CHARSET_EASTEUROPE: return 1250;
1286*8af74909SZhong Yang 	case SC_CHARSET_GB2312: return 936;
1287*8af74909SZhong Yang 	case SC_CHARSET_GREEK: return 1253;
1288*8af74909SZhong Yang 	case SC_CHARSET_HANGUL: return 949;
1289*8af74909SZhong Yang 	case SC_CHARSET_MAC: return 10000;
1290*8af74909SZhong Yang 	case SC_CHARSET_OEM: return 437;
1291*8af74909SZhong Yang 	case SC_CHARSET_RUSSIAN: return 1251;
1292*8af74909SZhong Yang 	case SC_CHARSET_SHIFTJIS: return 932;
1293*8af74909SZhong Yang 	case SC_CHARSET_TURKISH: return 1254;
1294*8af74909SZhong Yang 	case SC_CHARSET_JOHAB: return 1361;
1295*8af74909SZhong Yang 	case SC_CHARSET_HEBREW: return 1255;
1296*8af74909SZhong Yang 	case SC_CHARSET_ARABIC: return 1256;
1297*8af74909SZhong Yang 	case SC_CHARSET_VIETNAMESE: return 1258;
1298*8af74909SZhong Yang 	case SC_CHARSET_THAI: return 874;
1299*8af74909SZhong Yang 	case SC_CHARSET_8859_15: return 28605;
1300*8af74909SZhong Yang 	// Not supported
1301*8af74909SZhong Yang 	case SC_CHARSET_CYRILLIC: return documentCodePage;
1302*8af74909SZhong Yang 	case SC_CHARSET_SYMBOL: return documentCodePage;
1303*8af74909SZhong Yang 	}
1304*8af74909SZhong Yang 	return documentCodePage;
1305*8af74909SZhong Yang }
1306*8af74909SZhong Yang 
1307*8af74909SZhong Yang }
1308*8af74909SZhong Yang 
1309*8af74909SZhong Yang UINT ScintillaWin::CodePageOfDocument() const noexcept {
1310*8af74909SZhong Yang 	return CodePageFromCharSet(vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage);
1311*8af74909SZhong Yang }
1312*8af74909SZhong Yang 
1313*8af74909SZhong Yang std::string ScintillaWin::EncodeWString(std::wstring_view wsv) {
1314*8af74909SZhong Yang 	if (IsUnicodeMode()) {
1315*8af74909SZhong Yang 		const size_t len = UTF8Length(wsv);
1316*8af74909SZhong Yang 		std::string putf(len, 0);
1317*8af74909SZhong Yang 		UTF8FromUTF16(wsv, putf.data(), len);
1318*8af74909SZhong Yang 		return putf;
1319*8af74909SZhong Yang 	} else {
1320*8af74909SZhong Yang 		// Not in Unicode mode so convert from Unicode to current Scintilla code page
1321*8af74909SZhong Yang 		return StringEncode(wsv, CodePageOfDocument());
1322*8af74909SZhong Yang 	}
1323*8af74909SZhong Yang }
1324*8af74909SZhong Yang 
1325*8af74909SZhong Yang sptr_t ScintillaWin::GetTextLength() {
1326*8af74909SZhong Yang 	return pdoc->CountUTF16(0, pdoc->Length());
1327*8af74909SZhong Yang }
1328*8af74909SZhong Yang 
1329*8af74909SZhong Yang sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) {
1330*8af74909SZhong Yang 	if (lParam == 0) {
1331*8af74909SZhong Yang 		return pdoc->CountUTF16(0, pdoc->Length());
1332*8af74909SZhong Yang 	}
1333*8af74909SZhong Yang 	if (wParam == 0) {
1334*8af74909SZhong Yang 		return 0;
1335*8af74909SZhong Yang 	}
1336*8af74909SZhong Yang 	wchar_t *ptr = static_cast<wchar_t *>(PtrFromSPtr(lParam));
1337*8af74909SZhong Yang 	if (pdoc->Length() == 0) {
1338*8af74909SZhong Yang 		*ptr = L'\0';
1339*8af74909SZhong Yang 		return 0;
1340*8af74909SZhong Yang 	}
1341*8af74909SZhong Yang 	const Sci::Position lengthWanted = wParam - 1;
1342*8af74909SZhong Yang 	Sci::Position sizeRequestedRange = pdoc->GetRelativePositionUTF16(0, lengthWanted);
1343*8af74909SZhong Yang 	if (sizeRequestedRange < 0) {
1344*8af74909SZhong Yang 		// Requested more text than there is in the document.
1345*8af74909SZhong Yang 		sizeRequestedRange = pdoc->Length();
1346*8af74909SZhong Yang 	}
1347*8af74909SZhong Yang 	std::string docBytes(sizeRequestedRange, '\0');
1348*8af74909SZhong Yang 	pdoc->GetCharRange(&docBytes[0], 0, sizeRequestedRange);
1349*8af74909SZhong Yang 	if (IsUnicodeMode()) {
1350*8af74909SZhong Yang 		const size_t uLen = UTF16FromUTF8(docBytes, ptr, lengthWanted);
1351*8af74909SZhong Yang 		ptr[uLen] = L'\0';
1352*8af74909SZhong Yang 		return uLen;
1353*8af74909SZhong Yang 	} else {
1354*8af74909SZhong Yang 		// Not Unicode mode
1355*8af74909SZhong Yang 		// Convert to Unicode using the current Scintilla code page
1356*8af74909SZhong Yang 		const UINT cpSrc = CodePageOfDocument();
1357*8af74909SZhong Yang 		int lengthUTF16 = WideCharLenFromMultiByte(cpSrc, docBytes);
1358*8af74909SZhong Yang 		if (lengthUTF16 > lengthWanted)
1359*8af74909SZhong Yang 			lengthUTF16 = static_cast<int>(lengthWanted);
1360*8af74909SZhong Yang 		WideCharFromMultiByte(cpSrc, docBytes, ptr, lengthUTF16);
1361*8af74909SZhong Yang 		ptr[lengthUTF16] = L'\0';
1362*8af74909SZhong Yang 		return lengthUTF16;
1363*8af74909SZhong Yang 	}
1364*8af74909SZhong Yang }
1365*8af74909SZhong Yang 
1366*8af74909SZhong Yang Window::Cursor ScintillaWin::ContextCursor(Point pt) {
1367*8af74909SZhong Yang 	if (inDragDrop == ddDragging) {
1368*8af74909SZhong Yang 		return Window::cursorUp;
1369*8af74909SZhong Yang 	} else {
1370*8af74909SZhong Yang 		// Display regular (drag) cursor over selection
1371*8af74909SZhong Yang 		if (PointInSelMargin(pt)) {
1372*8af74909SZhong Yang 			return GetMarginCursor(pt);
1373*8af74909SZhong Yang 		} else if (!SelectionEmpty() && PointInSelection(pt)) {
1374*8af74909SZhong Yang 			return Window::cursorArrow;
1375*8af74909SZhong Yang 		} else if (PointIsHotspot(pt)) {
1376*8af74909SZhong Yang 			return Window::cursorHand;
1377*8af74909SZhong Yang 		} else if (hoverIndicatorPos != Sci::invalidPosition) {
1378*8af74909SZhong Yang 			const Sci::Position pos = PositionFromLocation(pt, true, true);
1379*8af74909SZhong Yang 			if (pos != Sci::invalidPosition) {
1380*8af74909SZhong Yang 				return Window::cursorHand;
1381*8af74909SZhong Yang 			}
1382*8af74909SZhong Yang 		}
1383*8af74909SZhong Yang 	}
1384*8af74909SZhong Yang 	return Window::cursorText;
1385*8af74909SZhong Yang }
1386*8af74909SZhong Yang 
1387*8af74909SZhong Yang sptr_t ScintillaWin::ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1388*8af74909SZhong Yang 	Point pt = PointFromLParam(lParam);
1389*8af74909SZhong Yang 	POINT rpt = POINTFromPoint(pt);
1390*8af74909SZhong Yang 	::ScreenToClient(MainHWND(), &rpt);
1391*8af74909SZhong Yang 	const Point ptClient = PointFromPOINT(rpt);
1392*8af74909SZhong Yang 	if (ShouldDisplayPopup(ptClient)) {
1393*8af74909SZhong Yang 		if ((pt.x == -1) && (pt.y == -1)) {
1394*8af74909SZhong Yang 			// Caused by keyboard so display menu near caret
1395*8af74909SZhong Yang 			pt = PointMainCaret();
1396*8af74909SZhong Yang 			POINT spt = POINTFromPoint(pt);
1397*8af74909SZhong Yang 			::ClientToScreen(MainHWND(), &spt);
1398*8af74909SZhong Yang 			pt = PointFromPOINT(spt);
1399*8af74909SZhong Yang 		}
1400*8af74909SZhong Yang 		ContextMenu(pt);
1401*8af74909SZhong Yang 		return 0;
1402*8af74909SZhong Yang 	}
1403*8af74909SZhong Yang 	return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1404*8af74909SZhong Yang }
1405*8af74909SZhong Yang 
1406*8af74909SZhong Yang void ScintillaWin::SizeWindow() {
1407*8af74909SZhong Yang #if defined(USE_D2D)
1408*8af74909SZhong Yang 	if (paintState == notPainting) {
1409*8af74909SZhong Yang 		DropRenderTarget();
1410*8af74909SZhong Yang 	} else {
1411*8af74909SZhong Yang 		renderTargetValid = false;
1412*8af74909SZhong Yang 	}
1413*8af74909SZhong Yang #endif
1414*8af74909SZhong Yang 	//Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam));
1415*8af74909SZhong Yang 	ChangeSize();
1416*8af74909SZhong Yang }
1417*8af74909SZhong Yang 
1418*8af74909SZhong Yang sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1419*8af74909SZhong Yang 	switch (iMessage) {
1420*8af74909SZhong Yang 	case WM_LBUTTONDOWN: {
1421*8af74909SZhong Yang 			// For IME, set the composition string as the result string.
1422*8af74909SZhong Yang 			IMContext imc(MainHWND());
1423*8af74909SZhong Yang 			if (imc.hIMC) {
1424*8af74909SZhong Yang 				::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
1425*8af74909SZhong Yang 			}
1426*8af74909SZhong Yang 			//
1427*8af74909SZhong Yang 			//Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
1428*8af74909SZhong Yang 			//	KeyboardIsKeyDown(VK_SHIFT),
1429*8af74909SZhong Yang 			//	KeyboardIsKeyDown(VK_CONTROL),
1430*8af74909SZhong Yang 			//	KeyboardIsKeyDown(VK_MENU));
1431*8af74909SZhong Yang 			::SetFocus(MainHWND());
1432*8af74909SZhong Yang 			ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(),
1433*8af74909SZhong Yang 						MouseModifiers(wParam));
1434*8af74909SZhong Yang 		}
1435*8af74909SZhong Yang 		break;
1436*8af74909SZhong Yang 
1437*8af74909SZhong Yang 	case WM_LBUTTONUP:
1438*8af74909SZhong Yang 		ButtonUpWithModifiers(PointFromLParam(lParam),
1439*8af74909SZhong Yang 				      ::GetMessageTime(), MouseModifiers(wParam));
1440*8af74909SZhong Yang 		break;
1441*8af74909SZhong Yang 
1442*8af74909SZhong Yang 	case WM_RBUTTONDOWN: {
1443*8af74909SZhong Yang 			::SetFocus(MainHWND());
1444*8af74909SZhong Yang 			const Point pt = PointFromLParam(lParam);
1445*8af74909SZhong Yang 			if (!PointInSelection(pt)) {
1446*8af74909SZhong Yang 				CancelModes();
1447*8af74909SZhong Yang 				SetEmptySelection(PositionFromLocation(PointFromLParam(lParam)));
1448*8af74909SZhong Yang 			}
1449*8af74909SZhong Yang 
1450*8af74909SZhong Yang 			RightButtonDownWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam));
1451*8af74909SZhong Yang 		}
1452*8af74909SZhong Yang 		break;
1453*8af74909SZhong Yang 
1454*8af74909SZhong Yang 	case WM_MOUSEMOVE: {
1455*8af74909SZhong Yang 			const Point pt = PointFromLParam(lParam);
1456*8af74909SZhong Yang 
1457*8af74909SZhong Yang 			// Windows might send WM_MOUSEMOVE even though the mouse has not been moved:
1458*8af74909SZhong Yang 			// http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx
1459*8af74909SZhong Yang 			if (ptMouseLast != pt) {
1460*8af74909SZhong Yang 				SetTrackMouseLeaveEvent(true);
1461*8af74909SZhong Yang 				ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam));
1462*8af74909SZhong Yang 			}
1463*8af74909SZhong Yang 		}
1464*8af74909SZhong Yang 		break;
1465*8af74909SZhong Yang 
1466*8af74909SZhong Yang 	case WM_MOUSELEAVE:
1467*8af74909SZhong Yang 		SetTrackMouseLeaveEvent(false);
1468*8af74909SZhong Yang 		MouseLeave();
1469*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1470*8af74909SZhong Yang 
1471*8af74909SZhong Yang 	case WM_MOUSEWHEEL:
1472*8af74909SZhong Yang 		if (!mouseWheelCaptures) {
1473*8af74909SZhong Yang 			// if the mouse wheel is not captured, test if the mouse
1474*8af74909SZhong Yang 			// pointer is over the editor window and if not, don't
1475*8af74909SZhong Yang 			// handle the message but pass it on.
1476*8af74909SZhong Yang 			RECT rc;
1477*8af74909SZhong Yang 			GetWindowRect(MainHWND(), &rc);
1478*8af74909SZhong Yang 			const POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1479*8af74909SZhong Yang 			if (!PtInRect(&rc, pt))
1480*8af74909SZhong Yang 				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1481*8af74909SZhong Yang 		}
1482*8af74909SZhong Yang 		// if autocomplete list active then send mousewheel message to it
1483*8af74909SZhong Yang 		if (ac.Active()) {
1484*8af74909SZhong Yang 			HWND hWnd = HwndFromWindow(*(ac.lb));
1485*8af74909SZhong Yang 			::SendMessage(hWnd, iMessage, wParam, lParam);
1486*8af74909SZhong Yang 			break;
1487*8af74909SZhong Yang 		}
1488*8af74909SZhong Yang 
1489*8af74909SZhong Yang 		// Don't handle datazoom.
1490*8af74909SZhong Yang 		// (A good idea for datazoom would be to "fold" or "unfold" details.
1491*8af74909SZhong Yang 		// i.e. if datazoomed out only class structures are visible, when datazooming in the control
1492*8af74909SZhong Yang 		// structures appear, then eventually the individual statements...)
1493*8af74909SZhong Yang 		if (wParam & MK_SHIFT) {
1494*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1495*8af74909SZhong Yang 		}
1496*8af74909SZhong Yang 		// Either SCROLL or ZOOM. We handle the wheel steppings calculation
1497*8af74909SZhong Yang 		wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
1498*8af74909SZhong Yang 		if (std::abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) {
1499*8af74909SZhong Yang 			Sci::Line linesToScroll = linesPerScroll;
1500*8af74909SZhong Yang 			if (linesPerScroll == WHEEL_PAGESCROLL)
1501*8af74909SZhong Yang 				linesToScroll = LinesOnScreen() - 1;
1502*8af74909SZhong Yang 			if (linesToScroll == 0) {
1503*8af74909SZhong Yang 				linesToScroll = 1;
1504*8af74909SZhong Yang 			}
1505*8af74909SZhong Yang 			linesToScroll *= (wheelDelta / WHEEL_DELTA);
1506*8af74909SZhong Yang 			if (wheelDelta >= 0)
1507*8af74909SZhong Yang 				wheelDelta = wheelDelta % WHEEL_DELTA;
1508*8af74909SZhong Yang 			else
1509*8af74909SZhong Yang 				wheelDelta = -(-wheelDelta % WHEEL_DELTA);
1510*8af74909SZhong Yang 
1511*8af74909SZhong Yang 			if (wParam & MK_CONTROL) {
1512*8af74909SZhong Yang 				// Zoom! We play with the font sizes in the styles.
1513*8af74909SZhong Yang 				// Number of steps/line is ignored, we just care if sizing up or down
1514*8af74909SZhong Yang 				if (linesToScroll < 0) {
1515*8af74909SZhong Yang 					KeyCommand(SCI_ZOOMIN);
1516*8af74909SZhong Yang 				} else {
1517*8af74909SZhong Yang 					KeyCommand(SCI_ZOOMOUT);
1518*8af74909SZhong Yang 				}
1519*8af74909SZhong Yang 			} else {
1520*8af74909SZhong Yang 				// Scroll
1521*8af74909SZhong Yang 				ScrollTo(topLine + linesToScroll);
1522*8af74909SZhong Yang 			}
1523*8af74909SZhong Yang 		}
1524*8af74909SZhong Yang 		return 0;
1525*8af74909SZhong Yang 	}
1526*8af74909SZhong Yang 	return 0;
1527*8af74909SZhong Yang }
1528*8af74909SZhong Yang 
1529*8af74909SZhong Yang sptr_t ScintillaWin::KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1530*8af74909SZhong Yang 	switch (iMessage) {
1531*8af74909SZhong Yang 
1532*8af74909SZhong Yang 	case WM_SYSKEYDOWN:
1533*8af74909SZhong Yang 	case WM_KEYDOWN: {
1534*8af74909SZhong Yang 			// Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n",
1535*8af74909SZhong Yang 			// iMessage == WM_KEYDOWN ? 'K' : 'S',
1536*8af74909SZhong Yang 			// (lParam & (1 << 24)) ? 'E' : '-',
1537*8af74909SZhong Yang 			// KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-',
1538*8af74909SZhong Yang 			// KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-',
1539*8af74909SZhong Yang 			// KeyboardIsKeyDown(VK_MENU) ? 'A' : '-',
1540*8af74909SZhong Yang 			// wParam, lParam);
1541*8af74909SZhong Yang 			lastKeyDownConsumed = false;
1542*8af74909SZhong Yang 			const bool altDown = KeyboardIsKeyDown(VK_MENU);
1543*8af74909SZhong Yang 			if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) {
1544*8af74909SZhong Yang 				// Don't interpret these as they may be characters entered by number.
1545*8af74909SZhong Yang 				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1546*8af74909SZhong Yang 			}
1547*8af74909SZhong Yang 			const int ret = KeyDownWithModifiers(KeyTranslate(static_cast<int>(wParam)),
1548*8af74909SZhong Yang 							     ModifierFlags(KeyboardIsKeyDown(VK_SHIFT),
1549*8af74909SZhong Yang 									     KeyboardIsKeyDown(VK_CONTROL),
1550*8af74909SZhong Yang 									     altDown),
1551*8af74909SZhong Yang 							     &lastKeyDownConsumed);
1552*8af74909SZhong Yang 			if (!ret && !lastKeyDownConsumed) {
1553*8af74909SZhong Yang 				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1554*8af74909SZhong Yang 			}
1555*8af74909SZhong Yang 			break;
1556*8af74909SZhong Yang 		}
1557*8af74909SZhong Yang 
1558*8af74909SZhong Yang 	case WM_KEYUP:
1559*8af74909SZhong Yang 		//Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
1560*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1561*8af74909SZhong Yang 
1562*8af74909SZhong Yang 	case WM_CHAR:
1563*8af74909SZhong Yang 		if (((wParam >= 128) || !iscntrl(static_cast<int>(wParam))) || !lastKeyDownConsumed) {
1564*8af74909SZhong Yang 			wchar_t wcs[3] = { static_cast<wchar_t>(wParam), 0 };
1565*8af74909SZhong Yang 			unsigned int wclen = 1;
1566*8af74909SZhong Yang 			if (IS_HIGH_SURROGATE(wcs[0])) {
1567*8af74909SZhong Yang 				// If this is a high surrogate character, we need a second one
1568*8af74909SZhong Yang 				lastHighSurrogateChar = wcs[0];
1569*8af74909SZhong Yang 				return 0;
1570*8af74909SZhong Yang 			} else if (IS_LOW_SURROGATE(wcs[0])) {
1571*8af74909SZhong Yang 				wcs[1] = wcs[0];
1572*8af74909SZhong Yang 				wcs[0] = lastHighSurrogateChar;
1573*8af74909SZhong Yang 				lastHighSurrogateChar = 0;
1574*8af74909SZhong Yang 				wclen = 2;
1575*8af74909SZhong Yang 			}
1576*8af74909SZhong Yang 			AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput);
1577*8af74909SZhong Yang 		}
1578*8af74909SZhong Yang 		return 0;
1579*8af74909SZhong Yang 
1580*8af74909SZhong Yang 	case WM_UNICHAR:
1581*8af74909SZhong Yang 		if (wParam == UNICODE_NOCHAR) {
1582*8af74909SZhong Yang 			return TRUE;
1583*8af74909SZhong Yang 		} else if (lastKeyDownConsumed) {
1584*8af74909SZhong Yang 			return 1;
1585*8af74909SZhong Yang 		} else {
1586*8af74909SZhong Yang 			wchar_t wcs[3] = { 0 };
1587*8af74909SZhong Yang 			const size_t wclen = UTF16FromUTF32Character(static_cast<unsigned int>(wParam), wcs);
1588*8af74909SZhong Yang 			AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput);
1589*8af74909SZhong Yang 			return FALSE;
1590*8af74909SZhong Yang 		}
1591*8af74909SZhong Yang 	}
1592*8af74909SZhong Yang 
1593*8af74909SZhong Yang 	return 0;
1594*8af74909SZhong Yang }
1595*8af74909SZhong Yang 
1596*8af74909SZhong Yang sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) {
1597*8af74909SZhong Yang 	switch (iMessage) {
1598*8af74909SZhong Yang 	case WM_KILLFOCUS: {
1599*8af74909SZhong Yang 		HWND wOther = reinterpret_cast<HWND>(wParam);
1600*8af74909SZhong Yang 		HWND wThis = MainHWND();
1601*8af74909SZhong Yang 		const HWND wCT = HwndFromWindow(ct.wCallTip);
1602*8af74909SZhong Yang 		if (!wParam ||
1603*8af74909SZhong Yang 			!(::IsChild(wThis, wOther) || (wOther == wCT))) {
1604*8af74909SZhong Yang 			SetFocusState(false);
1605*8af74909SZhong Yang 			DestroySystemCaret();
1606*8af74909SZhong Yang 		}
1607*8af74909SZhong Yang 		// Explicitly complete any IME composition
1608*8af74909SZhong Yang 		IMContext imc(MainHWND());
1609*8af74909SZhong Yang 		if (imc.hIMC) {
1610*8af74909SZhong Yang 			::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
1611*8af74909SZhong Yang 		}
1612*8af74909SZhong Yang 		break;
1613*8af74909SZhong Yang 	}
1614*8af74909SZhong Yang 
1615*8af74909SZhong Yang 	case WM_SETFOCUS:
1616*8af74909SZhong Yang 		SetFocusState(true);
1617*8af74909SZhong Yang 		DestroySystemCaret();
1618*8af74909SZhong Yang 		CreateSystemCaret();
1619*8af74909SZhong Yang 		break;
1620*8af74909SZhong Yang 	}
1621*8af74909SZhong Yang 	return 0;
1622*8af74909SZhong Yang }
1623*8af74909SZhong Yang 
1624*8af74909SZhong Yang sptr_t ScintillaWin::IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1625*8af74909SZhong Yang 	switch (iMessage) {
1626*8af74909SZhong Yang 
1627*8af74909SZhong Yang 	case WM_INPUTLANGCHANGE:
1628*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1629*8af74909SZhong Yang 
1630*8af74909SZhong Yang 	case WM_INPUTLANGCHANGEREQUEST:
1631*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1632*8af74909SZhong Yang 
1633*8af74909SZhong Yang 	case WM_IME_KEYDOWN: {
1634*8af74909SZhong Yang 			if (wParam == VK_HANJA) {
1635*8af74909SZhong Yang 				ToggleHanja();
1636*8af74909SZhong Yang 			}
1637*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1638*8af74909SZhong Yang 		}
1639*8af74909SZhong Yang 
1640*8af74909SZhong Yang 	case WM_IME_REQUEST: {
1641*8af74909SZhong Yang 			if (wParam == IMR_RECONVERTSTRING) {
1642*8af74909SZhong Yang 				return ImeOnReconvert(lParam);
1643*8af74909SZhong Yang 			}
1644*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1645*8af74909SZhong Yang 		}
1646*8af74909SZhong Yang 
1647*8af74909SZhong Yang 	case WM_IME_STARTCOMPOSITION:
1648*8af74909SZhong Yang 		if (KoreanIME() || imeInteraction == imeInline) {
1649*8af74909SZhong Yang 			return 0;
1650*8af74909SZhong Yang 		} else {
1651*8af74909SZhong Yang 			ImeStartComposition();
1652*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1653*8af74909SZhong Yang 		}
1654*8af74909SZhong Yang 
1655*8af74909SZhong Yang 	case WM_IME_ENDCOMPOSITION:
1656*8af74909SZhong Yang 		ImeEndComposition();
1657*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1658*8af74909SZhong Yang 
1659*8af74909SZhong Yang 	case WM_IME_COMPOSITION:
1660*8af74909SZhong Yang 		if (KoreanIME() || imeInteraction == imeInline) {
1661*8af74909SZhong Yang 			return HandleCompositionInline(wParam, lParam);
1662*8af74909SZhong Yang 		} else {
1663*8af74909SZhong Yang 			return HandleCompositionWindowed(wParam, lParam);
1664*8af74909SZhong Yang 		}
1665*8af74909SZhong Yang 
1666*8af74909SZhong Yang 	case WM_IME_SETCONTEXT:
1667*8af74909SZhong Yang 		if (KoreanIME() || imeInteraction == imeInline) {
1668*8af74909SZhong Yang 			if (wParam) {
1669*8af74909SZhong Yang 				LPARAM NoImeWin = lParam;
1670*8af74909SZhong Yang 				NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW);
1671*8af74909SZhong Yang 				return ::DefWindowProc(MainHWND(), iMessage, wParam, NoImeWin);
1672*8af74909SZhong Yang 			}
1673*8af74909SZhong Yang 		}
1674*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1675*8af74909SZhong Yang 
1676*8af74909SZhong Yang 	case WM_IME_NOTIFY:
1677*8af74909SZhong Yang 		return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1678*8af74909SZhong Yang 
1679*8af74909SZhong Yang 	}
1680*8af74909SZhong Yang 	return 0;
1681*8af74909SZhong Yang }
1682*8af74909SZhong Yang 
1683*8af74909SZhong Yang sptr_t ScintillaWin::EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1684*8af74909SZhong Yang 	switch (iMessage) {
1685*8af74909SZhong Yang 
1686*8af74909SZhong Yang 	case EM_LINEFROMCHAR:
1687*8af74909SZhong Yang 		if (static_cast<Sci::Position>(wParam) < 0) {
1688*8af74909SZhong Yang 			wParam = SelectionStart().Position();
1689*8af74909SZhong Yang 		}
1690*8af74909SZhong Yang 		return pdoc->LineFromPosition(wParam);
1691*8af74909SZhong Yang 
1692*8af74909SZhong Yang 	case EM_EXLINEFROMCHAR:
1693*8af74909SZhong Yang 		return pdoc->LineFromPosition(lParam);
1694*8af74909SZhong Yang 
1695*8af74909SZhong Yang 	case EM_GETSEL:
1696*8af74909SZhong Yang 		if (wParam) {
1697*8af74909SZhong Yang 			*reinterpret_cast<DWORD *>(wParam) = static_cast<DWORD>(SelectionStart().Position());
1698*8af74909SZhong Yang 		}
1699*8af74909SZhong Yang 		if (lParam) {
1700*8af74909SZhong Yang 			*reinterpret_cast<DWORD *>(lParam) = static_cast<DWORD>(SelectionEnd().Position());
1701*8af74909SZhong Yang 		}
1702*8af74909SZhong Yang 		return MAKELRESULT(SelectionStart().Position(), SelectionEnd().Position());
1703*8af74909SZhong Yang 
1704*8af74909SZhong Yang 	case EM_EXGETSEL: {
1705*8af74909SZhong Yang 			if (lParam == 0) {
1706*8af74909SZhong Yang 				return 0;
1707*8af74909SZhong Yang 			}
1708*8af74909SZhong Yang 			CHARRANGE *pCR = reinterpret_cast<CHARRANGE *>(lParam);
1709*8af74909SZhong Yang 			pCR->cpMin = static_cast<LONG>(SelectionStart().Position());
1710*8af74909SZhong Yang 			pCR->cpMax = static_cast<LONG>(SelectionEnd().Position());
1711*8af74909SZhong Yang 		}
1712*8af74909SZhong Yang 		break;
1713*8af74909SZhong Yang 
1714*8af74909SZhong Yang 	case EM_SETSEL: {
1715*8af74909SZhong Yang 			Sci::Position nStart = wParam;
1716*8af74909SZhong Yang 			Sci::Position nEnd = lParam;
1717*8af74909SZhong Yang 			if (nStart == 0 && nEnd == -1) {
1718*8af74909SZhong Yang 				nEnd = pdoc->Length();
1719*8af74909SZhong Yang 			}
1720*8af74909SZhong Yang 			if (nStart == -1) {
1721*8af74909SZhong Yang 				nStart = nEnd;	// Remove selection
1722*8af74909SZhong Yang 			}
1723*8af74909SZhong Yang 			SetSelection(nEnd, nStart);
1724*8af74909SZhong Yang 			EnsureCaretVisible();
1725*8af74909SZhong Yang 		}
1726*8af74909SZhong Yang 		break;
1727*8af74909SZhong Yang 
1728*8af74909SZhong Yang 	case EM_EXSETSEL: {
1729*8af74909SZhong Yang 			if (lParam == 0) {
1730*8af74909SZhong Yang 				return 0;
1731*8af74909SZhong Yang 			}
1732*8af74909SZhong Yang 			const CHARRANGE *pCR = reinterpret_cast<const CHARRANGE *>(lParam);
1733*8af74909SZhong Yang 			sel.selType = Selection::selStream;
1734*8af74909SZhong Yang 			if (pCR->cpMin == 0 && pCR->cpMax == -1) {
1735*8af74909SZhong Yang 				SetSelection(pCR->cpMin, pdoc->Length());
1736*8af74909SZhong Yang 			} else {
1737*8af74909SZhong Yang 				SetSelection(pCR->cpMin, pCR->cpMax);
1738*8af74909SZhong Yang 			}
1739*8af74909SZhong Yang 			EnsureCaretVisible();
1740*8af74909SZhong Yang 			return pdoc->LineFromPosition(SelectionStart().Position());
1741*8af74909SZhong Yang 		}
1742*8af74909SZhong Yang 	}
1743*8af74909SZhong Yang 	return 0;
1744*8af74909SZhong Yang }
1745*8af74909SZhong Yang 
1746*8af74909SZhong Yang sptr_t ScintillaWin::IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1747*8af74909SZhong Yang 	switch (iMessage) {
1748*8af74909SZhong Yang 	case SC_WIN_IDLE:
1749*8af74909SZhong Yang 		// wParam=dwTickCountInitial, or 0 to initialize.  lParam=bSkipUserInputTest
1750*8af74909SZhong Yang 		if (idler.state) {
1751*8af74909SZhong Yang 			if (lParam || (WAIT_TIMEOUT == MsgWaitForMultipleObjects(0, nullptr, 0, 0, QS_INPUT | QS_HOTKEY))) {
1752*8af74909SZhong Yang 				if (Idle()) {
1753*8af74909SZhong Yang 					// User input was given priority above, but all events do get a turn.  Other
1754*8af74909SZhong Yang 					// messages, notifications, etc. will get interleaved with the idle messages.
1755*8af74909SZhong Yang 
1756*8af74909SZhong Yang 					// However, some things like WM_PAINT are a lower priority, and will not fire
1757*8af74909SZhong Yang 					// when there's a message posted.  So, several times a second, we stop and let
1758*8af74909SZhong Yang 					// the low priority events have a turn (after which the timer will fire again).
1759*8af74909SZhong Yang 
1760*8af74909SZhong Yang 					// Suppress a warning from Code Analysis that the GetTickCount function
1761*8af74909SZhong Yang 					// wraps after 49 days. The WM_TIMER will kick off another SC_WIN_IDLE
1762*8af74909SZhong Yang 					// after the wrap.
1763*8af74909SZhong Yang #ifdef _MSC_VER
1764*8af74909SZhong Yang #pragma warning(suppress: 28159)
1765*8af74909SZhong Yang #endif
1766*8af74909SZhong Yang 					const DWORD dwCurrent = GetTickCount();
1767*8af74909SZhong Yang 					const DWORD dwStart = wParam ? static_cast<DWORD>(wParam) : dwCurrent;
1768*8af74909SZhong Yang 					constexpr DWORD maxWorkTime = 50;
1769*8af74909SZhong Yang 
1770*8af74909SZhong Yang 					if (dwCurrent >= dwStart && dwCurrent > maxWorkTime &&dwCurrent - maxWorkTime < dwStart)
1771*8af74909SZhong Yang 						PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0);
1772*8af74909SZhong Yang 				} else {
1773*8af74909SZhong Yang 					SetIdle(false);
1774*8af74909SZhong Yang 				}
1775*8af74909SZhong Yang 			}
1776*8af74909SZhong Yang 		}
1777*8af74909SZhong Yang 		break;
1778*8af74909SZhong Yang 
1779*8af74909SZhong Yang 	case SC_WORK_IDLE:
1780*8af74909SZhong Yang 		IdleWork();
1781*8af74909SZhong Yang 		break;
1782*8af74909SZhong Yang 	}
1783*8af74909SZhong Yang 	return 0;
1784*8af74909SZhong Yang }
1785*8af74909SZhong Yang 
1786*8af74909SZhong Yang sptr_t ScintillaWin::SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1787*8af74909SZhong Yang 	switch (iMessage) {
1788*8af74909SZhong Yang 	case SCI_GETDIRECTFUNCTION:
1789*8af74909SZhong Yang 		return reinterpret_cast<sptr_t>(DirectFunction);
1790*8af74909SZhong Yang 
1791*8af74909SZhong Yang 	case SCI_GETDIRECTPOINTER:
1792*8af74909SZhong Yang 		return reinterpret_cast<sptr_t>(this);
1793*8af74909SZhong Yang 
1794*8af74909SZhong Yang 	case SCI_GRABFOCUS:
1795*8af74909SZhong Yang 		::SetFocus(MainHWND());
1796*8af74909SZhong Yang 		break;
1797*8af74909SZhong Yang 
1798*8af74909SZhong Yang #ifdef INCLUDE_DEPRECATED_FEATURES
1799*8af74909SZhong Yang 	case SCI_SETKEYSUNICODE:
1800*8af74909SZhong Yang 		break;
1801*8af74909SZhong Yang 
1802*8af74909SZhong Yang 	case SCI_GETKEYSUNICODE:
1803*8af74909SZhong Yang 		return true;
1804*8af74909SZhong Yang #endif
1805*8af74909SZhong Yang 
1806*8af74909SZhong Yang 	case SCI_SETTECHNOLOGY:
1807*8af74909SZhong Yang 		if ((wParam == SC_TECHNOLOGY_DEFAULT) ||
1808*8af74909SZhong Yang 			(wParam == SC_TECHNOLOGY_DIRECTWRITERETAIN) ||
1809*8af74909SZhong Yang 			(wParam == SC_TECHNOLOGY_DIRECTWRITEDC) ||
1810*8af74909SZhong Yang 			(wParam == SC_TECHNOLOGY_DIRECTWRITE)) {
1811*8af74909SZhong Yang 			const int technologyNew = static_cast<int>(wParam);
1812*8af74909SZhong Yang 			if (technology != technologyNew) {
1813*8af74909SZhong Yang 				if (technologyNew > SC_TECHNOLOGY_DEFAULT) {
1814*8af74909SZhong Yang #if defined(USE_D2D)
1815*8af74909SZhong Yang 					if (!LoadD2D())
1816*8af74909SZhong Yang 						// Failed to load Direct2D or DirectWrite so no effect
1817*8af74909SZhong Yang 						return 0;
1818*8af74909SZhong Yang #else
1819*8af74909SZhong Yang 					return 0;
1820*8af74909SZhong Yang #endif
1821*8af74909SZhong Yang 				} else {
1822*8af74909SZhong Yang 					bidirectional = EditModel::Bidirectional::bidiDisabled;
1823*8af74909SZhong Yang 				}
1824*8af74909SZhong Yang #if defined(USE_D2D)
1825*8af74909SZhong Yang 				DropRenderTarget();
1826*8af74909SZhong Yang #endif
1827*8af74909SZhong Yang 				technology = technologyNew;
1828*8af74909SZhong Yang 				// Invalidate all cached information including layout.
1829*8af74909SZhong Yang 				DropGraphics(true);
1830*8af74909SZhong Yang 				InvalidateStyleRedraw();
1831*8af74909SZhong Yang 			}
1832*8af74909SZhong Yang 		}
1833*8af74909SZhong Yang 		break;
1834*8af74909SZhong Yang 
1835*8af74909SZhong Yang 	case SCI_SETBIDIRECTIONAL:
1836*8af74909SZhong Yang 		if (technology == SC_TECHNOLOGY_DEFAULT) {
1837*8af74909SZhong Yang 			bidirectional = EditModel::Bidirectional::bidiDisabled;
1838*8af74909SZhong Yang 		} else if (wParam <= SC_BIDIRECTIONAL_R2L) {
1839*8af74909SZhong Yang 			bidirectional = static_cast<EditModel::Bidirectional>(wParam);
1840*8af74909SZhong Yang 		}
1841*8af74909SZhong Yang 		// Invalidate all cached information including layout.
1842*8af74909SZhong Yang 		DropGraphics(true);
1843*8af74909SZhong Yang 		InvalidateStyleRedraw();
1844*8af74909SZhong Yang 		break;
1845*8af74909SZhong Yang 
1846*8af74909SZhong Yang 	case SCI_TARGETASUTF8:
1847*8af74909SZhong Yang 		return TargetAsUTF8(CharPtrFromSPtr(lParam));
1848*8af74909SZhong Yang 
1849*8af74909SZhong Yang 	case SCI_ENCODEDFROMUTF8:
1850*8af74909SZhong Yang 		return EncodedFromUTF8(ConstCharPtrFromUPtr(wParam),
1851*8af74909SZhong Yang 			CharPtrFromSPtr(lParam));
1852*8af74909SZhong Yang 
1853*8af74909SZhong Yang 	}
1854*8af74909SZhong Yang 	return 0;
1855*8af74909SZhong Yang }
1856*8af74909SZhong Yang 
1857*8af74909SZhong Yang sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1858*8af74909SZhong Yang 	try {
1859*8af74909SZhong Yang 		//Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
1860*8af74909SZhong Yang 		iMessage = SciMessageFromEM(iMessage);
1861*8af74909SZhong Yang 		switch (iMessage) {
1862*8af74909SZhong Yang 
1863*8af74909SZhong Yang 		case WM_CREATE:
1864*8af74909SZhong Yang 			ctrlID = ::GetDlgCtrlID(HwndFromWindow(wMain));
1865*8af74909SZhong Yang 			// Get Intellimouse scroll line parameters
1866*8af74909SZhong Yang 			GetIntelliMouseParameters();
1867*8af74909SZhong Yang 			::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget *>(&dt));
1868*8af74909SZhong Yang 			break;
1869*8af74909SZhong Yang 
1870*8af74909SZhong Yang 		case WM_COMMAND:
1871*8af74909SZhong Yang 			Command(LOWORD(wParam));
1872*8af74909SZhong Yang 			break;
1873*8af74909SZhong Yang 
1874*8af74909SZhong Yang 		case WM_PAINT:
1875*8af74909SZhong Yang 			return WndPaint();
1876*8af74909SZhong Yang 
1877*8af74909SZhong Yang 		case WM_PRINTCLIENT: {
1878*8af74909SZhong Yang 				HDC hdc = reinterpret_cast<HDC>(wParam);
1879*8af74909SZhong Yang 				if (!IsCompatibleDC(hdc)) {
1880*8af74909SZhong Yang 					return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1881*8af74909SZhong Yang 				}
1882*8af74909SZhong Yang 				FullPaintDC(hdc);
1883*8af74909SZhong Yang 			}
1884*8af74909SZhong Yang 			break;
1885*8af74909SZhong Yang 
1886*8af74909SZhong Yang 		case WM_VSCROLL:
1887*8af74909SZhong Yang 			ScrollMessage(wParam);
1888*8af74909SZhong Yang 			break;
1889*8af74909SZhong Yang 
1890*8af74909SZhong Yang 		case WM_HSCROLL:
1891*8af74909SZhong Yang 			HorizontalScrollMessage(wParam);
1892*8af74909SZhong Yang 			break;
1893*8af74909SZhong Yang 
1894*8af74909SZhong Yang 		case WM_SIZE:
1895*8af74909SZhong Yang 			SizeWindow();
1896*8af74909SZhong Yang 			break;
1897*8af74909SZhong Yang 
1898*8af74909SZhong Yang 		case WM_TIMER:
1899*8af74909SZhong Yang 			if (wParam == idleTimerID && idler.state) {
1900*8af74909SZhong Yang 				SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);
1901*8af74909SZhong Yang 			} else {
1902*8af74909SZhong Yang 				TickFor(static_cast<TickReason>(wParam - fineTimerStart));
1903*8af74909SZhong Yang 			}
1904*8af74909SZhong Yang 			break;
1905*8af74909SZhong Yang 
1906*8af74909SZhong Yang 		case SC_WIN_IDLE:
1907*8af74909SZhong Yang 		case SC_WORK_IDLE:
1908*8af74909SZhong Yang 			return IdleMessage(iMessage, wParam, lParam);
1909*8af74909SZhong Yang 
1910*8af74909SZhong Yang 		case WM_GETMINMAXINFO:
1911*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1912*8af74909SZhong Yang 
1913*8af74909SZhong Yang 		case WM_LBUTTONDOWN:
1914*8af74909SZhong Yang 		case WM_LBUTTONUP:
1915*8af74909SZhong Yang 		case WM_RBUTTONDOWN:
1916*8af74909SZhong Yang 		case WM_MOUSEMOVE:
1917*8af74909SZhong Yang 		case WM_MOUSELEAVE:
1918*8af74909SZhong Yang 		case WM_MOUSEWHEEL:
1919*8af74909SZhong Yang 			return MouseMessage(iMessage, wParam, lParam);
1920*8af74909SZhong Yang 
1921*8af74909SZhong Yang 		case WM_SETCURSOR:
1922*8af74909SZhong Yang 			if (LOWORD(lParam) == HTCLIENT) {
1923*8af74909SZhong Yang 				POINT pt;
1924*8af74909SZhong Yang 				if (::GetCursorPos(&pt)) {
1925*8af74909SZhong Yang 					::ScreenToClient(MainHWND(), &pt);
1926*8af74909SZhong Yang 					DisplayCursor(ContextCursor(PointFromPOINT(pt)));
1927*8af74909SZhong Yang 				}
1928*8af74909SZhong Yang 				return TRUE;
1929*8af74909SZhong Yang 			} else {
1930*8af74909SZhong Yang 				return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1931*8af74909SZhong Yang 			}
1932*8af74909SZhong Yang 
1933*8af74909SZhong Yang 		case WM_SYSKEYDOWN:
1934*8af74909SZhong Yang 		case WM_KEYDOWN:
1935*8af74909SZhong Yang 		case WM_KEYUP:
1936*8af74909SZhong Yang 		case WM_CHAR:
1937*8af74909SZhong Yang 		case WM_UNICHAR:
1938*8af74909SZhong Yang 			return KeyMessage(iMessage, wParam, lParam);
1939*8af74909SZhong Yang 
1940*8af74909SZhong Yang 		case WM_SETTINGCHANGE:
1941*8af74909SZhong Yang 			//Platform::DebugPrintf("Setting Changed\n");
1942*8af74909SZhong Yang 			InvalidateStyleData();
1943*8af74909SZhong Yang 			// Get Intellimouse scroll line parameters
1944*8af74909SZhong Yang 			GetIntelliMouseParameters();
1945*8af74909SZhong Yang 			break;
1946*8af74909SZhong Yang 
1947*8af74909SZhong Yang 		case WM_GETDLGCODE:
1948*8af74909SZhong Yang 			return DLGC_HASSETSEL | DLGC_WANTALLKEYS;
1949*8af74909SZhong Yang 
1950*8af74909SZhong Yang 		case WM_KILLFOCUS:
1951*8af74909SZhong Yang 		case WM_SETFOCUS:
1952*8af74909SZhong Yang 			return FocusMessage(iMessage, wParam, lParam);
1953*8af74909SZhong Yang 
1954*8af74909SZhong Yang 		case WM_SYSCOLORCHANGE:
1955*8af74909SZhong Yang 			//Platform::DebugPrintf("Setting Changed\n");
1956*8af74909SZhong Yang 			InvalidateStyleData();
1957*8af74909SZhong Yang 			break;
1958*8af74909SZhong Yang 
1959*8af74909SZhong Yang 		case WM_DPICHANGED:
1960*8af74909SZhong Yang 			dpi = HIWORD(wParam);
1961*8af74909SZhong Yang 			InvalidateStyleRedraw();
1962*8af74909SZhong Yang 			break;
1963*8af74909SZhong Yang 
1964*8af74909SZhong Yang 		case WM_DPICHANGED_AFTERPARENT: {
1965*8af74909SZhong Yang 				const UINT dpiNow = DpiForWindow(wMain.GetID());
1966*8af74909SZhong Yang 				if (dpi != dpiNow) {
1967*8af74909SZhong Yang 					dpi = dpiNow;
1968*8af74909SZhong Yang 					InvalidateStyleRedraw();
1969*8af74909SZhong Yang 				}
1970*8af74909SZhong Yang 			}
1971*8af74909SZhong Yang 			break;
1972*8af74909SZhong Yang 
1973*8af74909SZhong Yang 		case WM_CONTEXTMENU:
1974*8af74909SZhong Yang 			return ShowContextMenu(iMessage, wParam, lParam);
1975*8af74909SZhong Yang 
1976*8af74909SZhong Yang 		case WM_ERASEBKGND:
1977*8af74909SZhong Yang 			return 1;   // Avoid any background erasure as whole window painted.
1978*8af74909SZhong Yang 
1979*8af74909SZhong Yang 		case WM_CAPTURECHANGED:
1980*8af74909SZhong Yang 			capturedMouse = false;
1981*8af74909SZhong Yang 			return 0;
1982*8af74909SZhong Yang 
1983*8af74909SZhong Yang 		// These are not handled in Scintilla and its faster to dispatch them here.
1984*8af74909SZhong Yang 		// Also moves time out to here so profile doesn't count lots of empty message calls.
1985*8af74909SZhong Yang 
1986*8af74909SZhong Yang 		case WM_MOVE:
1987*8af74909SZhong Yang 		case WM_MOUSEACTIVATE:
1988*8af74909SZhong Yang 		case WM_NCHITTEST:
1989*8af74909SZhong Yang 		case WM_NCCALCSIZE:
1990*8af74909SZhong Yang 		case WM_NCPAINT:
1991*8af74909SZhong Yang 		case WM_NCMOUSEMOVE:
1992*8af74909SZhong Yang 		case WM_NCLBUTTONDOWN:
1993*8af74909SZhong Yang 		case WM_SYSCOMMAND:
1994*8af74909SZhong Yang 		case WM_WINDOWPOSCHANGING:
1995*8af74909SZhong Yang 		case WM_WINDOWPOSCHANGED:
1996*8af74909SZhong Yang 			return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
1997*8af74909SZhong Yang 
1998*8af74909SZhong Yang 		case WM_GETTEXTLENGTH:
1999*8af74909SZhong Yang 			return GetTextLength();
2000*8af74909SZhong Yang 
2001*8af74909SZhong Yang 		case WM_GETTEXT:
2002*8af74909SZhong Yang 			return GetText(wParam, lParam);
2003*8af74909SZhong Yang 
2004*8af74909SZhong Yang 		case WM_INPUTLANGCHANGE:
2005*8af74909SZhong Yang 		case WM_INPUTLANGCHANGEREQUEST:
2006*8af74909SZhong Yang 		case WM_IME_KEYDOWN:
2007*8af74909SZhong Yang 		case WM_IME_REQUEST:
2008*8af74909SZhong Yang 		case WM_IME_STARTCOMPOSITION:
2009*8af74909SZhong Yang 		case WM_IME_ENDCOMPOSITION:
2010*8af74909SZhong Yang 		case WM_IME_COMPOSITION:
2011*8af74909SZhong Yang 		case WM_IME_SETCONTEXT:
2012*8af74909SZhong Yang 		case WM_IME_NOTIFY:
2013*8af74909SZhong Yang 			return IMEMessage(iMessage, wParam, lParam);
2014*8af74909SZhong Yang 
2015*8af74909SZhong Yang 		case EM_LINEFROMCHAR:
2016*8af74909SZhong Yang 		case EM_EXLINEFROMCHAR:
2017*8af74909SZhong Yang 		case EM_GETSEL:
2018*8af74909SZhong Yang 		case EM_EXGETSEL:
2019*8af74909SZhong Yang 		case EM_SETSEL:
2020*8af74909SZhong Yang 		case EM_EXSETSEL:
2021*8af74909SZhong Yang 			return EditMessage(iMessage, wParam, lParam);
2022*8af74909SZhong Yang 
2023*8af74909SZhong Yang 		case SCI_GETDIRECTFUNCTION:
2024*8af74909SZhong Yang 		case SCI_GETDIRECTPOINTER:
2025*8af74909SZhong Yang 		case SCI_GRABFOCUS:
2026*8af74909SZhong Yang #ifdef INCLUDE_DEPRECATED_FEATURES
2027*8af74909SZhong Yang 		case SCI_SETKEYSUNICODE:
2028*8af74909SZhong Yang 		case SCI_GETKEYSUNICODE:
2029*8af74909SZhong Yang #endif
2030*8af74909SZhong Yang 		case SCI_SETTECHNOLOGY:
2031*8af74909SZhong Yang 		case SCI_SETBIDIRECTIONAL:
2032*8af74909SZhong Yang 		case SCI_TARGETASUTF8:
2033*8af74909SZhong Yang 		case SCI_ENCODEDFROMUTF8:
2034*8af74909SZhong Yang 			return SciMessage(iMessage, wParam, lParam);
2035*8af74909SZhong Yang 
2036*8af74909SZhong Yang 		default:
2037*8af74909SZhong Yang 			return ScintillaBase::WndProc(iMessage, wParam, lParam);
2038*8af74909SZhong Yang 		}
2039*8af74909SZhong Yang 	} catch (std::bad_alloc &) {
2040*8af74909SZhong Yang 		errorStatus = SC_STATUS_BADALLOC;
2041*8af74909SZhong Yang 	} catch (...) {
2042*8af74909SZhong Yang 		errorStatus = SC_STATUS_FAILURE;
2043*8af74909SZhong Yang 	}
2044*8af74909SZhong Yang 	return 0;
2045*8af74909SZhong Yang }
2046*8af74909SZhong Yang 
2047*8af74909SZhong Yang bool ScintillaWin::ValidCodePage(int codePage) const {
2048*8af74909SZhong Yang 	return codePage == 0 || codePage == SC_CP_UTF8 ||
2049*8af74909SZhong Yang 	       codePage == 932 || codePage == 936 || codePage == 949 ||
2050*8af74909SZhong Yang 	       codePage == 950 || codePage == 1361;
2051*8af74909SZhong Yang }
2052*8af74909SZhong Yang 
2053*8af74909SZhong Yang sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2054*8af74909SZhong Yang 	return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
2055*8af74909SZhong Yang }
2056*8af74909SZhong Yang 
2057*8af74909SZhong Yang bool ScintillaWin::FineTickerRunning(TickReason reason) {
2058*8af74909SZhong Yang 	return timers[reason] != 0;
2059*8af74909SZhong Yang }
2060*8af74909SZhong Yang 
2061*8af74909SZhong Yang void ScintillaWin::FineTickerStart(TickReason reason, int millis, int tolerance) {
2062*8af74909SZhong Yang 	FineTickerCancel(reason);
2063*8af74909SZhong Yang 	const UINT_PTR eventID = static_cast<UINT_PTR>(fineTimerStart) + reason;
2064*8af74909SZhong Yang 	if (SetCoalescableTimerFn && tolerance) {
2065*8af74909SZhong Yang 		timers[reason] = SetCoalescableTimerFn(MainHWND(), eventID, millis, nullptr, tolerance);
2066*8af74909SZhong Yang 	} else {
2067*8af74909SZhong Yang 		timers[reason] = ::SetTimer(MainHWND(), eventID, millis, nullptr);
2068*8af74909SZhong Yang 	}
2069*8af74909SZhong Yang }
2070*8af74909SZhong Yang 
2071*8af74909SZhong Yang void ScintillaWin::FineTickerCancel(TickReason reason) {
2072*8af74909SZhong Yang 	if (timers[reason]) {
2073*8af74909SZhong Yang 		::KillTimer(MainHWND(), timers[reason]);
2074*8af74909SZhong Yang 		timers[reason] = 0;
2075*8af74909SZhong Yang 	}
2076*8af74909SZhong Yang }
2077*8af74909SZhong Yang 
2078*8af74909SZhong Yang 
2079*8af74909SZhong Yang bool ScintillaWin::SetIdle(bool on) {
2080*8af74909SZhong Yang 	// On Win32 the Idler is implemented as a Timer on the Scintilla window.  This
2081*8af74909SZhong Yang 	// takes advantage of the fact that WM_TIMER messages are very low priority,
2082*8af74909SZhong Yang 	// and are only posted when the message queue is empty, i.e. during idle time.
2083*8af74909SZhong Yang 	if (idler.state != on) {
2084*8af74909SZhong Yang 		if (on) {
2085*8af74909SZhong Yang 			idler.idlerID = ::SetTimer(MainHWND(), idleTimerID, 10, nullptr)
2086*8af74909SZhong Yang 				? reinterpret_cast<IdlerID>(idleTimerID) : 0;
2087*8af74909SZhong Yang 		} else {
2088*8af74909SZhong Yang 			::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(idler.idlerID));
2089*8af74909SZhong Yang 			idler.idlerID = 0;
2090*8af74909SZhong Yang 		}
2091*8af74909SZhong Yang 		idler.state = idler.idlerID != 0;
2092*8af74909SZhong Yang 	}
2093*8af74909SZhong Yang 	return idler.state;
2094*8af74909SZhong Yang }
2095*8af74909SZhong Yang 
2096*8af74909SZhong Yang void ScintillaWin::IdleWork() {
2097*8af74909SZhong Yang 	styleIdleInQueue = false;
2098*8af74909SZhong Yang 	Editor::IdleWork();
2099*8af74909SZhong Yang }
2100*8af74909SZhong Yang 
2101*8af74909SZhong Yang void ScintillaWin::QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) {
2102*8af74909SZhong Yang 	Editor::QueueIdleWork(items, upTo);
2103*8af74909SZhong Yang 	if (!styleIdleInQueue) {
2104*8af74909SZhong Yang 		if (PostMessage(MainHWND(), SC_WORK_IDLE, 0, 0)) {
2105*8af74909SZhong Yang 			styleIdleInQueue = true;
2106*8af74909SZhong Yang 		}
2107*8af74909SZhong Yang 	}
2108*8af74909SZhong Yang }
2109*8af74909SZhong Yang 
2110*8af74909SZhong Yang void ScintillaWin::SetMouseCapture(bool on) {
2111*8af74909SZhong Yang 	if (mouseDownCaptures) {
2112*8af74909SZhong Yang 		if (on) {
2113*8af74909SZhong Yang 			::SetCapture(MainHWND());
2114*8af74909SZhong Yang 		} else {
2115*8af74909SZhong Yang 			::ReleaseCapture();
2116*8af74909SZhong Yang 		}
2117*8af74909SZhong Yang 	}
2118*8af74909SZhong Yang 	capturedMouse = on;
2119*8af74909SZhong Yang }
2120*8af74909SZhong Yang 
2121*8af74909SZhong Yang bool ScintillaWin::HaveMouseCapture() {
2122*8af74909SZhong Yang 	// Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
2123*8af74909SZhong Yang 	return capturedMouse;
2124*8af74909SZhong Yang 	//return capturedMouse && (::GetCapture() == MainHWND());
2125*8af74909SZhong Yang }
2126*8af74909SZhong Yang 
2127*8af74909SZhong Yang void ScintillaWin::SetTrackMouseLeaveEvent(bool on) noexcept {
2128*8af74909SZhong Yang 	if (on && !trackedMouseLeave) {
2129*8af74909SZhong Yang 		TRACKMOUSEEVENT tme;
2130*8af74909SZhong Yang 		tme.cbSize = sizeof(tme);
2131*8af74909SZhong Yang 		tme.dwFlags = TME_LEAVE;
2132*8af74909SZhong Yang 		tme.hwndTrack = MainHWND();
2133*8af74909SZhong Yang 		tme.dwHoverTime = HOVER_DEFAULT;	// Unused but triggers Dr. Memory if not initialized
2134*8af74909SZhong Yang 		TrackMouseEvent(&tme);
2135*8af74909SZhong Yang 	}
2136*8af74909SZhong Yang 	trackedMouseLeave = on;
2137*8af74909SZhong Yang }
2138*8af74909SZhong Yang 
2139*8af74909SZhong Yang bool ScintillaWin::PaintContains(PRectangle rc) {
2140*8af74909SZhong Yang 	if (paintState == painting) {
2141*8af74909SZhong Yang 		return BoundsContains(rcPaint, hRgnUpdate, rc);
2142*8af74909SZhong Yang 	}
2143*8af74909SZhong Yang 	return true;
2144*8af74909SZhong Yang }
2145*8af74909SZhong Yang 
2146*8af74909SZhong Yang void ScintillaWin::ScrollText(Sci::Line /* linesToMove */) {
2147*8af74909SZhong Yang 	//Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
2148*8af74909SZhong Yang 	//::ScrollWindow(MainHWND(), 0,
2149*8af74909SZhong Yang 	//	vs.lineHeight * linesToMove, 0, 0);
2150*8af74909SZhong Yang 	//::UpdateWindow(MainHWND());
2151*8af74909SZhong Yang 	Redraw();
2152*8af74909SZhong Yang 	UpdateSystemCaret();
2153*8af74909SZhong Yang }
2154*8af74909SZhong Yang 
2155*8af74909SZhong Yang void ScintillaWin::NotifyCaretMove() {
2156*8af74909SZhong Yang 	NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, MainHWND(), OBJID_CARET, CHILDID_SELF);
2157*8af74909SZhong Yang }
2158*8af74909SZhong Yang 
2159*8af74909SZhong Yang void ScintillaWin::UpdateSystemCaret() {
2160*8af74909SZhong Yang 	if (hasFocus) {
2161*8af74909SZhong Yang 		if (pdoc->TentativeActive()) {
2162*8af74909SZhong Yang 			// ongoing inline mode IME composition, don't inform IME of system caret position.
2163*8af74909SZhong Yang 			// fix candidate window for Google Japanese IME moved on typing on Win7.
2164*8af74909SZhong Yang 			return;
2165*8af74909SZhong Yang 		}
2166*8af74909SZhong Yang 		if (HasCaretSizeChanged()) {
2167*8af74909SZhong Yang 			DestroySystemCaret();
2168*8af74909SZhong Yang 			CreateSystemCaret();
2169*8af74909SZhong Yang 		}
2170*8af74909SZhong Yang 		const Point pos = PointMainCaret();
2171*8af74909SZhong Yang 		::SetCaretPos(static_cast<int>(pos.x), static_cast<int>(pos.y));
2172*8af74909SZhong Yang 	}
2173*8af74909SZhong Yang }
2174*8af74909SZhong Yang 
2175*8af74909SZhong Yang int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept {
2176*8af74909SZhong Yang 	return ::SetScrollInfo(MainHWND(), nBar, lpsi, bRedraw);
2177*8af74909SZhong Yang }
2178*8af74909SZhong Yang 
2179*8af74909SZhong Yang bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept {
2180*8af74909SZhong Yang 	return ::GetScrollInfo(MainHWND(), nBar, lpsi) ? true : false;
2181*8af74909SZhong Yang }
2182*8af74909SZhong Yang 
2183*8af74909SZhong Yang // Change the scroll position but avoid repaint if changing to same value
2184*8af74909SZhong Yang void ScintillaWin::ChangeScrollPos(int barType, Sci::Position pos) {
2185*8af74909SZhong Yang 	SCROLLINFO sci = {
2186*8af74909SZhong Yang 		sizeof(sci), 0, 0, 0, 0, 0, 0
2187*8af74909SZhong Yang 	};
2188*8af74909SZhong Yang 	sci.fMask = SIF_POS;
2189*8af74909SZhong Yang 	GetScrollInfo(barType, &sci);
2190*8af74909SZhong Yang 	if (sci.nPos != pos) {
2191*8af74909SZhong Yang 		DwellEnd(true);
2192*8af74909SZhong Yang 		sci.nPos = static_cast<int>(pos);
2193*8af74909SZhong Yang 		SetScrollInfo(barType, &sci, TRUE);
2194*8af74909SZhong Yang 	}
2195*8af74909SZhong Yang }
2196*8af74909SZhong Yang 
2197*8af74909SZhong Yang void ScintillaWin::SetVerticalScrollPos() {
2198*8af74909SZhong Yang 	ChangeScrollPos(SB_VERT, topLine);
2199*8af74909SZhong Yang }
2200*8af74909SZhong Yang 
2201*8af74909SZhong Yang void ScintillaWin::SetHorizontalScrollPos() {
2202*8af74909SZhong Yang 	ChangeScrollPos(SB_HORZ, xOffset);
2203*8af74909SZhong Yang }
2204*8af74909SZhong Yang 
2205*8af74909SZhong Yang bool ScintillaWin::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) {
2206*8af74909SZhong Yang 	bool modified = false;
2207*8af74909SZhong Yang 	SCROLLINFO sci = {
2208*8af74909SZhong Yang 		sizeof(sci), 0, 0, 0, 0, 0, 0
2209*8af74909SZhong Yang 	};
2210*8af74909SZhong Yang 	sci.fMask = SIF_PAGE | SIF_RANGE;
2211*8af74909SZhong Yang 	GetScrollInfo(SB_VERT, &sci);
2212*8af74909SZhong Yang 	const Sci::Line vertEndPreferred = nMax;
2213*8af74909SZhong Yang 	if (!verticalScrollBarVisible)
2214*8af74909SZhong Yang 		nPage = vertEndPreferred + 1;
2215*8af74909SZhong Yang 	if ((sci.nMin != 0) ||
2216*8af74909SZhong Yang 		(sci.nMax != vertEndPreferred) ||
2217*8af74909SZhong Yang 	        (sci.nPage != static_cast<unsigned int>(nPage)) ||
2218*8af74909SZhong Yang 	        (sci.nPos != 0)) {
2219*8af74909SZhong Yang 		sci.fMask = SIF_PAGE | SIF_RANGE;
2220*8af74909SZhong Yang 		sci.nMin = 0;
2221*8af74909SZhong Yang 		sci.nMax = static_cast<int>(vertEndPreferred);
2222*8af74909SZhong Yang 		sci.nPage = static_cast<UINT>(nPage);
2223*8af74909SZhong Yang 		sci.nPos = 0;
2224*8af74909SZhong Yang 		sci.nTrackPos = 1;
2225*8af74909SZhong Yang 		SetScrollInfo(SB_VERT, &sci, TRUE);
2226*8af74909SZhong Yang 		modified = true;
2227*8af74909SZhong Yang 	}
2228*8af74909SZhong Yang 
2229*8af74909SZhong Yang 	const PRectangle rcText = GetTextRectangle();
2230*8af74909SZhong Yang 	int horizEndPreferred = scrollWidth;
2231*8af74909SZhong Yang 	if (horizEndPreferred < 0)
2232*8af74909SZhong Yang 		horizEndPreferred = 0;
2233*8af74909SZhong Yang 	int pageWidth = static_cast<int>(rcText.Width());
2234*8af74909SZhong Yang 	if (!horizontalScrollBarVisible || Wrapping())
2235*8af74909SZhong Yang 		pageWidth = horizEndPreferred + 1;
2236*8af74909SZhong Yang 	sci.fMask = SIF_PAGE | SIF_RANGE;
2237*8af74909SZhong Yang 	GetScrollInfo(SB_HORZ, &sci);
2238*8af74909SZhong Yang 	if ((sci.nMin != 0) ||
2239*8af74909SZhong Yang 		(sci.nMax != horizEndPreferred) ||
2240*8af74909SZhong Yang 		(sci.nPage != static_cast<unsigned int>(pageWidth)) ||
2241*8af74909SZhong Yang 	        (sci.nPos != 0)) {
2242*8af74909SZhong Yang 		sci.fMask = SIF_PAGE | SIF_RANGE;
2243*8af74909SZhong Yang 		sci.nMin = 0;
2244*8af74909SZhong Yang 		sci.nMax = horizEndPreferred;
2245*8af74909SZhong Yang 		sci.nPage = pageWidth;
2246*8af74909SZhong Yang 		sci.nPos = 0;
2247*8af74909SZhong Yang 		sci.nTrackPos = 1;
2248*8af74909SZhong Yang 		SetScrollInfo(SB_HORZ, &sci, TRUE);
2249*8af74909SZhong Yang 		modified = true;
2250*8af74909SZhong Yang 		if (scrollWidth < pageWidth) {
2251*8af74909SZhong Yang 			HorizontalScrollTo(0);
2252*8af74909SZhong Yang 		}
2253*8af74909SZhong Yang 	}
2254*8af74909SZhong Yang 	return modified;
2255*8af74909SZhong Yang }
2256*8af74909SZhong Yang 
2257*8af74909SZhong Yang void ScintillaWin::NotifyChange() {
2258*8af74909SZhong Yang 	::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
2259*8af74909SZhong Yang 	        MAKEWPARAM(GetCtrlID(), SCEN_CHANGE),
2260*8af74909SZhong Yang 		reinterpret_cast<LPARAM>(MainHWND()));
2261*8af74909SZhong Yang }
2262*8af74909SZhong Yang 
2263*8af74909SZhong Yang void ScintillaWin::NotifyFocus(bool focus) {
2264*8af74909SZhong Yang 	if (commandEvents) {
2265*8af74909SZhong Yang 		::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
2266*8af74909SZhong Yang 			MAKEWPARAM(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS),
2267*8af74909SZhong Yang 			reinterpret_cast<LPARAM>(MainHWND()));
2268*8af74909SZhong Yang 	}
2269*8af74909SZhong Yang 	Editor::NotifyFocus(focus);
2270*8af74909SZhong Yang }
2271*8af74909SZhong Yang 
2272*8af74909SZhong Yang void ScintillaWin::SetCtrlID(int identifier) {
2273*8af74909SZhong Yang 	::SetWindowID(HwndFromWindow(wMain), identifier);
2274*8af74909SZhong Yang }
2275*8af74909SZhong Yang 
2276*8af74909SZhong Yang int ScintillaWin::GetCtrlID() {
2277*8af74909SZhong Yang 	return ::GetDlgCtrlID(HwndFromWindow(wMain));
2278*8af74909SZhong Yang }
2279*8af74909SZhong Yang 
2280*8af74909SZhong Yang void ScintillaWin::NotifyParent(SCNotification scn) {
2281*8af74909SZhong Yang 	scn.nmhdr.hwndFrom = MainHWND();
2282*8af74909SZhong Yang 	scn.nmhdr.idFrom = GetCtrlID();
2283*8af74909SZhong Yang 	::SendMessage(::GetParent(MainHWND()), WM_NOTIFY,
2284*8af74909SZhong Yang 	              GetCtrlID(), reinterpret_cast<LPARAM>(&scn));
2285*8af74909SZhong Yang }
2286*8af74909SZhong Yang 
2287*8af74909SZhong Yang void ScintillaWin::NotifyDoubleClick(Point pt, int modifiers) {
2288*8af74909SZhong Yang 	//Platform::DebugPrintf("ScintillaWin Double click 0\n");
2289*8af74909SZhong Yang 	ScintillaBase::NotifyDoubleClick(pt, modifiers);
2290*8af74909SZhong Yang 	// Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
2291*8af74909SZhong Yang 	::SendMessage(MainHWND(),
2292*8af74909SZhong Yang 			  WM_LBUTTONDBLCLK,
2293*8af74909SZhong Yang 			  (modifiers & SCI_SHIFT) ? MK_SHIFT : 0,
2294*8af74909SZhong Yang 			  MAKELPARAM(pt.x, pt.y));
2295*8af74909SZhong Yang }
2296*8af74909SZhong Yang 
2297*8af74909SZhong Yang class CaseFolderDBCS : public CaseFolderTable {
2298*8af74909SZhong Yang 	// Allocate the expandable storage here so that it does not need to be reallocated
2299*8af74909SZhong Yang 	// for each call to Fold.
2300*8af74909SZhong Yang 	std::vector<wchar_t> utf16Mixed;
2301*8af74909SZhong Yang 	std::vector<wchar_t> utf16Folded;
2302*8af74909SZhong Yang 	UINT cp;
2303*8af74909SZhong Yang public:
2304*8af74909SZhong Yang 	explicit CaseFolderDBCS(UINT cp_) : cp(cp_) {
2305*8af74909SZhong Yang 		StandardASCII();
2306*8af74909SZhong Yang 	}
2307*8af74909SZhong Yang 	size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override {
2308*8af74909SZhong Yang 		if ((lenMixed == 1) && (sizeFolded > 0)) {
2309*8af74909SZhong Yang 			folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
2310*8af74909SZhong Yang 			return 1;
2311*8af74909SZhong Yang 		} else {
2312*8af74909SZhong Yang 			if (lenMixed > utf16Mixed.size()) {
2313*8af74909SZhong Yang 				utf16Mixed.resize(lenMixed + 8);
2314*8af74909SZhong Yang 			}
2315*8af74909SZhong Yang 			const size_t nUtf16Mixed = WideCharFromMultiByte(cp,
2316*8af74909SZhong Yang 				std::string_view(mixed, lenMixed),
2317*8af74909SZhong Yang 				&utf16Mixed[0],
2318*8af74909SZhong Yang 				utf16Mixed.size());
2319*8af74909SZhong Yang 
2320*8af74909SZhong Yang 			if (nUtf16Mixed == 0) {
2321*8af74909SZhong Yang 				// Failed to convert -> bad input
2322*8af74909SZhong Yang 				folded[0] = '\0';
2323*8af74909SZhong Yang 				return 1;
2324*8af74909SZhong Yang 			}
2325*8af74909SZhong Yang 
2326*8af74909SZhong Yang 			size_t lenFlat = 0;
2327*8af74909SZhong Yang 			for (size_t mixIndex=0; mixIndex < nUtf16Mixed; mixIndex++) {
2328*8af74909SZhong Yang 				if ((lenFlat + 20) > utf16Folded.size())
2329*8af74909SZhong Yang 					utf16Folded.resize(lenFlat + 60);
2330*8af74909SZhong Yang 				const char *foldedUTF8 = CaseConvert(utf16Mixed[mixIndex], CaseConversionFold);
2331*8af74909SZhong Yang 				if (foldedUTF8) {
2332*8af74909SZhong Yang 					// Maximum length of a case conversion is 6 bytes, 3 characters
2333*8af74909SZhong Yang 					wchar_t wFolded[20];
2334*8af74909SZhong Yang 					const size_t charsConverted = UTF16FromUTF8(std::string_view(foldedUTF8),
2335*8af74909SZhong Yang 							wFolded, std::size(wFolded));
2336*8af74909SZhong Yang 					for (size_t j=0; j<charsConverted; j++)
2337*8af74909SZhong Yang 						utf16Folded[lenFlat++] = wFolded[j];
2338*8af74909SZhong Yang 				} else {
2339*8af74909SZhong Yang 					utf16Folded[lenFlat++] = utf16Mixed[mixIndex];
2340*8af74909SZhong Yang 				}
2341*8af74909SZhong Yang 			}
2342*8af74909SZhong Yang 
2343*8af74909SZhong Yang 			const std::wstring_view wsvFolded(&utf16Folded[0], lenFlat);
2344*8af74909SZhong Yang 			const size_t lenOut = MultiByteLenFromWideChar(cp, wsvFolded);
2345*8af74909SZhong Yang 
2346*8af74909SZhong Yang 			if (lenOut < sizeFolded) {
2347*8af74909SZhong Yang 				MultiByteFromWideChar(cp, wsvFolded, folded, lenOut);
2348*8af74909SZhong Yang 				return lenOut;
2349*8af74909SZhong Yang 			} else {
2350*8af74909SZhong Yang 				return 0;
2351*8af74909SZhong Yang 			}
2352*8af74909SZhong Yang 		}
2353*8af74909SZhong Yang 	}
2354*8af74909SZhong Yang };
2355*8af74909SZhong Yang 
2356*8af74909SZhong Yang CaseFolder *ScintillaWin::CaseFolderForEncoding() {
2357*8af74909SZhong Yang 	const UINT cpDest = CodePageOfDocument();
2358*8af74909SZhong Yang 	if (cpDest == SC_CP_UTF8) {
2359*8af74909SZhong Yang 		return new CaseFolderUnicode();
2360*8af74909SZhong Yang 	} else {
2361*8af74909SZhong Yang 		if (pdoc->dbcsCodePage == 0) {
2362*8af74909SZhong Yang 			CaseFolderTable *pcf = new CaseFolderTable();
2363*8af74909SZhong Yang 			pcf->StandardASCII();
2364*8af74909SZhong Yang 			// Only for single byte encodings
2365*8af74909SZhong Yang 			for (int i=0x80; i<0x100; i++) {
2366*8af74909SZhong Yang 				char sCharacter[2] = "A";
2367*8af74909SZhong Yang 				sCharacter[0] = static_cast<char>(i);
2368*8af74909SZhong Yang 				wchar_t wCharacter[20];
2369*8af74909SZhong Yang 				const unsigned int lengthUTF16 = WideCharFromMultiByte(cpDest, sCharacter,
2370*8af74909SZhong Yang 					wCharacter, std::size(wCharacter));
2371*8af74909SZhong Yang 				if (lengthUTF16 == 1) {
2372*8af74909SZhong Yang 					const char *caseFolded = CaseConvert(wCharacter[0], CaseConversionFold);
2373*8af74909SZhong Yang 					if (caseFolded) {
2374*8af74909SZhong Yang 						wchar_t wLower[20];
2375*8af74909SZhong Yang 						const size_t charsConverted = UTF16FromUTF8(std::string_view(caseFolded),
2376*8af74909SZhong Yang 							wLower, std::size(wLower));
2377*8af74909SZhong Yang 						if (charsConverted == 1) {
2378*8af74909SZhong Yang 							char sCharacterLowered[20];
2379*8af74909SZhong Yang 							const unsigned int lengthConverted = MultiByteFromWideChar(cpDest,
2380*8af74909SZhong Yang 								std::wstring_view(wLower, charsConverted),
2381*8af74909SZhong Yang 								sCharacterLowered, std::size(sCharacterLowered));
2382*8af74909SZhong Yang 							if ((lengthConverted == 1) && (sCharacter[0] != sCharacterLowered[0])) {
2383*8af74909SZhong Yang 								pcf->SetTranslation(sCharacter[0], sCharacterLowered[0]);
2384*8af74909SZhong Yang 							}
2385*8af74909SZhong Yang 						}
2386*8af74909SZhong Yang 					}
2387*8af74909SZhong Yang 				}
2388*8af74909SZhong Yang 			}
2389*8af74909SZhong Yang 			return pcf;
2390*8af74909SZhong Yang 		} else {
2391*8af74909SZhong Yang 			return new CaseFolderDBCS(cpDest);
2392*8af74909SZhong Yang 		}
2393*8af74909SZhong Yang 	}
2394*8af74909SZhong Yang }
2395*8af74909SZhong Yang 
2396*8af74909SZhong Yang std::string ScintillaWin::CaseMapString(const std::string &s, int caseMapping) {
2397*8af74909SZhong Yang 	if ((s.size() == 0) || (caseMapping == cmSame))
2398*8af74909SZhong Yang 		return s;
2399*8af74909SZhong Yang 
2400*8af74909SZhong Yang 	const UINT cpDoc = CodePageOfDocument();
2401*8af74909SZhong Yang 	if (cpDoc == SC_CP_UTF8) {
2402*8af74909SZhong Yang 		return CaseConvertString(s, (caseMapping == cmUpper) ? CaseConversionUpper : CaseConversionLower);
2403*8af74909SZhong Yang 	}
2404*8af74909SZhong Yang 
2405*8af74909SZhong Yang 	// Change text to UTF-16
2406*8af74909SZhong Yang 	const std::wstring wsText = StringDecode(s, cpDoc);
2407*8af74909SZhong Yang 
2408*8af74909SZhong Yang 	const DWORD mapFlags = LCMAP_LINGUISTIC_CASING |
2409*8af74909SZhong Yang 		((caseMapping == cmUpper) ? LCMAP_UPPERCASE : LCMAP_LOWERCASE);
2410*8af74909SZhong Yang 
2411*8af74909SZhong Yang 	// Change case
2412*8af74909SZhong Yang 	const std::wstring wsConverted = StringMapCase(wsText, mapFlags);
2413*8af74909SZhong Yang 
2414*8af74909SZhong Yang 	// Change back to document encoding
2415*8af74909SZhong Yang 	std::string sConverted = StringEncode(wsConverted, cpDoc);
2416*8af74909SZhong Yang 
2417*8af74909SZhong Yang 	return sConverted;
2418*8af74909SZhong Yang }
2419*8af74909SZhong Yang 
2420*8af74909SZhong Yang void ScintillaWin::Copy() {
2421*8af74909SZhong Yang 	//Platform::DebugPrintf("Copy\n");
2422*8af74909SZhong Yang 	if (!sel.Empty()) {
2423*8af74909SZhong Yang 		SelectionText selectedText;
2424*8af74909SZhong Yang 		CopySelectionRange(&selectedText);
2425*8af74909SZhong Yang 		CopyToClipboard(selectedText);
2426*8af74909SZhong Yang 	}
2427*8af74909SZhong Yang }
2428*8af74909SZhong Yang 
2429*8af74909SZhong Yang bool ScintillaWin::CanPaste() {
2430*8af74909SZhong Yang 	if (!Editor::CanPaste())
2431*8af74909SZhong Yang 		return false;
2432*8af74909SZhong Yang 	return ::IsClipboardFormatAvailable(CF_UNICODETEXT) != FALSE;
2433*8af74909SZhong Yang }
2434*8af74909SZhong Yang 
2435*8af74909SZhong Yang namespace {
2436*8af74909SZhong Yang 
2437*8af74909SZhong Yang class GlobalMemory {
2438*8af74909SZhong Yang 	HGLOBAL hand {};
2439*8af74909SZhong Yang public:
2440*8af74909SZhong Yang 	void *ptr {};
2441*8af74909SZhong Yang 	GlobalMemory() noexcept {
2442*8af74909SZhong Yang 	}
2443*8af74909SZhong Yang 	explicit GlobalMemory(HGLOBAL hand_) noexcept : hand(hand_) {
2444*8af74909SZhong Yang 		if (hand) {
2445*8af74909SZhong Yang 			ptr = ::GlobalLock(hand);
2446*8af74909SZhong Yang 		}
2447*8af74909SZhong Yang 	}
2448*8af74909SZhong Yang 	// Deleted so GlobalMemory objects can not be copied.
2449*8af74909SZhong Yang 	GlobalMemory(const GlobalMemory &) = delete;
2450*8af74909SZhong Yang 	GlobalMemory(GlobalMemory &&) = delete;
2451*8af74909SZhong Yang 	GlobalMemory &operator=(const GlobalMemory &) = delete;
2452*8af74909SZhong Yang 	GlobalMemory &operator=(GlobalMemory &&) = delete;
2453*8af74909SZhong Yang 	~GlobalMemory() {
2454*8af74909SZhong Yang 		assert(!ptr);
2455*8af74909SZhong Yang 		assert(!hand);
2456*8af74909SZhong Yang 	}
2457*8af74909SZhong Yang 	void Allocate(size_t bytes) noexcept {
2458*8af74909SZhong Yang 		assert(!hand);
2459*8af74909SZhong Yang 		hand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bytes);
2460*8af74909SZhong Yang 		if (hand) {
2461*8af74909SZhong Yang 			ptr = ::GlobalLock(hand);
2462*8af74909SZhong Yang 		}
2463*8af74909SZhong Yang 	}
2464*8af74909SZhong Yang 	HGLOBAL Unlock() noexcept {
2465*8af74909SZhong Yang 		assert(ptr);
2466*8af74909SZhong Yang 		HGLOBAL handCopy = hand;
2467*8af74909SZhong Yang 		::GlobalUnlock(hand);
2468*8af74909SZhong Yang 		ptr = nullptr;
2469*8af74909SZhong Yang 		hand = {};
2470*8af74909SZhong Yang 		return handCopy;
2471*8af74909SZhong Yang 	}
2472*8af74909SZhong Yang 	void SetClip(UINT uFormat) noexcept {
2473*8af74909SZhong Yang 		::SetClipboardData(uFormat, Unlock());
2474*8af74909SZhong Yang 	}
2475*8af74909SZhong Yang 	operator bool() const noexcept {
2476*8af74909SZhong Yang 		return ptr != nullptr;
2477*8af74909SZhong Yang 	}
2478*8af74909SZhong Yang 	SIZE_T Size() const noexcept {
2479*8af74909SZhong Yang 		return ::GlobalSize(hand);
2480*8af74909SZhong Yang 	}
2481*8af74909SZhong Yang };
2482*8af74909SZhong Yang 
2483*8af74909SZhong Yang // OpenClipboard may fail if another application has opened the clipboard.
2484*8af74909SZhong Yang // Try up to 8 times, with an initial delay of 1 ms and an exponential back off
2485*8af74909SZhong Yang // for a maximum total delay of 127 ms (1+2+4+8+16+32+64).
2486*8af74909SZhong Yang bool OpenClipboardRetry(HWND hwnd) noexcept {
2487*8af74909SZhong Yang 	for (int attempt=0; attempt<8; attempt++) {
2488*8af74909SZhong Yang 		if (attempt > 0) {
2489*8af74909SZhong Yang 			::Sleep(1 << (attempt-1));
2490*8af74909SZhong Yang 		}
2491*8af74909SZhong Yang 		if (::OpenClipboard(hwnd)) {
2492*8af74909SZhong Yang 			return true;
2493*8af74909SZhong Yang 		}
2494*8af74909SZhong Yang 	}
2495*8af74909SZhong Yang 	return false;
2496*8af74909SZhong Yang }
2497*8af74909SZhong Yang 
2498*8af74909SZhong Yang bool IsValidFormatEtc(const FORMATETC *pFE) noexcept {
2499*8af74909SZhong Yang 	return pFE->ptd == nullptr &&
2500*8af74909SZhong Yang 		(pFE->dwAspect & DVASPECT_CONTENT) != 0 &&
2501*8af74909SZhong Yang 		pFE->lindex == -1 &&
2502*8af74909SZhong Yang 		(pFE->tymed & TYMED_HGLOBAL) != 0;
2503*8af74909SZhong Yang }
2504*8af74909SZhong Yang 
2505*8af74909SZhong Yang bool SupportedFormat(const FORMATETC *pFE) noexcept {
2506*8af74909SZhong Yang 	return pFE->cfFormat == CF_UNICODETEXT &&
2507*8af74909SZhong Yang 		IsValidFormatEtc(pFE);
2508*8af74909SZhong Yang }
2509*8af74909SZhong Yang 
2510*8af74909SZhong Yang }
2511*8af74909SZhong Yang 
2512*8af74909SZhong Yang void ScintillaWin::Paste() {
2513*8af74909SZhong Yang 	if (!::OpenClipboardRetry(MainHWND())) {
2514*8af74909SZhong Yang 		return;
2515*8af74909SZhong Yang 	}
2516*8af74909SZhong Yang 	UndoGroup ug(pdoc);
2517*8af74909SZhong Yang 	const bool isLine = SelectionEmpty() &&
2518*8af74909SZhong Yang 		(::IsClipboardFormatAvailable(cfLineSelect) || ::IsClipboardFormatAvailable(cfVSLineTag));
2519*8af74909SZhong Yang 	ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH);
2520*8af74909SZhong Yang 	bool isRectangular = (::IsClipboardFormatAvailable(cfColumnSelect) != 0);
2521*8af74909SZhong Yang 
2522*8af74909SZhong Yang 	if (!isRectangular) {
2523*8af74909SZhong Yang 		// Evaluate "Borland IDE Block Type" explicitly
2524*8af74909SZhong Yang 		GlobalMemory memBorlandSelection(::GetClipboardData(cfBorlandIDEBlockType));
2525*8af74909SZhong Yang 		if (memBorlandSelection) {
2526*8af74909SZhong Yang 			isRectangular = (memBorlandSelection.Size() == 1) && (static_cast<BYTE *>(memBorlandSelection.ptr)[0] == 0x02);
2527*8af74909SZhong Yang 			memBorlandSelection.Unlock();
2528*8af74909SZhong Yang 		}
2529*8af74909SZhong Yang 	}
2530*8af74909SZhong Yang 	const PasteShape pasteShape = isRectangular ? pasteRectangular : (isLine ? pasteLine : pasteStream);
2531*8af74909SZhong Yang 
2532*8af74909SZhong Yang 	// Use CF_UNICODETEXT if available
2533*8af74909SZhong Yang 	GlobalMemory memUSelection(::GetClipboardData(CF_UNICODETEXT));
2534*8af74909SZhong Yang 	if (const wchar_t *uptr = static_cast<const wchar_t *>(memUSelection.ptr)) {
2535*8af74909SZhong Yang 		const std::string putf = EncodeWString(uptr);
2536*8af74909SZhong Yang 		InsertPasteShape(putf.c_str(), putf.length(), pasteShape);
2537*8af74909SZhong Yang 		memUSelection.Unlock();
2538*8af74909SZhong Yang 	}
2539*8af74909SZhong Yang 	::CloseClipboard();
2540*8af74909SZhong Yang 	Redraw();
2541*8af74909SZhong Yang }
2542*8af74909SZhong Yang 
2543*8af74909SZhong Yang void ScintillaWin::CreateCallTipWindow(PRectangle) {
2544*8af74909SZhong Yang 	if (!ct.wCallTip.Created()) {
2545*8af74909SZhong Yang 		HWND wnd = ::CreateWindow(callClassName, TEXT("ACallTip"),
2546*8af74909SZhong Yang 					     WS_POPUP, 100, 100, 150, 20,
2547*8af74909SZhong Yang 					     MainHWND(), 0,
2548*8af74909SZhong Yang 					     GetWindowInstance(MainHWND()),
2549*8af74909SZhong Yang 					     this);
2550*8af74909SZhong Yang 		ct.wCallTip = wnd;
2551*8af74909SZhong Yang 		ct.wDraw = wnd;
2552*8af74909SZhong Yang 	}
2553*8af74909SZhong Yang }
2554*8af74909SZhong Yang 
2555*8af74909SZhong Yang void ScintillaWin::AddToPopUp(LPCTSTR label, int cmd, bool enabled) {
2556*8af74909SZhong Yang 	HMENU hmenuPopup = static_cast<HMENU>(popup.GetID());
2557*8af74909SZhong Yang 	if (!label[0])
2558*8af74909SZhong Yang 		::AppendMenu(hmenuPopup, MF_SEPARATOR, 0, _T(""));
2559*8af74909SZhong Yang 	else if (enabled)
2560*8af74909SZhong Yang 		::AppendMenu(hmenuPopup, MF_STRING, cmd, label);
2561*8af74909SZhong Yang 	else
2562*8af74909SZhong Yang 		::AppendMenu(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label);
2563*8af74909SZhong Yang }
2564*8af74909SZhong Yang 
2565*8af74909SZhong Yang void ScintillaWin::ClaimSelection() {
2566*8af74909SZhong Yang 	// Windows does not have a primary selection
2567*8af74909SZhong Yang }
2568*8af74909SZhong Yang 
2569*8af74909SZhong Yang /// Implement IUnknown
2570*8af74909SZhong Yang 
2571*8af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe);
2572*8af74909SZhong Yang STDMETHODIMP FormatEnumerator_QueryInterface(FormatEnumerator *fe, REFIID riid, PVOID *ppv) {
2573*8af74909SZhong Yang 	//Platform::DebugPrintf("EFE QI");
2574*8af74909SZhong Yang 	*ppv = nullptr;
2575*8af74909SZhong Yang 	if (riid == IID_IUnknown)
2576*8af74909SZhong Yang 		*ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
2577*8af74909SZhong Yang 	if (riid == IID_IEnumFORMATETC)
2578*8af74909SZhong Yang 		*ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
2579*8af74909SZhong Yang 	if (!*ppv)
2580*8af74909SZhong Yang 		return E_NOINTERFACE;
2581*8af74909SZhong Yang 	FormatEnumerator_AddRef(fe);
2582*8af74909SZhong Yang 	return S_OK;
2583*8af74909SZhong Yang }
2584*8af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) {
2585*8af74909SZhong Yang 	return ++fe->ref;
2586*8af74909SZhong Yang }
2587*8af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) {
2588*8af74909SZhong Yang 	fe->ref--;
2589*8af74909SZhong Yang 	if (fe->ref > 0)
2590*8af74909SZhong Yang 		return fe->ref;
2591*8af74909SZhong Yang 	delete fe;
2592*8af74909SZhong Yang 	return 0;
2593*8af74909SZhong Yang }
2594*8af74909SZhong Yang /// Implement IEnumFORMATETC
2595*8af74909SZhong Yang STDMETHODIMP FormatEnumerator_Next(FormatEnumerator *fe, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
2596*8af74909SZhong Yang 	if (!rgelt) return E_POINTER;
2597*8af74909SZhong Yang 	ULONG putPos = 0;
2598*8af74909SZhong Yang 	while ((fe->pos < fe->formats.size()) && (putPos < celt)) {
2599*8af74909SZhong Yang 		rgelt->cfFormat = fe->formats[fe->pos];
2600*8af74909SZhong Yang 		rgelt->ptd = nullptr;
2601*8af74909SZhong Yang 		rgelt->dwAspect = DVASPECT_CONTENT;
2602*8af74909SZhong Yang 		rgelt->lindex = -1;
2603*8af74909SZhong Yang 		rgelt->tymed = TYMED_HGLOBAL;
2604*8af74909SZhong Yang 		rgelt++;
2605*8af74909SZhong Yang 		fe->pos++;
2606*8af74909SZhong Yang 		putPos++;
2607*8af74909SZhong Yang 	}
2608*8af74909SZhong Yang 	if (pceltFetched)
2609*8af74909SZhong Yang 		*pceltFetched = putPos;
2610*8af74909SZhong Yang 	return putPos ? S_OK : S_FALSE;
2611*8af74909SZhong Yang }
2612*8af74909SZhong Yang STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) {
2613*8af74909SZhong Yang 	fe->pos += celt;
2614*8af74909SZhong Yang 	return S_OK;
2615*8af74909SZhong Yang }
2616*8af74909SZhong Yang STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) {
2617*8af74909SZhong Yang 	fe->pos = 0;
2618*8af74909SZhong Yang 	return S_OK;
2619*8af74909SZhong Yang }
2620*8af74909SZhong Yang STDMETHODIMP FormatEnumerator_Clone(FormatEnumerator *fe, IEnumFORMATETC **ppenum) {
2621*8af74909SZhong Yang 	FormatEnumerator *pfe;
2622*8af74909SZhong Yang 	try {
2623*8af74909SZhong Yang 		pfe = new FormatEnumerator(fe->pos, &fe->formats[0], fe->formats.size());
2624*8af74909SZhong Yang 	} catch (...) {
2625*8af74909SZhong Yang 		return E_OUTOFMEMORY;
2626*8af74909SZhong Yang 	}
2627*8af74909SZhong Yang 	return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
2628*8af74909SZhong Yang 	                                       reinterpret_cast<void **>(ppenum));
2629*8af74909SZhong Yang }
2630*8af74909SZhong Yang 
2631*8af74909SZhong Yang static VFunction *vtFormatEnumerator[] = {
2632*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_QueryInterface),
2633*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_AddRef),
2634*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_Release),
2635*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_Next),
2636*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_Skip),
2637*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_Reset),
2638*8af74909SZhong Yang 	(VFunction *)(FormatEnumerator_Clone)
2639*8af74909SZhong Yang };
2640*8af74909SZhong Yang 
2641*8af74909SZhong Yang FormatEnumerator::FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_) {
2642*8af74909SZhong Yang 	vtbl = vtFormatEnumerator;
2643*8af74909SZhong Yang 	ref = 0;   // First QI adds first reference...
2644*8af74909SZhong Yang 	pos = pos_;
2645*8af74909SZhong Yang 	formats.insert(formats.begin(), formats_, formats_+formatsLen_);
2646*8af74909SZhong Yang }
2647*8af74909SZhong Yang 
2648*8af74909SZhong Yang /// Implement IUnknown
2649*8af74909SZhong Yang STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) {
2650*8af74909SZhong Yang 	return ds->sci->QueryInterface(riid, ppv);
2651*8af74909SZhong Yang }
2652*8af74909SZhong Yang STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) {
2653*8af74909SZhong Yang 	return ds->sci->AddRef();
2654*8af74909SZhong Yang }
2655*8af74909SZhong Yang STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) {
2656*8af74909SZhong Yang 	return ds->sci->Release();
2657*8af74909SZhong Yang }
2658*8af74909SZhong Yang 
2659*8af74909SZhong Yang /// Implement IDropSource
2660*8af74909SZhong Yang STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) {
2661*8af74909SZhong Yang 	if (fEsc)
2662*8af74909SZhong Yang 		return DRAGDROP_S_CANCEL;
2663*8af74909SZhong Yang 	if (!(grfKeyState & MK_LBUTTON))
2664*8af74909SZhong Yang 		return DRAGDROP_S_DROP;
2665*8af74909SZhong Yang 	return S_OK;
2666*8af74909SZhong Yang }
2667*8af74909SZhong Yang 
2668*8af74909SZhong Yang STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) {
2669*8af74909SZhong Yang 	return DRAGDROP_S_USEDEFAULTCURSORS;
2670*8af74909SZhong Yang }
2671*8af74909SZhong Yang 
2672*8af74909SZhong Yang static VFunction *vtDropSource[] = {
2673*8af74909SZhong Yang 	(VFunction *)(DropSource_QueryInterface),
2674*8af74909SZhong Yang 	(VFunction *)(DropSource_AddRef),
2675*8af74909SZhong Yang 	(VFunction *)(DropSource_Release),
2676*8af74909SZhong Yang 	(VFunction *)(DropSource_QueryContinueDrag),
2677*8af74909SZhong Yang 	(VFunction *)(DropSource_GiveFeedback)
2678*8af74909SZhong Yang };
2679*8af74909SZhong Yang 
2680*8af74909SZhong Yang DropSource::DropSource() noexcept {
2681*8af74909SZhong Yang 	vtbl = vtDropSource;
2682*8af74909SZhong Yang 	sci = nullptr;
2683*8af74909SZhong Yang }
2684*8af74909SZhong Yang 
2685*8af74909SZhong Yang /// Implement IUnkown
2686*8af74909SZhong Yang STDMETHODIMP DataObject_QueryInterface(DataObject *pd, REFIID riid, PVOID *ppv) {
2687*8af74909SZhong Yang 	//Platform::DebugPrintf("DO QI %x\n", pd);
2688*8af74909SZhong Yang 	return pd->sci->QueryInterface(riid, ppv);
2689*8af74909SZhong Yang }
2690*8af74909SZhong Yang STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) {
2691*8af74909SZhong Yang 	return pd->sci->AddRef();
2692*8af74909SZhong Yang }
2693*8af74909SZhong Yang STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) {
2694*8af74909SZhong Yang 	return pd->sci->Release();
2695*8af74909SZhong Yang }
2696*8af74909SZhong Yang /// Implement IDataObject
2697*8af74909SZhong Yang STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) {
2698*8af74909SZhong Yang 	return pd->sci->GetData(pFEIn, pSTM);
2699*8af74909SZhong Yang }
2700*8af74909SZhong Yang 
2701*8af74909SZhong Yang STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) {
2702*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB GetDataHere\n");
2703*8af74909SZhong Yang 	return E_NOTIMPL;
2704*8af74909SZhong Yang }
2705*8af74909SZhong Yang 
2706*8af74909SZhong Yang STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) {
2707*8af74909SZhong Yang 	if (pd->sci->DragIsRectangularOK(pFE->cfFormat) && IsValidFormatEtc(pFE)) {
2708*8af74909SZhong Yang 		return S_OK;
2709*8af74909SZhong Yang 	}
2710*8af74909SZhong Yang 
2711*8af74909SZhong Yang 	if (SupportedFormat(pFE)) {
2712*8af74909SZhong Yang 		return S_OK;
2713*8af74909SZhong Yang 	} else {
2714*8af74909SZhong Yang 		return S_FALSE;
2715*8af74909SZhong Yang 	}
2716*8af74909SZhong Yang }
2717*8af74909SZhong Yang 
2718*8af74909SZhong Yang STDMETHODIMP DataObject_GetCanonicalFormatEtc(DataObject *, FORMATETC *, FORMATETC *pFEOut) {
2719*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB GetCanon\n");
2720*8af74909SZhong Yang 	pFEOut->cfFormat = CF_UNICODETEXT;
2721*8af74909SZhong Yang 	pFEOut->ptd = nullptr;
2722*8af74909SZhong Yang 	pFEOut->dwAspect = DVASPECT_CONTENT;
2723*8af74909SZhong Yang 	pFEOut->lindex = -1;
2724*8af74909SZhong Yang 	pFEOut->tymed = TYMED_HGLOBAL;
2725*8af74909SZhong Yang 	return S_OK;
2726*8af74909SZhong Yang }
2727*8af74909SZhong Yang 
2728*8af74909SZhong Yang STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) {
2729*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB SetData\n");
2730*8af74909SZhong Yang 	return E_FAIL;
2731*8af74909SZhong Yang }
2732*8af74909SZhong Yang 
2733*8af74909SZhong Yang STDMETHODIMP DataObject_EnumFormatEtc(DataObject *pd, DWORD dwDirection, IEnumFORMATETC **ppEnum) {
2734*8af74909SZhong Yang 	try {
2735*8af74909SZhong Yang 		//Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
2736*8af74909SZhong Yang 		if (dwDirection != DATADIR_GET) {
2737*8af74909SZhong Yang 			*ppEnum = nullptr;
2738*8af74909SZhong Yang 			return E_FAIL;
2739*8af74909SZhong Yang 		}
2740*8af74909SZhong Yang 
2741*8af74909SZhong Yang 		const CLIPFORMAT formats[] = {CF_UNICODETEXT};
2742*8af74909SZhong Yang 		FormatEnumerator *pfe = new FormatEnumerator(0, formats, std::size(formats));
2743*8af74909SZhong Yang 		return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
2744*8af74909SZhong Yang 											   reinterpret_cast<void **>(ppEnum));
2745*8af74909SZhong Yang 	} catch (std::bad_alloc &) {
2746*8af74909SZhong Yang 		pd->sci->errorStatus = SC_STATUS_BADALLOC;
2747*8af74909SZhong Yang 		return E_OUTOFMEMORY;
2748*8af74909SZhong Yang 	} catch (...) {
2749*8af74909SZhong Yang 		pd->sci->errorStatus = SC_STATUS_FAILURE;
2750*8af74909SZhong Yang 		return E_FAIL;
2751*8af74909SZhong Yang 	}
2752*8af74909SZhong Yang }
2753*8af74909SZhong Yang 
2754*8af74909SZhong Yang STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) {
2755*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB DAdvise\n");
2756*8af74909SZhong Yang 	return E_FAIL;
2757*8af74909SZhong Yang }
2758*8af74909SZhong Yang 
2759*8af74909SZhong Yang STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) {
2760*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB DUnadvise\n");
2761*8af74909SZhong Yang 	return E_FAIL;
2762*8af74909SZhong Yang }
2763*8af74909SZhong Yang 
2764*8af74909SZhong Yang STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) {
2765*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB EnumDAdvise\n");
2766*8af74909SZhong Yang 	return E_FAIL;
2767*8af74909SZhong Yang }
2768*8af74909SZhong Yang 
2769*8af74909SZhong Yang static VFunction *vtDataObject[] = {
2770*8af74909SZhong Yang 	(VFunction *)(DataObject_QueryInterface),
2771*8af74909SZhong Yang 	(VFunction *)(DataObject_AddRef),
2772*8af74909SZhong Yang 	(VFunction *)(DataObject_Release),
2773*8af74909SZhong Yang 	(VFunction *)(DataObject_GetData),
2774*8af74909SZhong Yang 	(VFunction *)(DataObject_GetDataHere),
2775*8af74909SZhong Yang 	(VFunction *)(DataObject_QueryGetData),
2776*8af74909SZhong Yang 	(VFunction *)(DataObject_GetCanonicalFormatEtc),
2777*8af74909SZhong Yang 	(VFunction *)(DataObject_SetData),
2778*8af74909SZhong Yang 	(VFunction *)(DataObject_EnumFormatEtc),
2779*8af74909SZhong Yang 	(VFunction *)(DataObject_DAdvise),
2780*8af74909SZhong Yang 	(VFunction *)(DataObject_DUnadvise),
2781*8af74909SZhong Yang 	(VFunction *)(DataObject_EnumDAdvise)
2782*8af74909SZhong Yang };
2783*8af74909SZhong Yang 
2784*8af74909SZhong Yang DataObject::DataObject() noexcept {
2785*8af74909SZhong Yang 	vtbl = vtDataObject;
2786*8af74909SZhong Yang 	sci = nullptr;
2787*8af74909SZhong Yang }
2788*8af74909SZhong Yang 
2789*8af74909SZhong Yang /// Implement IUnknown
2790*8af74909SZhong Yang STDMETHODIMP DropTarget_QueryInterface(DropTarget *dt, REFIID riid, PVOID *ppv) {
2791*8af74909SZhong Yang 	//Platform::DebugPrintf("DT QI %x\n", dt);
2792*8af74909SZhong Yang 	return dt->sci->QueryInterface(riid, ppv);
2793*8af74909SZhong Yang }
2794*8af74909SZhong Yang STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) {
2795*8af74909SZhong Yang 	return dt->sci->AddRef();
2796*8af74909SZhong Yang }
2797*8af74909SZhong Yang STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) {
2798*8af74909SZhong Yang 	return dt->sci->Release();
2799*8af74909SZhong Yang }
2800*8af74909SZhong Yang 
2801*8af74909SZhong Yang /// Implement IDropTarget by forwarding to Scintilla
2802*8af74909SZhong Yang STDMETHODIMP DropTarget_DragEnter(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
2803*8af74909SZhong Yang                                   POINTL pt, PDWORD pdwEffect) {
2804*8af74909SZhong Yang 	try {
2805*8af74909SZhong Yang 		return dt->sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect);
2806*8af74909SZhong Yang 	} catch (...) {
2807*8af74909SZhong Yang 		dt->sci->errorStatus = SC_STATUS_FAILURE;
2808*8af74909SZhong Yang 	}
2809*8af74909SZhong Yang 	return E_FAIL;
2810*8af74909SZhong Yang }
2811*8af74909SZhong Yang STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
2812*8af74909SZhong Yang 	try {
2813*8af74909SZhong Yang 		return dt->sci->DragOver(grfKeyState, pt, pdwEffect);
2814*8af74909SZhong Yang 	} catch (...) {
2815*8af74909SZhong Yang 		dt->sci->errorStatus = SC_STATUS_FAILURE;
2816*8af74909SZhong Yang 	}
2817*8af74909SZhong Yang 	return E_FAIL;
2818*8af74909SZhong Yang }
2819*8af74909SZhong Yang STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) {
2820*8af74909SZhong Yang 	try {
2821*8af74909SZhong Yang 		return dt->sci->DragLeave();
2822*8af74909SZhong Yang 	} catch (...) {
2823*8af74909SZhong Yang 		dt->sci->errorStatus = SC_STATUS_FAILURE;
2824*8af74909SZhong Yang 	}
2825*8af74909SZhong Yang 	return E_FAIL;
2826*8af74909SZhong Yang }
2827*8af74909SZhong Yang STDMETHODIMP DropTarget_Drop(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
2828*8af74909SZhong Yang                              POINTL pt, PDWORD pdwEffect) {
2829*8af74909SZhong Yang 	try {
2830*8af74909SZhong Yang 		return dt->sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect);
2831*8af74909SZhong Yang 	} catch (...) {
2832*8af74909SZhong Yang 		dt->sci->errorStatus = SC_STATUS_FAILURE;
2833*8af74909SZhong Yang 	}
2834*8af74909SZhong Yang 	return E_FAIL;
2835*8af74909SZhong Yang }
2836*8af74909SZhong Yang 
2837*8af74909SZhong Yang static VFunction *vtDropTarget[] = {
2838*8af74909SZhong Yang 	(VFunction *)(DropTarget_QueryInterface),
2839*8af74909SZhong Yang 	(VFunction *)(DropTarget_AddRef),
2840*8af74909SZhong Yang 	(VFunction *)(DropTarget_Release),
2841*8af74909SZhong Yang 	(VFunction *)(DropTarget_DragEnter),
2842*8af74909SZhong Yang 	(VFunction *)(DropTarget_DragOver),
2843*8af74909SZhong Yang 	(VFunction *)(DropTarget_DragLeave),
2844*8af74909SZhong Yang 	(VFunction *)(DropTarget_Drop)
2845*8af74909SZhong Yang };
2846*8af74909SZhong Yang 
2847*8af74909SZhong Yang DropTarget::DropTarget() noexcept {
2848*8af74909SZhong Yang 	vtbl = vtDropTarget;
2849*8af74909SZhong Yang 	sci = nullptr;
2850*8af74909SZhong Yang }
2851*8af74909SZhong Yang 
2852*8af74909SZhong Yang /**
2853*8af74909SZhong Yang  * DBCS: support Input Method Editor (IME).
2854*8af74909SZhong Yang  * Called when IME Window opened.
2855*8af74909SZhong Yang  */
2856*8af74909SZhong Yang void ScintillaWin::ImeStartComposition() {
2857*8af74909SZhong Yang 	if (caret.active) {
2858*8af74909SZhong Yang 		// Move IME Window to current caret position
2859*8af74909SZhong Yang 		IMContext imc(MainHWND());
2860*8af74909SZhong Yang 		const Point pos = PointMainCaret();
2861*8af74909SZhong Yang 		COMPOSITIONFORM CompForm;
2862*8af74909SZhong Yang 		CompForm.dwStyle = CFS_POINT;
2863*8af74909SZhong Yang 		CompForm.ptCurrentPos = POINTFromPoint(pos);
2864*8af74909SZhong Yang 
2865*8af74909SZhong Yang 		::ImmSetCompositionWindow(imc.hIMC, &CompForm);
2866*8af74909SZhong Yang 
2867*8af74909SZhong Yang 		// Set font of IME window to same as surrounded text.
2868*8af74909SZhong Yang 		if (stylesValid) {
2869*8af74909SZhong Yang 			// Since the style creation code has been made platform independent,
2870*8af74909SZhong Yang 			// The logfont for the IME is recreated here.
2871*8af74909SZhong Yang 			//const int styleHere = pdoc->StyleIndexAt(sel.MainCaret());
2872*8af74909SZhong Yang             const int styleHere = STYLE_DEFAULT;
2873*8af74909SZhong Yang 			LOGFONTW lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L""};
2874*8af74909SZhong Yang 			int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER;
2875*8af74909SZhong Yang 			if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER)	// Hangs if sizeZoomed <= 1
2876*8af74909SZhong Yang 				sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
2877*8af74909SZhong Yang 			// The negative is to allow for leading
2878*8af74909SZhong Yang 			lf.lfHeight = -::MulDiv(sizeZoomed, dpi, 72*SC_FONT_SIZE_MULTIPLIER);
2879*8af74909SZhong Yang 			lf.lfWeight = vs.styles[styleHere].weight;
2880*8af74909SZhong Yang 			lf.lfItalic = vs.styles[styleHere].italic ? 1 : 0;
2881*8af74909SZhong Yang 			lf.lfCharSet = DEFAULT_CHARSET;
2882*8af74909SZhong Yang 			lf.lfFaceName[0] = L'\0';
2883*8af74909SZhong Yang 			if (vs.styles[styleHere].fontName) {
2884*8af74909SZhong Yang 				const char* fontName = vs.styles[styleHere].fontName;
2885*8af74909SZhong Yang 				UTF16FromUTF8(std::string_view(fontName), lf.lfFaceName, LF_FACESIZE);
2886*8af74909SZhong Yang 			}
2887*8af74909SZhong Yang 
2888*8af74909SZhong Yang 			::ImmSetCompositionFontW(imc.hIMC, &lf);
2889*8af74909SZhong Yang 		}
2890*8af74909SZhong Yang 		// Caret is displayed in IME window. So, caret in Scintilla is useless.
2891*8af74909SZhong Yang 		DropCaret();
2892*8af74909SZhong Yang 	}
2893*8af74909SZhong Yang }
2894*8af74909SZhong Yang 
2895*8af74909SZhong Yang /** Called when IME Window closed. */
2896*8af74909SZhong Yang void ScintillaWin::ImeEndComposition() {
2897*8af74909SZhong Yang 	// clear IME composition state.
2898*8af74909SZhong Yang 	view.imeCaretBlockOverride = false;
2899*8af74909SZhong Yang 	pdoc->TentativeUndo();
2900*8af74909SZhong Yang 	ShowCaretAtCurrentPosition();
2901*8af74909SZhong Yang }
2902*8af74909SZhong Yang 
2903*8af74909SZhong Yang LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) {
2904*8af74909SZhong Yang 	// Reconversion on windows limits within one line without eol.
2905*8af74909SZhong Yang 	// Look around:   baseStart  <--  (|mainStart|  -- mainEnd)  --> baseEnd.
2906*8af74909SZhong Yang 	const Sci::Position mainStart = sel.RangeMain().Start().Position();
2907*8af74909SZhong Yang 	const Sci::Position mainEnd = sel.RangeMain().End().Position();
2908*8af74909SZhong Yang 	const Sci::Line curLine = pdoc->SciLineFromPosition(mainStart);
2909*8af74909SZhong Yang 	if (curLine != pdoc->LineFromPosition(mainEnd))
2910*8af74909SZhong Yang 		return 0;
2911*8af74909SZhong Yang 	const Sci::Position baseStart = pdoc->LineStart(curLine);
2912*8af74909SZhong Yang 	const Sci::Position baseEnd = pdoc->LineEnd(curLine);
2913*8af74909SZhong Yang 	if ((baseStart == baseEnd) || (mainEnd > baseEnd))
2914*8af74909SZhong Yang 		return 0;
2915*8af74909SZhong Yang 
2916*8af74909SZhong Yang 	const int codePage = CodePageOfDocument();
2917*8af74909SZhong Yang 	const std::wstring rcFeed = StringDecode(RangeText(baseStart, baseEnd), codePage);
2918*8af74909SZhong Yang 	const int rcFeedLen = static_cast<int>(rcFeed.length()) * sizeof(wchar_t);
2919*8af74909SZhong Yang 	const int rcSize = sizeof(RECONVERTSTRING) + rcFeedLen + sizeof(wchar_t);
2920*8af74909SZhong Yang 
2921*8af74909SZhong Yang 	RECONVERTSTRING *rc = static_cast<RECONVERTSTRING *>(PtrFromSPtr(lParam));
2922*8af74909SZhong Yang 	if (!rc)
2923*8af74909SZhong Yang 		return rcSize; // Immediately be back with rcSize of memory block.
2924*8af74909SZhong Yang 
2925*8af74909SZhong Yang 	wchar_t *rcFeedStart = reinterpret_cast<wchar_t*>(rc + 1);
2926*8af74909SZhong Yang 	memcpy(rcFeedStart, &rcFeed[0], rcFeedLen);
2927*8af74909SZhong Yang 
2928*8af74909SZhong Yang 	std::string rcCompString = RangeText(mainStart, mainEnd);
2929*8af74909SZhong Yang 	std::wstring rcCompWstring = StringDecode(rcCompString, codePage);
2930*8af74909SZhong Yang 	std::string rcCompStart = RangeText(baseStart, mainStart);
2931*8af74909SZhong Yang 	std::wstring rcCompWstart = StringDecode(rcCompStart, codePage);
2932*8af74909SZhong Yang 
2933*8af74909SZhong Yang 	// Map selection to dwCompStr.
2934*8af74909SZhong Yang 	// No selection assumes current caret as rcCompString without length.
2935*8af74909SZhong Yang 	rc->dwVersion = 0; // It should be absolutely 0.
2936*8af74909SZhong Yang 	rc->dwStrLen = static_cast<DWORD>(rcFeed.length());
2937*8af74909SZhong Yang 	rc->dwStrOffset = sizeof(RECONVERTSTRING);
2938*8af74909SZhong Yang 	rc->dwCompStrLen = static_cast<DWORD>(rcCompWstring.length());
2939*8af74909SZhong Yang 	rc->dwCompStrOffset = static_cast<DWORD>(rcCompWstart.length()) * sizeof(wchar_t);
2940*8af74909SZhong Yang 	rc->dwTargetStrLen = rc->dwCompStrLen;
2941*8af74909SZhong Yang 	rc->dwTargetStrOffset =rc->dwCompStrOffset;
2942*8af74909SZhong Yang 
2943*8af74909SZhong Yang 	IMContext imc(MainHWND());
2944*8af74909SZhong Yang 	if (!imc.hIMC)
2945*8af74909SZhong Yang 		return 0;
2946*8af74909SZhong Yang 
2947*8af74909SZhong Yang 	if (!::ImmSetCompositionStringW(imc.hIMC, SCS_QUERYRECONVERTSTRING, rc, rcSize, nullptr, 0))
2948*8af74909SZhong Yang 		return 0;
2949*8af74909SZhong Yang 
2950*8af74909SZhong Yang 	// No selection asks IME to fill target fields with its own value.
2951*8af74909SZhong Yang 	const int tgWlen = rc->dwTargetStrLen;
2952*8af74909SZhong Yang 	const int tgWstart = rc->dwTargetStrOffset / sizeof(wchar_t);
2953*8af74909SZhong Yang 
2954*8af74909SZhong Yang 	std::string tgCompStart = StringEncode(rcFeed.substr(0, tgWstart), codePage);
2955*8af74909SZhong Yang 	std::string tgComp = StringEncode(rcFeed.substr(tgWstart, tgWlen), codePage);
2956*8af74909SZhong Yang 
2957*8af74909SZhong Yang 	// No selection needs to adjust reconvert start position for IME set.
2958*8af74909SZhong Yang 	const int adjust = static_cast<int>(tgCompStart.length() - rcCompStart.length());
2959*8af74909SZhong Yang 	const int docCompLen = static_cast<int>(tgComp.length());
2960*8af74909SZhong Yang 
2961*8af74909SZhong Yang 	// Make place for next composition string to sit in.
2962*8af74909SZhong Yang 	for (size_t r=0; r<sel.Count(); r++) {
2963*8af74909SZhong Yang 		const Sci::Position rBase = sel.Range(r).Start().Position();
2964*8af74909SZhong Yang 		const Sci::Position docCompStart = rBase + adjust;
2965*8af74909SZhong Yang 
2966*8af74909SZhong Yang 		if (inOverstrike) { // the docCompLen of bytes will be overstriked.
2967*8af74909SZhong Yang 			sel.Range(r).caret.SetPosition(docCompStart);
2968*8af74909SZhong Yang 			sel.Range(r).anchor.SetPosition(docCompStart);
2969*8af74909SZhong Yang 		} else {
2970*8af74909SZhong Yang 			// Ensure docCompStart+docCompLen be not beyond lineEnd.
2971*8af74909SZhong Yang 			// since docCompLen by byte might break eol.
2972*8af74909SZhong Yang 			const Sci::Position lineEnd = pdoc->LineEnd(pdoc->LineFromPosition(rBase));
2973*8af74909SZhong Yang 			const Sci::Position overflow = (docCompStart + docCompLen) - lineEnd;
2974*8af74909SZhong Yang 			if (overflow > 0) {
2975*8af74909SZhong Yang 				pdoc->DeleteChars(docCompStart, docCompLen - overflow);
2976*8af74909SZhong Yang 			} else {
2977*8af74909SZhong Yang 				pdoc->DeleteChars(docCompStart, docCompLen);
2978*8af74909SZhong Yang 			}
2979*8af74909SZhong Yang 		}
2980*8af74909SZhong Yang 	}
2981*8af74909SZhong Yang 	// Immediately Target Input or candidate box choice with GCS_COMPSTR.
2982*8af74909SZhong Yang 	return rcSize;
2983*8af74909SZhong Yang }
2984*8af74909SZhong Yang 
2985*8af74909SZhong Yang void ScintillaWin::GetIntelliMouseParameters() noexcept {
2986*8af74909SZhong Yang 	// This retrieves the number of lines per scroll as configured in the Mouse Properties sheet in Control Panel
2987*8af74909SZhong Yang 	::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
2988*8af74909SZhong Yang }
2989*8af74909SZhong Yang 
2990*8af74909SZhong Yang void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText) {
2991*8af74909SZhong Yang 	const std::string_view svSelected(selectedText.Data(), selectedText.LengthWithTerminator());
2992*8af74909SZhong Yang 	if (IsUnicodeMode()) {
2993*8af74909SZhong Yang 		const size_t uchars = UTF16Length(svSelected);
2994*8af74909SZhong Yang 		gmUnicode.Allocate(2 * uchars);
2995*8af74909SZhong Yang 		if (gmUnicode) {
2996*8af74909SZhong Yang 			UTF16FromUTF8(svSelected,
2997*8af74909SZhong Yang 				static_cast<wchar_t *>(gmUnicode.ptr), uchars);
2998*8af74909SZhong Yang 		}
2999*8af74909SZhong Yang 	} else {
3000*8af74909SZhong Yang 		// Not Unicode mode
3001*8af74909SZhong Yang 		// Convert to Unicode using the current Scintilla code page
3002*8af74909SZhong Yang 		const UINT cpSrc = CodePageFromCharSet(
3003*8af74909SZhong Yang 			selectedText.characterSet, selectedText.codePage);
3004*8af74909SZhong Yang 		const size_t uLen = WideCharLenFromMultiByte(cpSrc, svSelected);
3005*8af74909SZhong Yang 		gmUnicode.Allocate(2 * uLen);
3006*8af74909SZhong Yang 		if (gmUnicode) {
3007*8af74909SZhong Yang 			WideCharFromMultiByte(cpSrc, svSelected,
3008*8af74909SZhong Yang 				static_cast<wchar_t *>(gmUnicode.ptr), uLen);
3009*8af74909SZhong Yang 		}
3010*8af74909SZhong Yang 	}
3011*8af74909SZhong Yang }
3012*8af74909SZhong Yang 
3013*8af74909SZhong Yang void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
3014*8af74909SZhong Yang 	if (!::OpenClipboardRetry(MainHWND())) {
3015*8af74909SZhong Yang 		return;
3016*8af74909SZhong Yang 	}
3017*8af74909SZhong Yang 	::EmptyClipboard();
3018*8af74909SZhong Yang 
3019*8af74909SZhong Yang 	GlobalMemory uniText;
3020*8af74909SZhong Yang 	CopyToGlobal(uniText, selectedText);
3021*8af74909SZhong Yang 	if (uniText) {
3022*8af74909SZhong Yang 		uniText.SetClip(CF_UNICODETEXT);
3023*8af74909SZhong Yang 	}
3024*8af74909SZhong Yang 
3025*8af74909SZhong Yang 	if (selectedText.rectangular) {
3026*8af74909SZhong Yang 		::SetClipboardData(cfColumnSelect, 0);
3027*8af74909SZhong Yang 
3028*8af74909SZhong Yang 		GlobalMemory borlandSelection;
3029*8af74909SZhong Yang 		borlandSelection.Allocate(1);
3030*8af74909SZhong Yang 		if (borlandSelection) {
3031*8af74909SZhong Yang 			static_cast<BYTE *>(borlandSelection.ptr)[0] = 0x02;
3032*8af74909SZhong Yang 			borlandSelection.SetClip(cfBorlandIDEBlockType);
3033*8af74909SZhong Yang 		}
3034*8af74909SZhong Yang 	}
3035*8af74909SZhong Yang 
3036*8af74909SZhong Yang 	if (selectedText.lineCopy) {
3037*8af74909SZhong Yang 		::SetClipboardData(cfLineSelect, 0);
3038*8af74909SZhong Yang 		::SetClipboardData(cfVSLineTag, 0);
3039*8af74909SZhong Yang 	}
3040*8af74909SZhong Yang 
3041*8af74909SZhong Yang 	::CloseClipboard();
3042*8af74909SZhong Yang }
3043*8af74909SZhong Yang 
3044*8af74909SZhong Yang void ScintillaWin::ScrollMessage(WPARAM wParam) {
3045*8af74909SZhong Yang 	//DWORD dwStart = timeGetTime();
3046*8af74909SZhong Yang 	//Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
3047*8af74909SZhong Yang 
3048*8af74909SZhong Yang 	SCROLLINFO sci = {};
3049*8af74909SZhong Yang 	sci.cbSize = sizeof(sci);
3050*8af74909SZhong Yang 	sci.fMask = SIF_ALL;
3051*8af74909SZhong Yang 
3052*8af74909SZhong Yang 	GetScrollInfo(SB_VERT, &sci);
3053*8af74909SZhong Yang 
3054*8af74909SZhong Yang 	//Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
3055*8af74909SZhong Yang 	//sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
3056*8af74909SZhong Yang 	Sci::Line topLineNew = topLine;
3057*8af74909SZhong Yang 	switch (LOWORD(wParam)) {
3058*8af74909SZhong Yang 	case SB_LINEUP:
3059*8af74909SZhong Yang 		topLineNew -= 1;
3060*8af74909SZhong Yang 		break;
3061*8af74909SZhong Yang 	case SB_LINEDOWN:
3062*8af74909SZhong Yang 		topLineNew += 1;
3063*8af74909SZhong Yang 		break;
3064*8af74909SZhong Yang 	case SB_PAGEUP:
3065*8af74909SZhong Yang 		topLineNew -= LinesToScroll(); break;
3066*8af74909SZhong Yang 	case SB_PAGEDOWN: topLineNew += LinesToScroll(); break;
3067*8af74909SZhong Yang 	case SB_TOP: topLineNew = 0; break;
3068*8af74909SZhong Yang 	case SB_BOTTOM: topLineNew = MaxScrollPos(); break;
3069*8af74909SZhong Yang 	case SB_THUMBPOSITION: topLineNew = sci.nTrackPos; break;
3070*8af74909SZhong Yang 	case SB_THUMBTRACK: topLineNew = sci.nTrackPos; break;
3071*8af74909SZhong Yang 	}
3072*8af74909SZhong Yang 	ScrollTo(topLineNew);
3073*8af74909SZhong Yang }
3074*8af74909SZhong Yang 
3075*8af74909SZhong Yang void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) {
3076*8af74909SZhong Yang 	int xPos = xOffset;
3077*8af74909SZhong Yang 	const PRectangle rcText = GetTextRectangle();
3078*8af74909SZhong Yang 	const int pageWidth = static_cast<int>(rcText.Width() * 2 / 3);
3079*8af74909SZhong Yang 	switch (LOWORD(wParam)) {
3080*8af74909SZhong Yang 	case SB_LINEUP:
3081*8af74909SZhong Yang 		xPos -= 20;
3082*8af74909SZhong Yang 		break;
3083*8af74909SZhong Yang 	case SB_LINEDOWN:	// May move past the logical end
3084*8af74909SZhong Yang 		xPos += 20;
3085*8af74909SZhong Yang 		break;
3086*8af74909SZhong Yang 	case SB_PAGEUP:
3087*8af74909SZhong Yang 		xPos -= pageWidth;
3088*8af74909SZhong Yang 		break;
3089*8af74909SZhong Yang 	case SB_PAGEDOWN:
3090*8af74909SZhong Yang 		xPos += pageWidth;
3091*8af74909SZhong Yang 		if (xPos > scrollWidth - rcText.Width()) {	// Hit the end exactly
3092*8af74909SZhong Yang 			xPos = scrollWidth - static_cast<int>(rcText.Width());
3093*8af74909SZhong Yang 		}
3094*8af74909SZhong Yang 		break;
3095*8af74909SZhong Yang 	case SB_TOP:
3096*8af74909SZhong Yang 		xPos = 0;
3097*8af74909SZhong Yang 		break;
3098*8af74909SZhong Yang 	case SB_BOTTOM:
3099*8af74909SZhong Yang 		xPos = scrollWidth;
3100*8af74909SZhong Yang 		break;
3101*8af74909SZhong Yang 	case SB_THUMBPOSITION:
3102*8af74909SZhong Yang 	case SB_THUMBTRACK: {
3103*8af74909SZhong Yang 			// Do NOT use wParam, its 16 bit and not enough for very long lines. Its still possible to overflow the 32 bit but you have to try harder =]
3104*8af74909SZhong Yang 			SCROLLINFO si;
3105*8af74909SZhong Yang 			si.cbSize = sizeof(si);
3106*8af74909SZhong Yang 			si.fMask = SIF_TRACKPOS;
3107*8af74909SZhong Yang 			if (GetScrollInfo(SB_HORZ, &si)) {
3108*8af74909SZhong Yang 				xPos = si.nTrackPos;
3109*8af74909SZhong Yang 			}
3110*8af74909SZhong Yang 		}
3111*8af74909SZhong Yang 		break;
3112*8af74909SZhong Yang 	}
3113*8af74909SZhong Yang 	HorizontalScrollTo(xPos);
3114*8af74909SZhong Yang }
3115*8af74909SZhong Yang 
3116*8af74909SZhong Yang /**
3117*8af74909SZhong Yang  * Redraw all of text area.
3118*8af74909SZhong Yang  * This paint will not be abandoned.
3119*8af74909SZhong Yang  */
3120*8af74909SZhong Yang void ScintillaWin::FullPaint() {
3121*8af74909SZhong Yang 	if ((technology == SC_TECHNOLOGY_DEFAULT) || (technology == SC_TECHNOLOGY_DIRECTWRITEDC)) {
3122*8af74909SZhong Yang 		HDC hdc = ::GetDC(MainHWND());
3123*8af74909SZhong Yang 		FullPaintDC(hdc);
3124*8af74909SZhong Yang 		::ReleaseDC(MainHWND(), hdc);
3125*8af74909SZhong Yang 	} else {
3126*8af74909SZhong Yang 		FullPaintDC({});
3127*8af74909SZhong Yang 	}
3128*8af74909SZhong Yang }
3129*8af74909SZhong Yang 
3130*8af74909SZhong Yang /**
3131*8af74909SZhong Yang  * Redraw all of text area on the specified DC.
3132*8af74909SZhong Yang  * This paint will not be abandoned.
3133*8af74909SZhong Yang  */
3134*8af74909SZhong Yang void ScintillaWin::FullPaintDC(HDC hdc) {
3135*8af74909SZhong Yang 	paintState = painting;
3136*8af74909SZhong Yang 	rcPaint = GetClientRectangle();
3137*8af74909SZhong Yang 	paintingAllText = true;
3138*8af74909SZhong Yang 	PaintDC(hdc);
3139*8af74909SZhong Yang 	paintState = notPainting;
3140*8af74909SZhong Yang }
3141*8af74909SZhong Yang 
3142*8af74909SZhong Yang namespace {
3143*8af74909SZhong Yang 
3144*8af74909SZhong Yang bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) noexcept {
3145*8af74909SZhong Yang 	return ::GetDeviceCaps(hdc, nIndex) == ::GetDeviceCaps(hOtherDC, nIndex);
3146*8af74909SZhong Yang }
3147*8af74909SZhong Yang 
3148*8af74909SZhong Yang }
3149*8af74909SZhong Yang 
3150*8af74909SZhong Yang bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) noexcept {
3151*8af74909SZhong Yang 	HDC hdc = ::GetDC(MainHWND());
3152*8af74909SZhong Yang 	const bool isCompatible =
3153*8af74909SZhong Yang 		CompareDevCap(hdc, hOtherDC, TECHNOLOGY) &&
3154*8af74909SZhong Yang 		CompareDevCap(hdc, hOtherDC, LOGPIXELSY) &&
3155*8af74909SZhong Yang 		CompareDevCap(hdc, hOtherDC, LOGPIXELSX) &&
3156*8af74909SZhong Yang 		CompareDevCap(hdc, hOtherDC, BITSPIXEL) &&
3157*8af74909SZhong Yang 		CompareDevCap(hdc, hOtherDC, PLANES);
3158*8af74909SZhong Yang 	::ReleaseDC(MainHWND(), hdc);
3159*8af74909SZhong Yang 	return isCompatible;
3160*8af74909SZhong Yang }
3161*8af74909SZhong Yang 
3162*8af74909SZhong Yang DWORD ScintillaWin::EffectFromState(DWORD grfKeyState) const noexcept {
3163*8af74909SZhong Yang 	// These are the Wordpad semantics.
3164*8af74909SZhong Yang 	DWORD dwEffect;
3165*8af74909SZhong Yang 	if (inDragDrop == ddDragging)	// Internal defaults to move
3166*8af74909SZhong Yang 		dwEffect = DROPEFFECT_MOVE;
3167*8af74909SZhong Yang 	else
3168*8af74909SZhong Yang 		dwEffect = DROPEFFECT_COPY;
3169*8af74909SZhong Yang 	if (grfKeyState & MK_ALT)
3170*8af74909SZhong Yang 		dwEffect = DROPEFFECT_MOVE;
3171*8af74909SZhong Yang 	if (grfKeyState & MK_CONTROL)
3172*8af74909SZhong Yang 		dwEffect = DROPEFFECT_COPY;
3173*8af74909SZhong Yang 	return dwEffect;
3174*8af74909SZhong Yang }
3175*8af74909SZhong Yang 
3176*8af74909SZhong Yang /// Implement IUnknown
3177*8af74909SZhong Yang STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) {
3178*8af74909SZhong Yang 	*ppv = nullptr;
3179*8af74909SZhong Yang 	if (riid == IID_IUnknown)
3180*8af74909SZhong Yang 		*ppv = reinterpret_cast<IDropTarget *>(&dt);
3181*8af74909SZhong Yang 	if (riid == IID_IDropSource)
3182*8af74909SZhong Yang 		*ppv = reinterpret_cast<IDropSource *>(&ds);
3183*8af74909SZhong Yang 	if (riid == IID_IDropTarget)
3184*8af74909SZhong Yang 		*ppv = reinterpret_cast<IDropTarget *>(&dt);
3185*8af74909SZhong Yang 	if (riid == IID_IDataObject)
3186*8af74909SZhong Yang 		*ppv = reinterpret_cast<IDataObject *>(&dob);
3187*8af74909SZhong Yang 	if (!*ppv)
3188*8af74909SZhong Yang 		return E_NOINTERFACE;
3189*8af74909SZhong Yang 	return S_OK;
3190*8af74909SZhong Yang }
3191*8af74909SZhong Yang 
3192*8af74909SZhong Yang STDMETHODIMP_(ULONG) ScintillaWin::AddRef() {
3193*8af74909SZhong Yang 	return 1;
3194*8af74909SZhong Yang }
3195*8af74909SZhong Yang 
3196*8af74909SZhong Yang STDMETHODIMP_(ULONG) ScintillaWin::Release() {
3197*8af74909SZhong Yang 	return 1;
3198*8af74909SZhong Yang }
3199*8af74909SZhong Yang 
3200*8af74909SZhong Yang /// Implement IDropTarget
3201*8af74909SZhong Yang STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
3202*8af74909SZhong Yang                                      POINTL, PDWORD pdwEffect) {
3203*8af74909SZhong Yang 	if (!pIDataSource )
3204*8af74909SZhong Yang 		return E_POINTER;
3205*8af74909SZhong Yang 	FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
3206*8af74909SZhong Yang 	const HRESULT hrHasUText = pIDataSource->QueryGetData(&fmtu);
3207*8af74909SZhong Yang 	hasOKText = (hrHasUText == S_OK);
3208*8af74909SZhong Yang 	if (hasOKText) {
3209*8af74909SZhong Yang 		*pdwEffect = EffectFromState(grfKeyState);
3210*8af74909SZhong Yang 	} else {
3211*8af74909SZhong Yang 		*pdwEffect = DROPEFFECT_NONE;
3212*8af74909SZhong Yang 	}
3213*8af74909SZhong Yang 
3214*8af74909SZhong Yang 	return S_OK;
3215*8af74909SZhong Yang }
3216*8af74909SZhong Yang 
3217*8af74909SZhong Yang STDMETHODIMP ScintillaWin::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
3218*8af74909SZhong Yang 	try {
3219*8af74909SZhong Yang 		if (!hasOKText || pdoc->IsReadOnly()) {
3220*8af74909SZhong Yang 			*pdwEffect = DROPEFFECT_NONE;
3221*8af74909SZhong Yang 			return S_OK;
3222*8af74909SZhong Yang 		}
3223*8af74909SZhong Yang 
3224*8af74909SZhong Yang 		*pdwEffect = EffectFromState(grfKeyState);
3225*8af74909SZhong Yang 
3226*8af74909SZhong Yang 		// Update the cursor.
3227*8af74909SZhong Yang 		POINT rpt = {pt.x, pt.y};
3228*8af74909SZhong Yang 		::ScreenToClient(MainHWND(), &rpt);
3229*8af74909SZhong Yang 		SetDragPosition(SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace()));
3230*8af74909SZhong Yang 
3231*8af74909SZhong Yang 		return S_OK;
3232*8af74909SZhong Yang 	} catch (...) {
3233*8af74909SZhong Yang 		errorStatus = SC_STATUS_FAILURE;
3234*8af74909SZhong Yang 	}
3235*8af74909SZhong Yang 	return E_FAIL;
3236*8af74909SZhong Yang }
3237*8af74909SZhong Yang 
3238*8af74909SZhong Yang STDMETHODIMP ScintillaWin::DragLeave() {
3239*8af74909SZhong Yang 	try {
3240*8af74909SZhong Yang 		SetDragPosition(SelectionPosition(Sci::invalidPosition));
3241*8af74909SZhong Yang 		return S_OK;
3242*8af74909SZhong Yang 	} catch (...) {
3243*8af74909SZhong Yang 		errorStatus = SC_STATUS_FAILURE;
3244*8af74909SZhong Yang 	}
3245*8af74909SZhong Yang 	return E_FAIL;
3246*8af74909SZhong Yang }
3247*8af74909SZhong Yang 
3248*8af74909SZhong Yang STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
3249*8af74909SZhong Yang                                 POINTL pt, PDWORD pdwEffect) {
3250*8af74909SZhong Yang 	try {
3251*8af74909SZhong Yang 		*pdwEffect = EffectFromState(grfKeyState);
3252*8af74909SZhong Yang 
3253*8af74909SZhong Yang 		if (!pIDataSource)
3254*8af74909SZhong Yang 			return E_POINTER;
3255*8af74909SZhong Yang 
3256*8af74909SZhong Yang 		SetDragPosition(SelectionPosition(Sci::invalidPosition));
3257*8af74909SZhong Yang 
3258*8af74909SZhong Yang 		std::string putf;
3259*8af74909SZhong Yang 		FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
3260*8af74909SZhong Yang 		STGMEDIUM medium{};
3261*8af74909SZhong Yang 		const HRESULT hr = pIDataSource->GetData(&fmtu, &medium);
3262*8af74909SZhong Yang 		if (!SUCCEEDED(hr)) {
3263*8af74909SZhong Yang 			return hr;
3264*8af74909SZhong Yang 		}
3265*8af74909SZhong Yang 		if (medium.hGlobal) {
3266*8af74909SZhong Yang 			GlobalMemory memUDrop(medium.hGlobal);
3267*8af74909SZhong Yang 			if (const wchar_t *uptr = static_cast<const wchar_t *>(memUDrop.ptr)) {
3268*8af74909SZhong Yang 				putf = EncodeWString(uptr);
3269*8af74909SZhong Yang 			}
3270*8af74909SZhong Yang 			memUDrop.Unlock();
3271*8af74909SZhong Yang 		}
3272*8af74909SZhong Yang 
3273*8af74909SZhong Yang 		if (putf.empty()) {
3274*8af74909SZhong Yang 			return S_OK;
3275*8af74909SZhong Yang 		}
3276*8af74909SZhong Yang 
3277*8af74909SZhong Yang 		FORMATETC fmtr = {cfColumnSelect, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
3278*8af74909SZhong Yang 		const bool isRectangular = S_OK == pIDataSource->QueryGetData(&fmtr);
3279*8af74909SZhong Yang 
3280*8af74909SZhong Yang 		POINT rpt = {pt.x, pt.y};
3281*8af74909SZhong Yang 		::ScreenToClient(MainHWND(), &rpt);
3282*8af74909SZhong Yang 		const SelectionPosition movePos = SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace());
3283*8af74909SZhong Yang 
3284*8af74909SZhong Yang 		DropAt(movePos, putf.c_str(), putf.size(), *pdwEffect == DROPEFFECT_MOVE, isRectangular);
3285*8af74909SZhong Yang 
3286*8af74909SZhong Yang 		// Free data
3287*8af74909SZhong Yang 		::ReleaseStgMedium(&medium);
3288*8af74909SZhong Yang 
3289*8af74909SZhong Yang 		return S_OK;
3290*8af74909SZhong Yang 	} catch (...) {
3291*8af74909SZhong Yang 		errorStatus = SC_STATUS_FAILURE;
3292*8af74909SZhong Yang 	}
3293*8af74909SZhong Yang 	return E_FAIL;
3294*8af74909SZhong Yang }
3295*8af74909SZhong Yang 
3296*8af74909SZhong Yang /// Implement important part of IDataObject
3297*8af74909SZhong Yang STDMETHODIMP ScintillaWin::GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) {
3298*8af74909SZhong Yang 	if (!SupportedFormat(pFEIn)) {
3299*8af74909SZhong Yang 		//Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
3300*8af74909SZhong Yang 		return DATA_E_FORMATETC;
3301*8af74909SZhong Yang 	}
3302*8af74909SZhong Yang 
3303*8af74909SZhong Yang 	pSTM->tymed = TYMED_HGLOBAL;
3304*8af74909SZhong Yang 	//Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
3305*8af74909SZhong Yang 
3306*8af74909SZhong Yang 	GlobalMemory uniText;
3307*8af74909SZhong Yang 	CopyToGlobal(uniText, drag);
3308*8af74909SZhong Yang 	pSTM->hGlobal = uniText ? uniText.Unlock() : 0;
3309*8af74909SZhong Yang 	pSTM->pUnkForRelease = nullptr;
3310*8af74909SZhong Yang 	return S_OK;
3311*8af74909SZhong Yang }
3312*8af74909SZhong Yang 
3313*8af74909SZhong Yang void ScintillaWin::Prepare() noexcept {
3314*8af74909SZhong Yang 	Platform_Initialise(hInstance);
3315*8af74909SZhong Yang 
3316*8af74909SZhong Yang 	// Register the CallTip class
3317*8af74909SZhong Yang 	WNDCLASSEX wndclassc{};
3318*8af74909SZhong Yang 	wndclassc.cbSize = sizeof(wndclassc);
3319*8af74909SZhong Yang 	wndclassc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
3320*8af74909SZhong Yang 	wndclassc.cbWndExtra = sizeof(ScintillaWin *);
3321*8af74909SZhong Yang 	wndclassc.hInstance = hInstance;
3322*8af74909SZhong Yang 	wndclassc.lpfnWndProc = ScintillaWin::CTWndProc;
3323*8af74909SZhong Yang 	wndclassc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
3324*8af74909SZhong Yang 	wndclassc.lpszClassName = callClassName;
3325*8af74909SZhong Yang 
3326*8af74909SZhong Yang 	callClassAtom = ::RegisterClassEx(&wndclassc);
3327*8af74909SZhong Yang }
3328*8af74909SZhong Yang 
3329*8af74909SZhong Yang bool ScintillaWin::Register(HINSTANCE hInstance_) noexcept {
3330*8af74909SZhong Yang 
3331*8af74909SZhong Yang 	hInstance = hInstance_;
3332*8af74909SZhong Yang 
3333*8af74909SZhong Yang 	// Register the Scintilla class
3334*8af74909SZhong Yang 	// Register Scintilla as a wide character window
3335*8af74909SZhong Yang 	WNDCLASSEXW wndclass {};
3336*8af74909SZhong Yang 	wndclass.cbSize = sizeof(wndclass);
3337*8af74909SZhong Yang 	wndclass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
3338*8af74909SZhong Yang 	wndclass.lpfnWndProc = ScintillaWin::SWndProc;
3339*8af74909SZhong Yang 	wndclass.cbWndExtra = sizeof(ScintillaWin *);
3340*8af74909SZhong Yang 	wndclass.hInstance = hInstance;
3341*8af74909SZhong Yang 	wndclass.lpszClassName = L"Scintilla";
3342*8af74909SZhong Yang 	scintillaClassAtom = ::RegisterClassExW(&wndclass);
3343*8af74909SZhong Yang 	const bool result = 0 != scintillaClassAtom;
3344*8af74909SZhong Yang 
3345*8af74909SZhong Yang 	return result;
3346*8af74909SZhong Yang }
3347*8af74909SZhong Yang 
3348*8af74909SZhong Yang bool ScintillaWin::Unregister() noexcept {
3349*8af74909SZhong Yang 	bool result = true;
3350*8af74909SZhong Yang 	if (0 != scintillaClassAtom) {
3351*8af74909SZhong Yang 		if (::UnregisterClass(MAKEINTATOM(scintillaClassAtom), hInstance) == 0) {
3352*8af74909SZhong Yang 			result = false;
3353*8af74909SZhong Yang 		}
3354*8af74909SZhong Yang 		scintillaClassAtom = 0;
3355*8af74909SZhong Yang 	}
3356*8af74909SZhong Yang 	if (0 != callClassAtom) {
3357*8af74909SZhong Yang 		if (::UnregisterClass(MAKEINTATOM(callClassAtom), hInstance) == 0) {
3358*8af74909SZhong Yang 			result = false;
3359*8af74909SZhong Yang 		}
3360*8af74909SZhong Yang 		callClassAtom = 0;
3361*8af74909SZhong Yang 	}
3362*8af74909SZhong Yang 	return result;
3363*8af74909SZhong Yang }
3364*8af74909SZhong Yang 
3365*8af74909SZhong Yang bool ScintillaWin::HasCaretSizeChanged() const noexcept {
3366*8af74909SZhong Yang 	if (
3367*8af74909SZhong Yang 		( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) )
3368*8af74909SZhong Yang 		|| ((0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight))
3369*8af74909SZhong Yang 		) {
3370*8af74909SZhong Yang 		return true;
3371*8af74909SZhong Yang 	}
3372*8af74909SZhong Yang 	return false;
3373*8af74909SZhong Yang }
3374*8af74909SZhong Yang 
3375*8af74909SZhong Yang BOOL ScintillaWin::CreateSystemCaret() {
3376*8af74909SZhong Yang 	sysCaretWidth = vs.caretWidth;
3377*8af74909SZhong Yang 	if (0 == sysCaretWidth) {
3378*8af74909SZhong Yang 		sysCaretWidth = 1;
3379*8af74909SZhong Yang 	}
3380*8af74909SZhong Yang 	sysCaretHeight = vs.lineHeight;
3381*8af74909SZhong Yang 	const int bitmapSize = (((sysCaretWidth + 15) & ~15) >> 3) *
3382*8af74909SZhong Yang 		sysCaretHeight;
3383*8af74909SZhong Yang 	std::vector<BYTE> bits(bitmapSize);
3384*8af74909SZhong Yang 	sysCaretBitmap = ::CreateBitmap(sysCaretWidth, sysCaretHeight, 1,
3385*8af74909SZhong Yang 		1, &bits[0]);
3386*8af74909SZhong Yang 	const BOOL retval = ::CreateCaret(
3387*8af74909SZhong Yang 		MainHWND(), sysCaretBitmap,
3388*8af74909SZhong Yang 		sysCaretWidth, sysCaretHeight);
3389*8af74909SZhong Yang 	if (technology == SC_TECHNOLOGY_DEFAULT) {
3390*8af74909SZhong Yang 		// System caret interferes with Direct2D drawing so only show it for GDI.
3391*8af74909SZhong Yang 		::ShowCaret(MainHWND());
3392*8af74909SZhong Yang 	}
3393*8af74909SZhong Yang 	return retval;
3394*8af74909SZhong Yang }
3395*8af74909SZhong Yang 
3396*8af74909SZhong Yang BOOL ScintillaWin::DestroySystemCaret() noexcept {
3397*8af74909SZhong Yang 	::HideCaret(MainHWND());
3398*8af74909SZhong Yang 	const BOOL retval = ::DestroyCaret();
3399*8af74909SZhong Yang 	if (sysCaretBitmap) {
3400*8af74909SZhong Yang 		::DeleteObject(sysCaretBitmap);
3401*8af74909SZhong Yang 		sysCaretBitmap = {};
3402*8af74909SZhong Yang 	}
3403*8af74909SZhong Yang 	return retval;
3404*8af74909SZhong Yang }
3405*8af74909SZhong Yang 
3406*8af74909SZhong Yang LRESULT PASCAL ScintillaWin::CTWndProc(
3407*8af74909SZhong Yang 	HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
3408*8af74909SZhong Yang 	// Find C++ object associated with window.
3409*8af74909SZhong Yang 	ScintillaWin *sciThis = static_cast<ScintillaWin *>(PointerFromWindow(hWnd));
3410*8af74909SZhong Yang 	try {
3411*8af74909SZhong Yang 		// ctp will be zero if WM_CREATE not seen yet
3412*8af74909SZhong Yang 		if (sciThis == nullptr) {
3413*8af74909SZhong Yang 			if (iMessage == WM_CREATE) {
3414*8af74909SZhong Yang 				// Associate CallTip object with window
3415*8af74909SZhong Yang 				CREATESTRUCT *pCreate = static_cast<CREATESTRUCT *>(PtrFromSPtr(lParam));
3416*8af74909SZhong Yang 				SetWindowPointer(hWnd, pCreate->lpCreateParams);
3417*8af74909SZhong Yang 				return 0;
3418*8af74909SZhong Yang 			} else {
3419*8af74909SZhong Yang 				return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3420*8af74909SZhong Yang 			}
3421*8af74909SZhong Yang 		} else {
3422*8af74909SZhong Yang 			if (iMessage == WM_NCDESTROY) {
3423*8af74909SZhong Yang 				SetWindowPointer(hWnd, nullptr);
3424*8af74909SZhong Yang 				return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3425*8af74909SZhong Yang 			} else if (iMessage == WM_PAINT) {
3426*8af74909SZhong Yang 				PAINTSTRUCT ps;
3427*8af74909SZhong Yang 				::BeginPaint(hWnd, &ps);
3428*8af74909SZhong Yang 				std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(sciThis->technology));
3429*8af74909SZhong Yang #if defined(USE_D2D)
3430*8af74909SZhong Yang 				ID2D1HwndRenderTarget *pCTRenderTarget = nullptr;
3431*8af74909SZhong Yang #endif
3432*8af74909SZhong Yang 				RECT rc;
3433*8af74909SZhong Yang 				GetClientRect(hWnd, &rc);
3434*8af74909SZhong Yang 				// Create a Direct2D render target.
3435*8af74909SZhong Yang 				if (sciThis->technology == SC_TECHNOLOGY_DEFAULT) {
3436*8af74909SZhong Yang 					surfaceWindow->Init(ps.hdc, hWnd);
3437*8af74909SZhong Yang 				} else {
3438*8af74909SZhong Yang #if defined(USE_D2D)
3439*8af74909SZhong Yang 					D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp;
3440*8af74909SZhong Yang 					dhrtp.hwnd = hWnd;
3441*8af74909SZhong Yang 					dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
3442*8af74909SZhong Yang 					dhrtp.presentOptions = (sciThis->technology == SC_TECHNOLOGY_DIRECTWRITERETAIN) ?
3443*8af74909SZhong Yang 						D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE;
3444*8af74909SZhong Yang 
3445*8af74909SZhong Yang 					D2D1_RENDER_TARGET_PROPERTIES drtp;
3446*8af74909SZhong Yang 					drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
3447*8af74909SZhong Yang 					drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
3448*8af74909SZhong Yang 					drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
3449*8af74909SZhong Yang 					drtp.dpiX = 96.0;
3450*8af74909SZhong Yang 					drtp.dpiY = 96.0;
3451*8af74909SZhong Yang 					drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
3452*8af74909SZhong Yang 					drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
3453*8af74909SZhong Yang 
3454*8af74909SZhong Yang 					if (!SUCCEEDED(pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pCTRenderTarget))) {
3455*8af74909SZhong Yang 						surfaceWindow->Release();
3456*8af74909SZhong Yang 						::EndPaint(hWnd, &ps);
3457*8af74909SZhong Yang 						return 0;
3458*8af74909SZhong Yang 					}
3459*8af74909SZhong Yang 					// If above SUCCEEDED, then pCTRenderTarget not nullptr
3460*8af74909SZhong Yang 					assert(pCTRenderTarget);
3461*8af74909SZhong Yang 					if (pCTRenderTarget) {
3462*8af74909SZhong Yang 						surfaceWindow->Init(pCTRenderTarget, hWnd);
3463*8af74909SZhong Yang 						pCTRenderTarget->BeginDraw();
3464*8af74909SZhong Yang 					}
3465*8af74909SZhong Yang #endif
3466*8af74909SZhong Yang 				}
3467*8af74909SZhong Yang 				surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);
3468*8af74909SZhong Yang 				surfaceWindow->SetDBCSMode(sciThis->ct.codePage);
3469*8af74909SZhong Yang 				surfaceWindow->SetBidiR2L(sciThis->BidirectionalR2L());
3470*8af74909SZhong Yang 				sciThis->ct.PaintCT(surfaceWindow.get());
3471*8af74909SZhong Yang #if defined(USE_D2D)
3472*8af74909SZhong Yang 				if (pCTRenderTarget)
3473*8af74909SZhong Yang 					pCTRenderTarget->EndDraw();
3474*8af74909SZhong Yang #endif
3475*8af74909SZhong Yang 				surfaceWindow->Release();
3476*8af74909SZhong Yang #if defined(USE_D2D)
3477*8af74909SZhong Yang 				ReleaseUnknown(pCTRenderTarget);
3478*8af74909SZhong Yang #endif
3479*8af74909SZhong Yang 				::EndPaint(hWnd, &ps);
3480*8af74909SZhong Yang 				return 0;
3481*8af74909SZhong Yang 			} else if ((iMessage == WM_NCLBUTTONDOWN) || (iMessage == WM_NCLBUTTONDBLCLK)) {
3482*8af74909SZhong Yang 				POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
3483*8af74909SZhong Yang 				ScreenToClient(hWnd, &pt);
3484*8af74909SZhong Yang 				sciThis->ct.MouseClick(PointFromPOINT(pt));
3485*8af74909SZhong Yang 				sciThis->CallTipClick();
3486*8af74909SZhong Yang 				return 0;
3487*8af74909SZhong Yang 			} else if (iMessage == WM_LBUTTONDOWN) {
3488*8af74909SZhong Yang 				// This does not fire due to the hit test code
3489*8af74909SZhong Yang 				sciThis->ct.MouseClick(PointFromLParam(lParam));
3490*8af74909SZhong Yang 				sciThis->CallTipClick();
3491*8af74909SZhong Yang 				return 0;
3492*8af74909SZhong Yang 			} else if (iMessage == WM_SETCURSOR) {
3493*8af74909SZhong Yang 				::SetCursor(::LoadCursor(NULL, IDC_ARROW));
3494*8af74909SZhong Yang 				return 0;
3495*8af74909SZhong Yang 			} else if (iMessage == WM_NCHITTEST) {
3496*8af74909SZhong Yang 				return HTCAPTION;
3497*8af74909SZhong Yang 			} else {
3498*8af74909SZhong Yang 				return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3499*8af74909SZhong Yang 			}
3500*8af74909SZhong Yang 		}
3501*8af74909SZhong Yang 	} catch (...) {
3502*8af74909SZhong Yang 		sciThis->errorStatus = SC_STATUS_FAILURE;
3503*8af74909SZhong Yang 	}
3504*8af74909SZhong Yang 	return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3505*8af74909SZhong Yang }
3506*8af74909SZhong Yang 
3507*8af74909SZhong Yang sptr_t ScintillaWin::DirectFunction(
3508*8af74909SZhong Yang     sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam) {
3509*8af74909SZhong Yang 	PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(reinterpret_cast<ScintillaWin *>(ptr)->MainHWND(), nullptr));
3510*8af74909SZhong Yang 	return reinterpret_cast<ScintillaWin *>(ptr)->WndProc(iMessage, wParam, lParam);
3511*8af74909SZhong Yang }
3512*8af74909SZhong Yang 
3513*8af74909SZhong Yang namespace Scintilla {
3514*8af74909SZhong Yang 
3515*8af74909SZhong Yang sptr_t DirectFunction(
3516*8af74909SZhong Yang     ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam) {
3517*8af74909SZhong Yang 	return sci->WndProc(iMessage, wParam, lParam);
3518*8af74909SZhong Yang }
3519*8af74909SZhong Yang 
3520*8af74909SZhong Yang }
3521*8af74909SZhong Yang 
3522*8af74909SZhong Yang LRESULT PASCAL ScintillaWin::SWndProc(
3523*8af74909SZhong Yang 	HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
3524*8af74909SZhong Yang 	//Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
3525*8af74909SZhong Yang 
3526*8af74909SZhong Yang 	// Find C++ object associated with window.
3527*8af74909SZhong Yang 	ScintillaWin *sci = static_cast<ScintillaWin *>(PointerFromWindow(hWnd));
3528*8af74909SZhong Yang 	// sci will be zero if WM_CREATE not seen yet
3529*8af74909SZhong Yang 	if (sci == nullptr) {
3530*8af74909SZhong Yang 		try {
3531*8af74909SZhong Yang 			if (iMessage == WM_CREATE) {
3532*8af74909SZhong Yang 				static std::once_flag once;
3533*8af74909SZhong Yang 				std::call_once(once, Prepare);
3534*8af74909SZhong Yang 				// Create C++ object associated with window
3535*8af74909SZhong Yang 				sci = new ScintillaWin(hWnd);
3536*8af74909SZhong Yang 				SetWindowPointer(hWnd, sci);
3537*8af74909SZhong Yang 				return sci->WndProc(iMessage, wParam, lParam);
3538*8af74909SZhong Yang 			}
3539*8af74909SZhong Yang 		} catch (...) {
3540*8af74909SZhong Yang 		}
3541*8af74909SZhong Yang 		return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3542*8af74909SZhong Yang 	} else {
3543*8af74909SZhong Yang 		if (iMessage == WM_NCDESTROY) {
3544*8af74909SZhong Yang 			try {
3545*8af74909SZhong Yang 				sci->Finalise();
3546*8af74909SZhong Yang 				delete sci;
3547*8af74909SZhong Yang 			} catch (...) {
3548*8af74909SZhong Yang 			}
3549*8af74909SZhong Yang 			SetWindowPointer(hWnd, nullptr);
3550*8af74909SZhong Yang 			return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
3551*8af74909SZhong Yang 		} else {
3552*8af74909SZhong Yang 			return sci->WndProc(iMessage, wParam, lParam);
3553*8af74909SZhong Yang 		}
3554*8af74909SZhong Yang 	}
3555*8af74909SZhong Yang }
3556*8af74909SZhong Yang 
3557*8af74909SZhong Yang // This function is externally visible so it can be called from container when building statically.
3558*8af74909SZhong Yang // Must be called once only.
3559*8af74909SZhong Yang int Scintilla_RegisterClasses(void *hInstance) {
3560*8af74909SZhong Yang 	const bool result = ScintillaWin::Register(static_cast<HINSTANCE>(hInstance));
3561*8af74909SZhong Yang 	return result;
3562*8af74909SZhong Yang }
3563*8af74909SZhong Yang 
3564*8af74909SZhong Yang namespace Scintilla {
3565*8af74909SZhong Yang 
3566*8af74909SZhong Yang int ResourcesRelease(bool fromDllMain) noexcept {
3567*8af74909SZhong Yang 	const bool result = ScintillaWin::Unregister();
3568*8af74909SZhong Yang 	Platform_Finalise(fromDllMain);
3569*8af74909SZhong Yang 	return result;
3570*8af74909SZhong Yang }
3571*8af74909SZhong Yang 
3572*8af74909SZhong Yang }
3573*8af74909SZhong Yang 
3574*8af74909SZhong Yang // This function is externally visible so it can be called from container when building statically.
3575*8af74909SZhong Yang int Scintilla_ReleaseResources() {
3576*8af74909SZhong Yang 	return Scintilla::ResourcesRelease(false);
3577*8af74909SZhong Yang }
3578