18af74909SZhong Yang // Scintilla source code edit control
28af74909SZhong Yang /** @file ScintillaWin.cxx
38af74909SZhong Yang ** Windows specific subclass of ScintillaBase.
48af74909SZhong Yang **/
58af74909SZhong Yang // Copyright 1998-2003 by Neil Hodgson <[email protected]>
68af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
78af74909SZhong Yang
88af74909SZhong Yang #include <cstddef>
98af74909SZhong Yang #include <cstdlib>
108af74909SZhong Yang #include <cassert>
118af74909SZhong Yang #include <cstring>
128af74909SZhong Yang #include <cstdio>
138af74909SZhong Yang #include <cmath>
148af74909SZhong Yang #include <climits>
158af74909SZhong Yang
168af74909SZhong Yang #include <stdexcept>
178af74909SZhong Yang #include <new>
188af74909SZhong Yang #include <string>
198af74909SZhong Yang #include <string_view>
208af74909SZhong Yang #include <vector>
218af74909SZhong Yang #include <map>
228af74909SZhong Yang #include <algorithm>
238af74909SZhong Yang #include <memory>
248af74909SZhong Yang #include <chrono>
258af74909SZhong Yang #include <mutex>
268af74909SZhong Yang
278af74909SZhong Yang // Want to use std::min and std::max so don't want Windows.h version of min and max
288af74909SZhong Yang #if !defined(NOMINMAX)
298af74909SZhong Yang #define NOMINMAX
308af74909SZhong Yang #endif
318af74909SZhong Yang #undef _WIN32_WINNT
328af74909SZhong Yang #define _WIN32_WINNT 0x0500
338af74909SZhong Yang #undef WINVER
348af74909SZhong Yang #define WINVER 0x0500
358af74909SZhong Yang #include <windows.h>
368af74909SZhong Yang #include <commctrl.h>
378af74909SZhong Yang #include <richedit.h>
388af74909SZhong Yang #include <windowsx.h>
398af74909SZhong Yang #include <zmouse.h>
408af74909SZhong Yang #include <ole2.h>
418af74909SZhong Yang
428af74909SZhong Yang #if !defined(DISABLE_D2D)
438af74909SZhong Yang #define USE_D2D 1
448af74909SZhong Yang #endif
458af74909SZhong Yang
468af74909SZhong Yang #if defined(USE_D2D)
478af74909SZhong Yang #include <d2d1.h>
488af74909SZhong Yang #include <dwrite.h>
498af74909SZhong Yang #endif
508af74909SZhong Yang
518af74909SZhong Yang #include "Platform.h"
528af74909SZhong Yang
538af74909SZhong Yang #include "ILoader.h"
548af74909SZhong Yang #include "ILexer.h"
558af74909SZhong Yang #include "Scintilla.h"
568af74909SZhong Yang
578af74909SZhong Yang #include "CharacterCategory.h"
588af74909SZhong Yang #include "Position.h"
598af74909SZhong Yang #include "UniqueString.h"
608af74909SZhong Yang #include "SplitVector.h"
618af74909SZhong Yang #include "Partitioning.h"
628af74909SZhong Yang #include "RunStyles.h"
638af74909SZhong Yang #include "ContractionState.h"
648af74909SZhong Yang #include "CellBuffer.h"
658af74909SZhong Yang #include "CallTip.h"
668af74909SZhong Yang #include "KeyMap.h"
678af74909SZhong Yang #include "Indicator.h"
688af74909SZhong Yang #include "LineMarker.h"
698af74909SZhong Yang #include "Style.h"
708af74909SZhong Yang #include "ViewStyle.h"
718af74909SZhong Yang #include "CharClassify.h"
728af74909SZhong Yang #include "Decoration.h"
738af74909SZhong Yang #include "CaseFolder.h"
748af74909SZhong Yang #include "Document.h"
758af74909SZhong Yang #include "CaseConvert.h"
768af74909SZhong Yang #include "UniConversion.h"
778af74909SZhong Yang #include "Selection.h"
788af74909SZhong Yang #include "PositionCache.h"
798af74909SZhong Yang #include "EditModel.h"
808af74909SZhong Yang #include "MarginView.h"
818af74909SZhong Yang #include "EditView.h"
828af74909SZhong Yang #include "Editor.h"
838af74909SZhong Yang #include "ElapsedPeriod.h"
848af74909SZhong Yang
858af74909SZhong Yang #include "AutoComplete.h"
868af74909SZhong Yang #include "ScintillaBase.h"
878af74909SZhong Yang
888af74909SZhong Yang #include "PlatWin.h"
898af74909SZhong Yang #include "HanjaDic.h"
908af74909SZhong Yang #include "ScintillaWin.h"
918af74909SZhong Yang
928af74909SZhong Yang #ifndef SPI_GETWHEELSCROLLLINES
938af74909SZhong Yang #define SPI_GETWHEELSCROLLLINES 104
948af74909SZhong Yang #endif
958af74909SZhong Yang
968af74909SZhong Yang #ifndef WM_UNICHAR
978af74909SZhong Yang #define WM_UNICHAR 0x0109
988af74909SZhong Yang #endif
998af74909SZhong Yang
1008af74909SZhong Yang #ifndef WM_DPICHANGED
1018af74909SZhong Yang #define WM_DPICHANGED 0x02E0
1028af74909SZhong Yang #endif
1038af74909SZhong Yang #ifndef WM_DPICHANGED_AFTERPARENT
1048af74909SZhong Yang #define WM_DPICHANGED_AFTERPARENT 0x02E3
1058af74909SZhong Yang #endif
1068af74909SZhong Yang
1078af74909SZhong Yang #ifndef UNICODE_NOCHAR
1088af74909SZhong Yang #define UNICODE_NOCHAR 0xFFFF
1098af74909SZhong Yang #endif
1108af74909SZhong Yang
1118af74909SZhong Yang #ifndef IS_HIGH_SURROGATE
1128af74909SZhong Yang #define IS_HIGH_SURROGATE(x) ((x) >= SURROGATE_LEAD_FIRST && (x) <= SURROGATE_LEAD_LAST)
1138af74909SZhong Yang #endif
1148af74909SZhong Yang
1158af74909SZhong Yang #ifndef IS_LOW_SURROGATE
1168af74909SZhong Yang #define IS_LOW_SURROGATE(x) ((x) >= SURROGATE_TRAIL_FIRST && (x) <= SURROGATE_TRAIL_LAST)
1178af74909SZhong Yang #endif
1188af74909SZhong Yang
1198af74909SZhong Yang #ifndef MK_ALT
1208af74909SZhong Yang #define MK_ALT 32
1218af74909SZhong Yang #endif
1228af74909SZhong Yang
1238af74909SZhong Yang // Two idle messages SC_WIN_IDLE and SC_WORK_IDLE.
1248af74909SZhong Yang
1258af74909SZhong Yang // SC_WIN_IDLE is low priority so should occur after the next WM_PAINT
1268af74909SZhong Yang // It is for lengthy actions like wrapping and background styling
1278af74909SZhong Yang constexpr UINT SC_WIN_IDLE = 5001;
1288af74909SZhong Yang // SC_WORK_IDLE is high priority and should occur before the next WM_PAINT
1298af74909SZhong Yang // It is for shorter actions like restyling the text just inserted
1308af74909SZhong Yang // and delivering SCN_UPDATEUI
1318af74909SZhong Yang constexpr UINT SC_WORK_IDLE = 5002;
1328af74909SZhong Yang
1338af74909SZhong Yang #define SC_INDICATOR_INPUT INDICATOR_IME
1348af74909SZhong Yang #define SC_INDICATOR_TARGET INDICATOR_IME+1
1358af74909SZhong Yang #define SC_INDICATOR_CONVERTED INDICATOR_IME+2
1368af74909SZhong Yang #define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX
1378af74909SZhong Yang
1388af74909SZhong Yang #ifndef SCS_CAP_SETRECONVERTSTRING
1398af74909SZhong Yang #define SCS_CAP_SETRECONVERTSTRING 0x00000004
1408af74909SZhong Yang #define SCS_QUERYRECONVERTSTRING 0x00020000
1418af74909SZhong Yang #define SCS_SETRECONVERTSTRING 0x00010000
1428af74909SZhong Yang #endif
1438af74909SZhong Yang
1448af74909SZhong Yang typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent,
1458af74909SZhong Yang UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
1468af74909SZhong Yang
1478af74909SZhong Yang // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
1488af74909SZhong Yang
1498af74909SZhong Yang using namespace Scintilla;
1508af74909SZhong Yang
1518af74909SZhong Yang namespace {
1528af74909SZhong Yang
1538af74909SZhong Yang const TCHAR callClassName[] = TEXT("CallTip");
1548af74909SZhong Yang
SetWindowID(HWND hWnd,int identifier)1558af74909SZhong Yang void SetWindowID(HWND hWnd, int identifier) noexcept {
1568af74909SZhong Yang ::SetWindowLongPtr(hWnd, GWLP_ID, identifier);
1578af74909SZhong Yang }
1588af74909SZhong Yang
PointFromLParam(sptr_t lpoint)1598af74909SZhong Yang Point PointFromLParam(sptr_t lpoint) noexcept {
1608af74909SZhong Yang return Point::FromInts(GET_X_LPARAM(lpoint), GET_Y_LPARAM(lpoint));
1618af74909SZhong Yang }
1628af74909SZhong Yang
KeyboardIsKeyDown(int key)1638af74909SZhong Yang bool KeyboardIsKeyDown(int key) noexcept {
1648af74909SZhong Yang return (::GetKeyState(key) & 0x80000000) != 0;
1658af74909SZhong Yang }
1668af74909SZhong Yang
KeyboardIsNumericKeypadFunction(uptr_t wParam,sptr_t lParam)1678af74909SZhong Yang constexpr bool KeyboardIsNumericKeypadFunction(uptr_t wParam, sptr_t lParam) {
1688af74909SZhong Yang // Bit 24 is the extended keyboard flag and the numeric keypad is non-extended
1698af74909SZhong Yang if ((lParam & (1 << 24)) != 0) {
1708af74909SZhong Yang // Not from the numeric keypad
1718af74909SZhong Yang return false;
1728af74909SZhong Yang }
1738af74909SZhong Yang
1748af74909SZhong Yang switch (wParam) {
1758af74909SZhong Yang case VK_INSERT: // 0
1768af74909SZhong Yang case VK_END: // 1
1778af74909SZhong Yang case VK_DOWN: // 2
1788af74909SZhong Yang case VK_NEXT: // 3
1798af74909SZhong Yang case VK_LEFT: // 4
1808af74909SZhong Yang case VK_CLEAR: // 5
1818af74909SZhong Yang case VK_RIGHT: // 6
1828af74909SZhong Yang case VK_HOME: // 7
1838af74909SZhong Yang case VK_UP: // 8
1848af74909SZhong Yang case VK_PRIOR: // 9
1858af74909SZhong Yang return true;
1868af74909SZhong Yang default:
1878af74909SZhong Yang return false;
1888af74909SZhong Yang }
1898af74909SZhong Yang }
1908af74909SZhong Yang
1918af74909SZhong Yang }
1928af74909SZhong Yang
1938af74909SZhong Yang class ScintillaWin; // Forward declaration for COM interface subobjects
1948af74909SZhong Yang
1958af74909SZhong Yang typedef void VFunction(void);
1968af74909SZhong Yang
1978af74909SZhong Yang
1988af74909SZhong Yang /**
1998af74909SZhong Yang */
2008af74909SZhong Yang class FormatEnumerator {
2018af74909SZhong Yang public:
2028af74909SZhong Yang VFunction **vtbl;
2038af74909SZhong Yang ULONG ref;
2048af74909SZhong Yang ULONG pos;
2058af74909SZhong Yang std::vector<CLIPFORMAT> formats;
2068af74909SZhong Yang FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_);
2078af74909SZhong Yang };
2088af74909SZhong Yang
2098af74909SZhong Yang /**
2108af74909SZhong Yang */
2118af74909SZhong Yang class DropSource {
2128af74909SZhong Yang public:
2138af74909SZhong Yang VFunction **vtbl;
2148af74909SZhong Yang ScintillaWin *sci;
2158af74909SZhong Yang DropSource() noexcept;
2168af74909SZhong Yang };
2178af74909SZhong Yang
2188af74909SZhong Yang /**
2198af74909SZhong Yang */
2208af74909SZhong Yang class DataObject {
2218af74909SZhong Yang public:
2228af74909SZhong Yang VFunction **vtbl;
2238af74909SZhong Yang ScintillaWin *sci;
2248af74909SZhong Yang DataObject() noexcept;
2258af74909SZhong Yang };
2268af74909SZhong Yang
2278af74909SZhong Yang /**
2288af74909SZhong Yang */
2298af74909SZhong Yang class DropTarget {
2308af74909SZhong Yang public:
2318af74909SZhong Yang VFunction **vtbl;
2328af74909SZhong Yang ScintillaWin *sci;
2338af74909SZhong Yang DropTarget() noexcept;
2348af74909SZhong Yang };
2358af74909SZhong Yang
2368af74909SZhong Yang namespace {
2378af74909SZhong Yang
2388af74909SZhong Yang class IMContext {
2398af74909SZhong Yang HWND hwnd;
2408af74909SZhong Yang public:
2418af74909SZhong Yang HIMC hIMC;
IMContext(HWND hwnd_)2428af74909SZhong Yang IMContext(HWND hwnd_) noexcept :
2438af74909SZhong Yang hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) {
2448af74909SZhong Yang }
2458af74909SZhong Yang // Deleted so IMContext objects can not be copied.
2468af74909SZhong Yang IMContext(const IMContext &) = delete;
2478af74909SZhong Yang IMContext(IMContext &&) = delete;
2488af74909SZhong Yang IMContext &operator=(const IMContext &) = delete;
2498af74909SZhong Yang IMContext &operator=(IMContext &&) = delete;
~IMContext()2508af74909SZhong Yang ~IMContext() {
2518af74909SZhong Yang if (hIMC)
2528af74909SZhong Yang ::ImmReleaseContext(hwnd, hIMC);
2538af74909SZhong Yang }
2548af74909SZhong Yang
GetImeCaretPos() const2558af74909SZhong Yang unsigned int GetImeCaretPos() const noexcept {
2568af74909SZhong Yang return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0);
2578af74909SZhong Yang }
2588af74909SZhong Yang
GetImeAttributes()2598af74909SZhong Yang std::vector<BYTE> GetImeAttributes() {
2608af74909SZhong Yang const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, nullptr, 0);
2618af74909SZhong Yang std::vector<BYTE> attr(attrLen, 0);
2628af74909SZhong Yang ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast<DWORD>(attr.size()));
2638af74909SZhong Yang return attr;
2648af74909SZhong Yang }
2658af74909SZhong Yang
GetCompositionString(DWORD dwIndex)2668af74909SZhong Yang std::wstring GetCompositionString(DWORD dwIndex) {
2678af74909SZhong Yang const LONG byteLen = ::ImmGetCompositionStringW(hIMC, dwIndex, nullptr, 0);
2688af74909SZhong Yang std::wstring wcs(byteLen / 2, 0);
2698af74909SZhong Yang ::ImmGetCompositionStringW(hIMC, dwIndex, &wcs[0], byteLen);
2708af74909SZhong Yang return wcs;
2718af74909SZhong Yang }
2728af74909SZhong Yang };
2738af74909SZhong Yang
2748af74909SZhong Yang class GlobalMemory;
2758af74909SZhong Yang
2768af74909SZhong Yang class ReverseArrowCursor {
2778af74909SZhong Yang UINT dpi = USER_DEFAULT_SCREEN_DPI;
2788af74909SZhong Yang HCURSOR cursor {};
2798af74909SZhong Yang
2808af74909SZhong Yang public:
ReverseArrowCursor()2818af74909SZhong Yang ReverseArrowCursor() noexcept {}
2828af74909SZhong Yang // Deleted so ReverseArrowCursor objects can not be copied.
2838af74909SZhong Yang ReverseArrowCursor(const ReverseArrowCursor &) = delete;
2848af74909SZhong Yang ReverseArrowCursor(ReverseArrowCursor &&) = delete;
2858af74909SZhong Yang ReverseArrowCursor &operator=(const ReverseArrowCursor &) = delete;
2868af74909SZhong Yang ReverseArrowCursor &operator=(ReverseArrowCursor &&) = delete;
~ReverseArrowCursor()2878af74909SZhong Yang ~ReverseArrowCursor() {
2888af74909SZhong Yang if (cursor) {
2898af74909SZhong Yang ::DestroyCursor(cursor);
2908af74909SZhong Yang }
2918af74909SZhong Yang }
2928af74909SZhong Yang
Load(UINT dpi_)2938af74909SZhong Yang HCURSOR Load(UINT dpi_) noexcept {
2948af74909SZhong Yang if (cursor) {
2958af74909SZhong Yang if (dpi == dpi_) {
2968af74909SZhong Yang return cursor;
2978af74909SZhong Yang }
2988af74909SZhong Yang ::DestroyCursor(cursor);
2998af74909SZhong Yang }
3008af74909SZhong Yang
3018af74909SZhong Yang dpi = dpi_;
3028af74909SZhong Yang cursor = LoadReverseArrowCursor(dpi_);
3038af74909SZhong Yang return cursor ? cursor : ::LoadCursor({}, IDC_ARROW);
3048af74909SZhong Yang }
3058af74909SZhong Yang };
3068af74909SZhong Yang
3078af74909SZhong Yang }
3088af74909SZhong Yang
3098af74909SZhong Yang /**
3108af74909SZhong Yang */
3118af74909SZhong Yang class ScintillaWin :
3128af74909SZhong Yang public ScintillaBase {
3138af74909SZhong Yang
3148af74909SZhong Yang bool lastKeyDownConsumed;
3158af74909SZhong Yang wchar_t lastHighSurrogateChar;
3168af74909SZhong Yang
3178af74909SZhong Yang bool capturedMouse;
3188af74909SZhong Yang bool trackedMouseLeave;
3198af74909SZhong Yang SetCoalescableTimerSig SetCoalescableTimerFn;
3208af74909SZhong Yang
3218af74909SZhong Yang unsigned int linesPerScroll; ///< Intellimouse support
3228af74909SZhong Yang int wheelDelta; ///< Wheel delta from roll
3238af74909SZhong Yang
3248af74909SZhong Yang UINT dpi = USER_DEFAULT_SCREEN_DPI;
3258af74909SZhong Yang ReverseArrowCursor reverseArrowCursor;
3268af74909SZhong Yang
3278af74909SZhong Yang HRGN hRgnUpdate;
3288af74909SZhong Yang
3298af74909SZhong Yang bool hasOKText;
3308af74909SZhong Yang
3318af74909SZhong Yang CLIPFORMAT cfColumnSelect;
3328af74909SZhong Yang CLIPFORMAT cfBorlandIDEBlockType;
3338af74909SZhong Yang CLIPFORMAT cfLineSelect;
3348af74909SZhong Yang CLIPFORMAT cfVSLineTag;
3358af74909SZhong Yang
3368af74909SZhong Yang HRESULT hrOle;
3378af74909SZhong Yang DropSource ds;
3388af74909SZhong Yang DataObject dob;
3398af74909SZhong Yang DropTarget dt;
3408af74909SZhong Yang
3418af74909SZhong Yang static HINSTANCE hInstance;
3428af74909SZhong Yang static ATOM scintillaClassAtom;
3438af74909SZhong Yang static ATOM callClassAtom;
3448af74909SZhong Yang
3458af74909SZhong Yang #if defined(USE_D2D)
3468af74909SZhong Yang ID2D1RenderTarget *pRenderTarget;
3478af74909SZhong Yang bool renderTargetValid;
3488af74909SZhong Yang #endif
3498af74909SZhong Yang
3508af74909SZhong Yang explicit ScintillaWin(HWND hwnd);
3518af74909SZhong Yang // Deleted so ScintillaWin objects can not be copied.
3528af74909SZhong Yang ScintillaWin(const ScintillaWin &) = delete;
3538af74909SZhong Yang ScintillaWin(ScintillaWin &&) = delete;
3548af74909SZhong Yang ScintillaWin &operator=(const ScintillaWin &) = delete;
3558af74909SZhong Yang ScintillaWin &operator=(ScintillaWin &&) = delete;
3568af74909SZhong Yang // ~ScintillaWin() in public section
3578af74909SZhong Yang
3588af74909SZhong Yang void Init();
3598af74909SZhong Yang void Finalise() override;
3608af74909SZhong Yang #if defined(USE_D2D)
3618af74909SZhong Yang void EnsureRenderTarget(HDC hdc);
3628af74909SZhong Yang void DropRenderTarget();
3638af74909SZhong Yang #endif
3648af74909SZhong Yang HWND MainHWND() const noexcept;
3658af74909SZhong Yang
3668af74909SZhong Yang static sptr_t DirectFunction(
3678af74909SZhong Yang sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam);
3688af74909SZhong Yang static LRESULT PASCAL SWndProc(
3698af74909SZhong Yang HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
3708af74909SZhong Yang static LRESULT PASCAL CTWndProc(
3718af74909SZhong Yang HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
3728af74909SZhong Yang
3738af74909SZhong Yang enum : UINT_PTR { invalidTimerID, standardTimerID, idleTimerID, fineTimerStart };
3748af74909SZhong Yang
3758af74909SZhong Yang void DisplayCursor(Window::Cursor c) override;
3768af74909SZhong Yang bool DragThreshold(Point ptStart, Point ptNow) override;
3778af74909SZhong Yang void StartDrag() override;
3788af74909SZhong Yang static int MouseModifiers(uptr_t wParam) noexcept;
3798af74909SZhong Yang
3808af74909SZhong Yang Sci::Position TargetAsUTF8(char *text) const;
3818af74909SZhong Yang Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
3828af74909SZhong Yang
3838af74909SZhong Yang bool PaintDC(HDC hdc);
3848af74909SZhong Yang sptr_t WndPaint();
3858af74909SZhong Yang
3868af74909SZhong Yang // DBCS
3878af74909SZhong Yang void ImeStartComposition();
3888af74909SZhong Yang void ImeEndComposition();
3898af74909SZhong Yang LRESULT ImeOnReconvert(LPARAM lParam);
3908af74909SZhong Yang sptr_t HandleCompositionWindowed(uptr_t wParam, sptr_t lParam);
3918af74909SZhong Yang sptr_t HandleCompositionInline(uptr_t wParam, sptr_t lParam);
3928af74909SZhong Yang static bool KoreanIME() noexcept;
3938af74909SZhong Yang void MoveImeCarets(Sci::Position offset);
3948af74909SZhong Yang void DrawImeIndicator(int indicator, Sci::Position len);
3958af74909SZhong Yang void SetCandidateWindowPos();
3968af74909SZhong Yang void SelectionToHangul();
3978af74909SZhong Yang void EscapeHanja();
3988af74909SZhong Yang void ToggleHanja();
3998af74909SZhong Yang void AddWString(std::wstring_view wsv, CharacterSource charSource);
4008af74909SZhong Yang
4018af74909SZhong Yang UINT CodePageOfDocument() const noexcept;
4028af74909SZhong Yang bool ValidCodePage(int codePage) const override;
4038af74909SZhong Yang std::string EncodeWString(std::wstring_view wsv);
4048af74909SZhong Yang sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
4058af74909SZhong Yang void IdleWork() override;
4068af74909SZhong Yang void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) override;
4078af74909SZhong Yang bool SetIdle(bool on) override;
4088af74909SZhong Yang UINT_PTR timers[tickDwell+1] {};
4098af74909SZhong Yang bool FineTickerRunning(TickReason reason) override;
4108af74909SZhong Yang void FineTickerStart(TickReason reason, int millis, int tolerance) override;
4118af74909SZhong Yang void FineTickerCancel(TickReason reason) override;
4128af74909SZhong Yang void SetMouseCapture(bool on) override;
4138af74909SZhong Yang bool HaveMouseCapture() override;
4148af74909SZhong Yang void SetTrackMouseLeaveEvent(bool on) noexcept;
4158af74909SZhong Yang bool PaintContains(PRectangle rc) override;
4168af74909SZhong Yang void ScrollText(Sci::Line linesToMove) override;
4178af74909SZhong Yang void NotifyCaretMove() override;
4188af74909SZhong Yang void UpdateSystemCaret() override;
4198af74909SZhong Yang void SetVerticalScrollPos() override;
4208af74909SZhong Yang void SetHorizontalScrollPos() override;
4218af74909SZhong Yang bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override;
4228af74909SZhong Yang void NotifyChange() override;
4238af74909SZhong Yang void NotifyFocus(bool focus) override;
4248af74909SZhong Yang void SetCtrlID(int identifier) override;
4258af74909SZhong Yang int GetCtrlID() override;
4268af74909SZhong Yang void NotifyParent(SCNotification scn) override;
4278af74909SZhong Yang void NotifyDoubleClick(Point pt, int modifiers) override;
4288af74909SZhong Yang CaseFolder *CaseFolderForEncoding() override;
4298af74909SZhong Yang std::string CaseMapString(const std::string &s, int caseMapping) override;
4308af74909SZhong Yang void Copy() override;
4318af74909SZhong Yang bool CanPaste() override;
4328af74909SZhong Yang void Paste() override;
4338af74909SZhong Yang void CreateCallTipWindow(PRectangle rc) override;
434*f9763b28Slrisora void AddToPopUp(const wchar_t *label, int cmd = 0, bool enabled = true) override;
4358af74909SZhong Yang void ClaimSelection() override;
4368af74909SZhong Yang
4378af74909SZhong Yang void GetIntelliMouseParameters() noexcept;
4388af74909SZhong Yang void CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText);
4398af74909SZhong Yang void CopyToClipboard(const SelectionText &selectedText) override;
4408af74909SZhong Yang void ScrollMessage(WPARAM wParam);
4418af74909SZhong Yang void HorizontalScrollMessage(WPARAM wParam);
4428af74909SZhong Yang void FullPaint();
4438af74909SZhong Yang void FullPaintDC(HDC hdc);
4448af74909SZhong Yang bool IsCompatibleDC(HDC hOtherDC) noexcept;
4458af74909SZhong Yang DWORD EffectFromState(DWORD grfKeyState) const noexcept;
4468af74909SZhong Yang
4478af74909SZhong Yang int SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept;
4488af74909SZhong Yang bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept;
4498af74909SZhong Yang void ChangeScrollPos(int barType, Sci::Position pos);
4508af74909SZhong Yang sptr_t GetTextLength();
4518af74909SZhong Yang sptr_t GetText(uptr_t wParam, sptr_t lParam);
4528af74909SZhong Yang Window::Cursor ContextCursor(Point pt);
4538af74909SZhong Yang sptr_t ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4548af74909SZhong Yang void SizeWindow();
4558af74909SZhong Yang sptr_t MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4568af74909SZhong Yang sptr_t KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4578af74909SZhong Yang sptr_t FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4588af74909SZhong Yang sptr_t IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4598af74909SZhong Yang sptr_t EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4608af74909SZhong Yang sptr_t IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4618af74909SZhong Yang sptr_t SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
4628af74909SZhong Yang
4638af74909SZhong Yang public:
4648af74909SZhong Yang ~ScintillaWin() override;
4658af74909SZhong Yang
4668af74909SZhong Yang // Public for benefit of Scintilla_DirectFunction
4678af74909SZhong Yang sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
4688af74909SZhong Yang
4698af74909SZhong Yang /// Implement IUnknown
4708af74909SZhong Yang STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv);
4718af74909SZhong Yang STDMETHODIMP_(ULONG)AddRef();
4728af74909SZhong Yang STDMETHODIMP_(ULONG)Release();
4738af74909SZhong Yang
4748af74909SZhong Yang /// Implement IDropTarget
4758af74909SZhong Yang STDMETHODIMP DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
4768af74909SZhong Yang POINTL pt, PDWORD pdwEffect);
4778af74909SZhong Yang STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect);
4788af74909SZhong Yang STDMETHODIMP DragLeave();
4798af74909SZhong Yang STDMETHODIMP Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
4808af74909SZhong Yang POINTL pt, PDWORD pdwEffect);
4818af74909SZhong Yang
4828af74909SZhong Yang /// Implement important part of IDataObject
4838af74909SZhong Yang STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM);
4848af74909SZhong Yang
4858af74909SZhong Yang static void Prepare() noexcept;
4868af74909SZhong Yang static bool Register(HINSTANCE hInstance_) noexcept;
4878af74909SZhong Yang static bool Unregister() noexcept;
4888af74909SZhong Yang
4898af74909SZhong Yang friend class DropSource;
4908af74909SZhong Yang friend class DataObject;
4918af74909SZhong Yang friend class DropTarget;
DragIsRectangularOK(CLIPFORMAT fmt) const4928af74909SZhong Yang bool DragIsRectangularOK(CLIPFORMAT fmt) const noexcept {
4938af74909SZhong Yang return drag.rectangular && (fmt == cfColumnSelect);
4948af74909SZhong Yang }
4958af74909SZhong Yang
4968af74909SZhong Yang private:
4978af74909SZhong Yang // For use in creating a system caret
4988af74909SZhong Yang bool HasCaretSizeChanged() const noexcept;
4998af74909SZhong Yang BOOL CreateSystemCaret();
5008af74909SZhong Yang BOOL DestroySystemCaret() noexcept;
5018af74909SZhong Yang HBITMAP sysCaretBitmap;
5028af74909SZhong Yang int sysCaretWidth;
5038af74909SZhong Yang int sysCaretHeight;
5048af74909SZhong Yang bool styleIdleInQueue;
5058af74909SZhong Yang };
5068af74909SZhong Yang
5078af74909SZhong Yang HINSTANCE ScintillaWin::hInstance {};
5088af74909SZhong Yang ATOM ScintillaWin::scintillaClassAtom = 0;
5098af74909SZhong Yang ATOM ScintillaWin::callClassAtom = 0;
5108af74909SZhong Yang
ScintillaWin(HWND hwnd)5118af74909SZhong Yang ScintillaWin::ScintillaWin(HWND hwnd) {
5128af74909SZhong Yang
5138af74909SZhong Yang lastKeyDownConsumed = false;
5148af74909SZhong Yang lastHighSurrogateChar = 0;
5158af74909SZhong Yang
5168af74909SZhong Yang capturedMouse = false;
5178af74909SZhong Yang trackedMouseLeave = false;
5188af74909SZhong Yang SetCoalescableTimerFn = nullptr;
5198af74909SZhong Yang
5208af74909SZhong Yang linesPerScroll = 0;
5218af74909SZhong Yang wheelDelta = 0; // Wheel delta from roll
5228af74909SZhong Yang
5238af74909SZhong Yang dpi = DpiForWindow(hwnd);
5248af74909SZhong Yang
5258af74909SZhong Yang hRgnUpdate = {};
5268af74909SZhong Yang
5278af74909SZhong Yang hasOKText = false;
5288af74909SZhong Yang
5298af74909SZhong Yang // There does not seem to be a real standard for indicating that the clipboard
5308af74909SZhong Yang // contains a rectangular selection, so copy Developer Studio and Borland Delphi.
5318af74909SZhong Yang cfColumnSelect = static_cast<CLIPFORMAT>(
5328af74909SZhong Yang ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
5338af74909SZhong Yang cfBorlandIDEBlockType = static_cast<CLIPFORMAT>(
5348af74909SZhong Yang ::RegisterClipboardFormat(TEXT("Borland IDE Block Type")));
5358af74909SZhong Yang
5368af74909SZhong Yang // Likewise for line-copy (copies a full line when no text is selected)
5378af74909SZhong Yang cfLineSelect = static_cast<CLIPFORMAT>(
5388af74909SZhong Yang ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
5398af74909SZhong Yang cfVSLineTag = static_cast<CLIPFORMAT>(
5408af74909SZhong Yang ::RegisterClipboardFormat(TEXT("VisualStudioEditorOperationsLineCutCopyClipboardTag")));
5418af74909SZhong Yang hrOle = E_FAIL;
5428af74909SZhong Yang
5438af74909SZhong Yang wMain = hwnd;
5448af74909SZhong Yang
5458af74909SZhong Yang dob.sci = this;
5468af74909SZhong Yang ds.sci = this;
5478af74909SZhong Yang dt.sci = this;
5488af74909SZhong Yang
5498af74909SZhong Yang sysCaretBitmap = {};
5508af74909SZhong Yang sysCaretWidth = 0;
5518af74909SZhong Yang sysCaretHeight = 0;
5528af74909SZhong Yang
5538af74909SZhong Yang styleIdleInQueue = false;
5548af74909SZhong Yang
5558af74909SZhong Yang #if defined(USE_D2D)
5568af74909SZhong Yang pRenderTarget = nullptr;
5578af74909SZhong Yang renderTargetValid = true;
5588af74909SZhong Yang #endif
5598af74909SZhong Yang
5608af74909SZhong Yang caret.period = ::GetCaretBlinkTime();
5618af74909SZhong Yang if (caret.period < 0)
5628af74909SZhong Yang caret.period = 0;
5638af74909SZhong Yang
5648af74909SZhong Yang Init();
5658af74909SZhong Yang }
5668af74909SZhong Yang
~ScintillaWin()5678af74909SZhong Yang ScintillaWin::~ScintillaWin() {}
5688af74909SZhong Yang
Init()5698af74909SZhong Yang void ScintillaWin::Init() {
5708af74909SZhong Yang // Initialize COM. If the app has already done this it will have
5718af74909SZhong Yang // no effect. If the app hasn't, we really shouldn't ask them to call
5728af74909SZhong Yang // it just so this internal feature works.
5738af74909SZhong Yang hrOle = ::OleInitialize(nullptr);
5748af74909SZhong Yang
5758af74909SZhong Yang // Find SetCoalescableTimer which is only available from Windows 8+
5768af74909SZhong Yang HMODULE user32 = ::GetModuleHandleW(L"user32.dll");
5778af74909SZhong Yang SetCoalescableTimerFn = DLLFunction<SetCoalescableTimerSig>(user32, "SetCoalescableTimer");
5788af74909SZhong Yang
5798af74909SZhong Yang vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(INDIC_HIDDEN, ColourDesired(0, 0, 0xff));
5808af74909SZhong Yang vs.indicators[SC_INDICATOR_INPUT] = Indicator(INDIC_DOTS, ColourDesired(0, 0, 0xff));
5818af74909SZhong Yang vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(INDIC_COMPOSITIONTHICK, ColourDesired(0, 0, 0xff));
5828af74909SZhong Yang vs.indicators[SC_INDICATOR_TARGET] = Indicator(INDIC_STRAIGHTBOX, ColourDesired(0, 0, 0xff));
5838af74909SZhong Yang }
5848af74909SZhong Yang
Finalise()5858af74909SZhong Yang void ScintillaWin::Finalise() {
5868af74909SZhong Yang ScintillaBase::Finalise();
5878af74909SZhong Yang for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
5888af74909SZhong Yang FineTickerCancel(tr);
5898af74909SZhong Yang }
5908af74909SZhong Yang SetIdle(false);
5918af74909SZhong Yang #if defined(USE_D2D)
5928af74909SZhong Yang DropRenderTarget();
5938af74909SZhong Yang #endif
5948af74909SZhong Yang ::RevokeDragDrop(MainHWND());
5958af74909SZhong Yang if (SUCCEEDED(hrOle)) {
5968af74909SZhong Yang ::OleUninitialize();
5978af74909SZhong Yang }
5988af74909SZhong Yang }
5998af74909SZhong Yang
6008af74909SZhong Yang #if defined(USE_D2D)
6018af74909SZhong Yang
EnsureRenderTarget(HDC hdc)6028af74909SZhong Yang void ScintillaWin::EnsureRenderTarget(HDC hdc) {
6038af74909SZhong Yang if (!renderTargetValid) {
6048af74909SZhong Yang DropRenderTarget();
6058af74909SZhong Yang renderTargetValid = true;
6068af74909SZhong Yang }
6078af74909SZhong Yang if (pD2DFactory && !pRenderTarget) {
6088af74909SZhong Yang HWND hw = MainHWND();
6098af74909SZhong Yang RECT rc;
6108af74909SZhong Yang GetClientRect(hw, &rc);
6118af74909SZhong Yang
6128af74909SZhong Yang const D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
6138af74909SZhong Yang
6148af74909SZhong Yang // Create a Direct2D render target.
6158af74909SZhong Yang #if 1
6168af74909SZhong Yang D2D1_RENDER_TARGET_PROPERTIES drtp;
6178af74909SZhong Yang drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
6188af74909SZhong Yang drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
6198af74909SZhong Yang drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
6208af74909SZhong Yang drtp.dpiX = 96.0;
6218af74909SZhong Yang drtp.dpiY = 96.0;
6228af74909SZhong Yang drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
6238af74909SZhong Yang drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
6248af74909SZhong Yang
6258af74909SZhong Yang if (technology == SC_TECHNOLOGY_DIRECTWRITEDC) {
6268af74909SZhong Yang // Explicit pixel format needed.
6278af74909SZhong Yang drtp.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
6288af74909SZhong Yang D2D1_ALPHA_MODE_IGNORE);
6298af74909SZhong Yang
6308af74909SZhong Yang ID2D1DCRenderTarget *pDCRT = nullptr;
6318af74909SZhong Yang const HRESULT hr = pD2DFactory->CreateDCRenderTarget(&drtp, &pDCRT);
6328af74909SZhong Yang if (SUCCEEDED(hr)) {
6338af74909SZhong Yang pRenderTarget = pDCRT;
6348af74909SZhong Yang } else {
6358af74909SZhong Yang Platform::DebugPrintf("Failed CreateDCRenderTarget 0x%lx\n", hr);
6368af74909SZhong Yang pRenderTarget = nullptr;
6378af74909SZhong Yang }
6388af74909SZhong Yang
6398af74909SZhong Yang } else {
6408af74909SZhong Yang D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp;
6418af74909SZhong Yang dhrtp.hwnd = hw;
6428af74909SZhong Yang dhrtp.pixelSize = size;
6438af74909SZhong Yang dhrtp.presentOptions = (technology == SC_TECHNOLOGY_DIRECTWRITERETAIN) ?
6448af74909SZhong Yang D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE;
6458af74909SZhong Yang
6468af74909SZhong Yang ID2D1HwndRenderTarget *pHwndRenderTarget = nullptr;
6478af74909SZhong Yang const HRESULT hr = pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pHwndRenderTarget);
6488af74909SZhong Yang if (SUCCEEDED(hr)) {
6498af74909SZhong Yang pRenderTarget = pHwndRenderTarget;
6508af74909SZhong Yang } else {
6518af74909SZhong Yang Platform::DebugPrintf("Failed CreateHwndRenderTarget 0x%lx\n", hr);
6528af74909SZhong Yang pRenderTarget = nullptr;
6538af74909SZhong Yang }
6548af74909SZhong Yang }
6558af74909SZhong Yang #else
6568af74909SZhong Yang pD2DFactory->CreateHwndRenderTarget(
6578af74909SZhong Yang D2D1::RenderTargetProperties(
6588af74909SZhong Yang D2D1_RENDER_TARGET_TYPE_DEFAULT ,
6598af74909SZhong Yang D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
6608af74909SZhong Yang 96.0f, 96.0f, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT),
6618af74909SZhong Yang D2D1::HwndRenderTargetProperties(hw, size),
6628af74909SZhong Yang &pRenderTarget);
6638af74909SZhong Yang #endif
6648af74909SZhong Yang // Pixmaps were created to be compatible with previous render target so
6658af74909SZhong Yang // need to be recreated.
6668af74909SZhong Yang DropGraphics(false);
6678af74909SZhong Yang }
6688af74909SZhong Yang
6698af74909SZhong Yang if ((technology == SC_TECHNOLOGY_DIRECTWRITEDC) && pRenderTarget) {
6708af74909SZhong Yang RECT rcWindow;
6718af74909SZhong Yang GetClientRect(MainHWND(), &rcWindow);
6728af74909SZhong Yang const HRESULT hr = static_cast<ID2D1DCRenderTarget*>(pRenderTarget)->BindDC(hdc, &rcWindow);
6738af74909SZhong Yang if (FAILED(hr)) {
6748af74909SZhong Yang Platform::DebugPrintf("BindDC failed 0x%lx\n", hr);
6758af74909SZhong Yang DropRenderTarget();
6768af74909SZhong Yang }
6778af74909SZhong Yang }
6788af74909SZhong Yang }
6798af74909SZhong Yang
DropRenderTarget()6808af74909SZhong Yang void ScintillaWin::DropRenderTarget() {
6818af74909SZhong Yang ReleaseUnknown(pRenderTarget);
6828af74909SZhong Yang }
6838af74909SZhong Yang
6848af74909SZhong Yang #endif
6858af74909SZhong Yang
MainHWND() const6868af74909SZhong Yang HWND ScintillaWin::MainHWND() const noexcept {
6878af74909SZhong Yang return HwndFromWindow(wMain);
6888af74909SZhong Yang }
6898af74909SZhong Yang
DisplayCursor(Window::Cursor c)6908af74909SZhong Yang void ScintillaWin::DisplayCursor(Window::Cursor c) {
6918af74909SZhong Yang if (cursorMode != SC_CURSORNORMAL) {
6928af74909SZhong Yang c = static_cast<Window::Cursor>(cursorMode);
6938af74909SZhong Yang }
6948af74909SZhong Yang if (c == Window::cursorReverseArrow) {
6958af74909SZhong Yang ::SetCursor(reverseArrowCursor.Load(dpi));
6968af74909SZhong Yang } else {
6978af74909SZhong Yang wMain.SetCursor(c);
6988af74909SZhong Yang }
6998af74909SZhong Yang }
7008af74909SZhong Yang
DragThreshold(Point ptStart,Point ptNow)7018af74909SZhong Yang bool ScintillaWin::DragThreshold(Point ptStart, Point ptNow) {
7028af74909SZhong Yang const Point ptDifference = ptStart - ptNow;
7038af74909SZhong Yang const XYPOSITION xMove = std::trunc(std::abs(ptDifference.x));
7048af74909SZhong Yang const XYPOSITION yMove = std::trunc(std::abs(ptDifference.y));
7058af74909SZhong Yang return (xMove > SystemMetricsForDpi(SM_CXDRAG, dpi)) ||
7068af74909SZhong Yang (yMove > SystemMetricsForDpi(SM_CYDRAG, dpi));
7078af74909SZhong Yang }
7088af74909SZhong Yang
StartDrag()7098af74909SZhong Yang void ScintillaWin::StartDrag() {
7108af74909SZhong Yang inDragDrop = ddDragging;
7118af74909SZhong Yang DWORD dwEffect = 0;
7128af74909SZhong Yang dropWentOutside = true;
7138af74909SZhong Yang IDataObject *pDataObject = reinterpret_cast<IDataObject *>(&dob);
7148af74909SZhong Yang IDropSource *pDropSource = reinterpret_cast<IDropSource *>(&ds);
7158af74909SZhong Yang //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
7168af74909SZhong Yang const HRESULT hr = ::DoDragDrop(
7178af74909SZhong Yang pDataObject,
7188af74909SZhong Yang pDropSource,
7198af74909SZhong Yang DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
7208af74909SZhong Yang //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
7218af74909SZhong Yang if (SUCCEEDED(hr)) {
7228af74909SZhong Yang if ((hr == DRAGDROP_S_DROP) && (dwEffect == DROPEFFECT_MOVE) && dropWentOutside) {
7238af74909SZhong Yang // Remove dragged out text
7248af74909SZhong Yang ClearSelection();
7258af74909SZhong Yang }
7268af74909SZhong Yang }
7278af74909SZhong Yang inDragDrop = ddNone;
7288af74909SZhong Yang SetDragPosition(SelectionPosition(Sci::invalidPosition));
7298af74909SZhong Yang }
7308af74909SZhong Yang
MouseModifiers(uptr_t wParam)7318af74909SZhong Yang int ScintillaWin::MouseModifiers(uptr_t wParam) noexcept {
7328af74909SZhong Yang return ModifierFlags((wParam & MK_SHIFT) != 0,
7338af74909SZhong Yang (wParam & MK_CONTROL) != 0,
7348af74909SZhong Yang KeyboardIsKeyDown(VK_MENU));
7358af74909SZhong Yang }
7368af74909SZhong Yang
7378af74909SZhong Yang namespace {
7388af74909SZhong Yang
InputCodePage()7398af74909SZhong Yang int InputCodePage() noexcept {
7408af74909SZhong Yang HKL inputLocale = ::GetKeyboardLayout(0);
7418af74909SZhong Yang const LANGID inputLang = LOWORD(inputLocale);
7428af74909SZhong Yang char sCodePage[10];
7438af74909SZhong Yang const int res = ::GetLocaleInfoA(MAKELCID(inputLang, SORT_DEFAULT),
7448af74909SZhong Yang LOCALE_IDEFAULTANSICODEPAGE, sCodePage, sizeof(sCodePage));
7458af74909SZhong Yang if (!res)
7468af74909SZhong Yang return 0;
7478af74909SZhong Yang return atoi(sCodePage);
7488af74909SZhong Yang }
7498af74909SZhong Yang
7508af74909SZhong Yang /** Map the key codes to their equivalent SCK_ form. */
KeyTranslate(int keyIn)7518af74909SZhong Yang int KeyTranslate(int keyIn) noexcept {
7528af74909SZhong Yang //PLATFORM_ASSERT(!keyIn);
7538af74909SZhong Yang switch (keyIn) {
7548af74909SZhong Yang case VK_DOWN: return SCK_DOWN;
7558af74909SZhong Yang case VK_UP: return SCK_UP;
7568af74909SZhong Yang case VK_LEFT: return SCK_LEFT;
7578af74909SZhong Yang case VK_RIGHT: return SCK_RIGHT;
7588af74909SZhong Yang case VK_HOME: return SCK_HOME;
7598af74909SZhong Yang case VK_END: return SCK_END;
7608af74909SZhong Yang case VK_PRIOR: return SCK_PRIOR;
7618af74909SZhong Yang case VK_NEXT: return SCK_NEXT;
7628af74909SZhong Yang case VK_DELETE: return SCK_DELETE;
7638af74909SZhong Yang case VK_INSERT: return SCK_INSERT;
7648af74909SZhong Yang case VK_ESCAPE: return SCK_ESCAPE;
7658af74909SZhong Yang case VK_BACK: return SCK_BACK;
7668af74909SZhong Yang case VK_TAB: return SCK_TAB;
7678af74909SZhong Yang case VK_RETURN: return SCK_RETURN;
7688af74909SZhong Yang case VK_ADD: return SCK_ADD;
7698af74909SZhong Yang case VK_SUBTRACT: return SCK_SUBTRACT;
7708af74909SZhong Yang case VK_DIVIDE: return SCK_DIVIDE;
7718af74909SZhong Yang case VK_LWIN: return SCK_WIN;
7728af74909SZhong Yang case VK_RWIN: return SCK_RWIN;
7738af74909SZhong Yang case VK_APPS: return SCK_MENU;
7748af74909SZhong Yang case VK_OEM_2: return '/';
7758af74909SZhong Yang case VK_OEM_3: return '`';
7768af74909SZhong Yang case VK_OEM_4: return '[';
7778af74909SZhong Yang case VK_OEM_5: return '\\';
7788af74909SZhong Yang case VK_OEM_6: return ']';
7798af74909SZhong Yang default: return keyIn;
7808af74909SZhong Yang }
7818af74909SZhong Yang }
7828af74909SZhong Yang
BoundsContains(PRectangle rcBounds,HRGN hRgnBounds,PRectangle rcCheck)7838af74909SZhong Yang bool BoundsContains(PRectangle rcBounds, HRGN hRgnBounds, PRectangle rcCheck) noexcept {
7848af74909SZhong Yang bool contains = true;
7858af74909SZhong Yang if (!rcCheck.Empty()) {
7868af74909SZhong Yang if (!rcBounds.Contains(rcCheck)) {
7878af74909SZhong Yang contains = false;
7888af74909SZhong Yang } else if (hRgnBounds) {
7898af74909SZhong Yang // In bounding rectangle so check more accurately using region
7908af74909SZhong Yang const RECT rcw = RectFromPRectangle(rcCheck);
7918af74909SZhong Yang HRGN hRgnCheck = ::CreateRectRgnIndirect(&rcw);
7928af74909SZhong Yang if (hRgnCheck) {
7938af74909SZhong Yang HRGN hRgnDifference = ::CreateRectRgn(0, 0, 0, 0);
7948af74909SZhong Yang if (hRgnDifference) {
7958af74909SZhong Yang const int combination = ::CombineRgn(hRgnDifference, hRgnCheck, hRgnBounds, RGN_DIFF);
7968af74909SZhong Yang if (combination != NULLREGION) {
7978af74909SZhong Yang contains = false;
7988af74909SZhong Yang }
7998af74909SZhong Yang ::DeleteRgn(hRgnDifference);
8008af74909SZhong Yang }
8018af74909SZhong Yang ::DeleteRgn(hRgnCheck);
8028af74909SZhong Yang }
8038af74909SZhong Yang }
8048af74909SZhong Yang }
8058af74909SZhong Yang return contains;
8068af74909SZhong Yang }
8078af74909SZhong Yang
8088af74909SZhong Yang // Simplify calling WideCharToMultiByte and MultiByteToWideChar by providing default parameters and using string view.
8098af74909SZhong Yang
MultiByteFromWideChar(UINT codePage,std::wstring_view wsv,LPSTR lpMultiByteStr,ptrdiff_t cbMultiByte)8108af74909SZhong Yang int MultiByteFromWideChar(UINT codePage, std::wstring_view wsv, LPSTR lpMultiByteStr, ptrdiff_t cbMultiByte) noexcept {
8118af74909SZhong Yang return ::WideCharToMultiByte(codePage, 0, wsv.data(), static_cast<int>(wsv.length()), lpMultiByteStr, static_cast<int>(cbMultiByte), nullptr, nullptr);
8128af74909SZhong Yang }
8138af74909SZhong Yang
MultiByteLenFromWideChar(UINT codePage,std::wstring_view wsv)8148af74909SZhong Yang int MultiByteLenFromWideChar(UINT codePage, std::wstring_view wsv) noexcept {
8158af74909SZhong Yang return MultiByteFromWideChar(codePage, wsv, nullptr, 0);
8168af74909SZhong Yang }
8178af74909SZhong Yang
WideCharFromMultiByte(UINT codePage,std::string_view sv,LPWSTR lpWideCharStr,ptrdiff_t cchWideChar)8188af74909SZhong Yang int WideCharFromMultiByte(UINT codePage, std::string_view sv, LPWSTR lpWideCharStr, ptrdiff_t cchWideChar) noexcept {
8198af74909SZhong Yang return ::MultiByteToWideChar(codePage, 0, sv.data(), static_cast<int>(sv.length()), lpWideCharStr, static_cast<int>(cchWideChar));
8208af74909SZhong Yang }
8218af74909SZhong Yang
WideCharLenFromMultiByte(UINT codePage,std::string_view sv)8228af74909SZhong Yang int WideCharLenFromMultiByte(UINT codePage, std::string_view sv) noexcept {
8238af74909SZhong Yang return WideCharFromMultiByte(codePage, sv, nullptr, 0);
8248af74909SZhong Yang }
8258af74909SZhong Yang
StringEncode(std::wstring_view wsv,int codePage)8268af74909SZhong Yang std::string StringEncode(std::wstring_view wsv, int codePage) {
8278af74909SZhong Yang const int cchMulti = wsv.length() ? MultiByteLenFromWideChar(codePage, wsv) : 0;
8288af74909SZhong Yang std::string sMulti(cchMulti, 0);
8298af74909SZhong Yang if (cchMulti) {
8308af74909SZhong Yang MultiByteFromWideChar(codePage, wsv, sMulti.data(), cchMulti);
8318af74909SZhong Yang }
8328af74909SZhong Yang return sMulti;
8338af74909SZhong Yang }
8348af74909SZhong Yang
StringDecode(std::string_view sv,int codePage)8358af74909SZhong Yang std::wstring StringDecode(std::string_view sv, int codePage) {
8368af74909SZhong Yang const int cchWide = sv.length() ? WideCharLenFromMultiByte(codePage, sv) : 0;
8378af74909SZhong Yang std::wstring sWide(cchWide, 0);
8388af74909SZhong Yang if (cchWide) {
8398af74909SZhong Yang WideCharFromMultiByte(codePage, sv, sWide.data(), cchWide);
8408af74909SZhong Yang }
8418af74909SZhong Yang return sWide;
8428af74909SZhong Yang }
8438af74909SZhong Yang
StringMapCase(std::wstring_view wsv,DWORD mapFlags)8448af74909SZhong Yang std::wstring StringMapCase(std::wstring_view wsv, DWORD mapFlags) {
8458af74909SZhong Yang const int charsConverted = ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags,
8468af74909SZhong Yang wsv.data(), static_cast<int>(wsv.length()), nullptr, 0);
8478af74909SZhong Yang std::wstring wsConverted(charsConverted, 0);
8488af74909SZhong Yang if (charsConverted) {
8498af74909SZhong Yang ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags,
8508af74909SZhong Yang wsv.data(), static_cast<int>(wsv.length()), wsConverted.data(), charsConverted);
8518af74909SZhong Yang }
8528af74909SZhong Yang return wsConverted;
8538af74909SZhong Yang }
8548af74909SZhong Yang
8558af74909SZhong Yang }
8568af74909SZhong Yang
8578af74909SZhong Yang // Returns the target converted to UTF8.
8588af74909SZhong Yang // Return the length in bytes.
TargetAsUTF8(char * text) const8598af74909SZhong Yang Sci::Position ScintillaWin::TargetAsUTF8(char *text) const {
8608af74909SZhong Yang const Sci::Position targetLength = targetRange.Length();
8618af74909SZhong Yang if (IsUnicodeMode()) {
8628af74909SZhong Yang if (text) {
8638af74909SZhong Yang pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
8648af74909SZhong Yang }
8658af74909SZhong Yang } else {
8668af74909SZhong Yang // Need to convert
8678af74909SZhong Yang const std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position());
8688af74909SZhong Yang const std::wstring characters = StringDecode(s, CodePageOfDocument());
8698af74909SZhong Yang const int utf8Len = MultiByteLenFromWideChar(CP_UTF8, characters);
8708af74909SZhong Yang if (text) {
8718af74909SZhong Yang MultiByteFromWideChar(CP_UTF8, characters, text, utf8Len);
8728af74909SZhong Yang text[utf8Len] = '\0';
8738af74909SZhong Yang }
8748af74909SZhong Yang return utf8Len;
8758af74909SZhong Yang }
8768af74909SZhong Yang return targetLength;
8778af74909SZhong Yang }
8788af74909SZhong Yang
8798af74909SZhong Yang // Translates a nul terminated UTF8 string into the document encoding.
8808af74909SZhong Yang // Return the length of the result in bytes.
EncodedFromUTF8(const char * utf8,char * encoded) const8818af74909SZhong Yang Sci::Position ScintillaWin::EncodedFromUTF8(const char *utf8, char *encoded) const {
8828af74909SZhong Yang const Sci::Position inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
8838af74909SZhong Yang if (IsUnicodeMode()) {
8848af74909SZhong Yang if (encoded) {
8858af74909SZhong Yang memcpy(encoded, utf8, inputLength);
8868af74909SZhong Yang }
8878af74909SZhong Yang return inputLength;
8888af74909SZhong Yang } else {
8898af74909SZhong Yang // Need to convert
8908af74909SZhong Yang const std::string_view utf8Input(utf8, inputLength);
8918af74909SZhong Yang const int charsLen = WideCharLenFromMultiByte(CP_UTF8, utf8Input);
8928af74909SZhong Yang std::wstring characters(charsLen, L'\0');
8938af74909SZhong Yang WideCharFromMultiByte(CP_UTF8, utf8Input, &characters[0], charsLen);
8948af74909SZhong Yang
8958af74909SZhong Yang const int encodedLen = MultiByteLenFromWideChar(CodePageOfDocument(), characters);
8968af74909SZhong Yang if (encoded) {
8978af74909SZhong Yang MultiByteFromWideChar(CodePageOfDocument(), characters, encoded, encodedLen);
8988af74909SZhong Yang encoded[encodedLen] = '\0';
8998af74909SZhong Yang }
9008af74909SZhong Yang return encodedLen;
9018af74909SZhong Yang }
9028af74909SZhong Yang }
9038af74909SZhong Yang
PaintDC(HDC hdc)9048af74909SZhong Yang bool ScintillaWin::PaintDC(HDC hdc) {
9058af74909SZhong Yang if (technology == SC_TECHNOLOGY_DEFAULT) {
9068af74909SZhong Yang AutoSurface surfaceWindow(hdc, this);
9078af74909SZhong Yang if (surfaceWindow) {
9088af74909SZhong Yang Paint(surfaceWindow, rcPaint);
9098af74909SZhong Yang surfaceWindow->Release();
9108af74909SZhong Yang }
9118af74909SZhong Yang } else {
9128af74909SZhong Yang #if defined(USE_D2D)
9138af74909SZhong Yang EnsureRenderTarget(hdc);
9148af74909SZhong Yang if (pRenderTarget) {
9158af74909SZhong Yang AutoSurface surfaceWindow(pRenderTarget, this);
9168af74909SZhong Yang if (surfaceWindow) {
9178af74909SZhong Yang pRenderTarget->BeginDraw();
9188af74909SZhong Yang Paint(surfaceWindow, rcPaint);
9198af74909SZhong Yang surfaceWindow->Release();
9208af74909SZhong Yang const HRESULT hr = pRenderTarget->EndDraw();
9218af74909SZhong Yang if (hr == static_cast<HRESULT>(D2DERR_RECREATE_TARGET)) {
9228af74909SZhong Yang DropRenderTarget();
9238af74909SZhong Yang return false;
9248af74909SZhong Yang }
9258af74909SZhong Yang }
9268af74909SZhong Yang }
9278af74909SZhong Yang #endif
9288af74909SZhong Yang }
9298af74909SZhong Yang
9308af74909SZhong Yang return true;
9318af74909SZhong Yang }
9328af74909SZhong Yang
WndPaint()9338af74909SZhong Yang sptr_t ScintillaWin::WndPaint() {
9348af74909SZhong Yang //ElapsedPeriod ep;
9358af74909SZhong Yang
9368af74909SZhong Yang // Redirect assertions to debug output and save current state
9378af74909SZhong Yang const bool assertsPopup = Platform::ShowAssertionPopUps(false);
9388af74909SZhong Yang paintState = painting;
9398af74909SZhong Yang PAINTSTRUCT ps = {};
9408af74909SZhong Yang
9418af74909SZhong Yang // Removed since this interferes with reporting other assertions as it occurs repeatedly
9428af74909SZhong Yang //PLATFORM_ASSERT(hRgnUpdate == NULL);
9438af74909SZhong Yang hRgnUpdate = ::CreateRectRgn(0, 0, 0, 0);
9448af74909SZhong Yang ::GetUpdateRgn(MainHWND(), hRgnUpdate, FALSE);
9458af74909SZhong Yang ::BeginPaint(MainHWND(), &ps);
9468af74909SZhong Yang rcPaint = PRectangle::FromInts(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
9478af74909SZhong Yang const PRectangle rcClient = GetClientRectangle();
9488af74909SZhong Yang paintingAllText = BoundsContains(rcPaint, hRgnUpdate, rcClient);
9498af74909SZhong Yang if (!PaintDC(ps.hdc)) {
9508af74909SZhong Yang paintState = paintAbandoned;
9518af74909SZhong Yang }
9528af74909SZhong Yang if (hRgnUpdate) {
9538af74909SZhong Yang ::DeleteRgn(hRgnUpdate);
9548af74909SZhong Yang hRgnUpdate = {};
9558af74909SZhong Yang }
9568af74909SZhong Yang
9578af74909SZhong Yang ::EndPaint(MainHWND(), &ps);
9588af74909SZhong Yang if (paintState == paintAbandoned) {
9598af74909SZhong Yang // Painting area was insufficient to cover new styling or brace highlight positions
9608af74909SZhong Yang FullPaint();
9618af74909SZhong Yang ::ValidateRect(MainHWND(), nullptr);
9628af74909SZhong Yang }
9638af74909SZhong Yang paintState = notPainting;
9648af74909SZhong Yang
9658af74909SZhong Yang // Restore debug output state
9668af74909SZhong Yang Platform::ShowAssertionPopUps(assertsPopup);
9678af74909SZhong Yang
9688af74909SZhong Yang //Platform::DebugPrintf("Paint took %g\n", ep.Duration());
9698af74909SZhong Yang return 0;
9708af74909SZhong Yang }
9718af74909SZhong Yang
HandleCompositionWindowed(uptr_t wParam,sptr_t lParam)9728af74909SZhong Yang sptr_t ScintillaWin::HandleCompositionWindowed(uptr_t wParam, sptr_t lParam) {
9738af74909SZhong Yang if (lParam & GCS_RESULTSTR) {
9748af74909SZhong Yang IMContext imc(MainHWND());
9758af74909SZhong Yang if (imc.hIMC) {
9768af74909SZhong Yang AddWString(imc.GetCompositionString(GCS_RESULTSTR), CharacterSource::imeResult);
9778af74909SZhong Yang
9788af74909SZhong Yang // Set new position after converted
9798af74909SZhong Yang const Point pos = PointMainCaret();
9808af74909SZhong Yang COMPOSITIONFORM CompForm;
9818af74909SZhong Yang CompForm.dwStyle = CFS_POINT;
9828af74909SZhong Yang CompForm.ptCurrentPos = POINTFromPoint(pos);
9838af74909SZhong Yang ::ImmSetCompositionWindow(imc.hIMC, &CompForm);
9848af74909SZhong Yang }
9858af74909SZhong Yang return 0;
9868af74909SZhong Yang }
9878af74909SZhong Yang return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
9888af74909SZhong Yang }
9898af74909SZhong Yang
KoreanIME()9908af74909SZhong Yang bool ScintillaWin::KoreanIME() noexcept {
9918af74909SZhong Yang const int codePage = InputCodePage();
9928af74909SZhong Yang return codePage == 949 || codePage == 1361;
9938af74909SZhong Yang }
9948af74909SZhong Yang
MoveImeCarets(Sci::Position offset)9958af74909SZhong Yang void ScintillaWin::MoveImeCarets(Sci::Position offset) {
9968af74909SZhong Yang // Move carets relatively by bytes.
9978af74909SZhong Yang for (size_t r=0; r<sel.Count(); r++) {
9988af74909SZhong Yang const Sci::Position positionInsert = sel.Range(r).Start().Position();
9998af74909SZhong Yang sel.Range(r).caret.SetPosition(positionInsert + offset);
10008af74909SZhong Yang sel.Range(r).anchor.SetPosition(positionInsert + offset);
10018af74909SZhong Yang }
10028af74909SZhong Yang }
10038af74909SZhong Yang
DrawImeIndicator(int indicator,Sci::Position len)10048af74909SZhong Yang void ScintillaWin::DrawImeIndicator(int indicator, Sci::Position len) {
10058af74909SZhong Yang // Emulate the visual style of IME characters with indicators.
10068af74909SZhong Yang // Draw an indicator on the character before caret by the character bytes of len
10078af74909SZhong Yang // so it should be called after InsertCharacter().
10088af74909SZhong Yang // It does not affect caret positions.
10098af74909SZhong Yang if (indicator < 8 || indicator > INDICATOR_MAX) {
10108af74909SZhong Yang return;
10118af74909SZhong Yang }
10128af74909SZhong Yang pdoc->DecorationSetCurrentIndicator(indicator);
10138af74909SZhong Yang for (size_t r=0; r<sel.Count(); r++) {
10148af74909SZhong Yang const Sci::Position positionInsert = sel.Range(r).Start().Position();
10158af74909SZhong Yang pdoc->DecorationFillRange(positionInsert - len, 1, len);
10168af74909SZhong Yang }
10178af74909SZhong Yang }
10188af74909SZhong Yang
SetCandidateWindowPos()10198af74909SZhong Yang void ScintillaWin::SetCandidateWindowPos() {
10208af74909SZhong Yang IMContext imc(MainHWND());
10218af74909SZhong Yang if (imc.hIMC) {
10228af74909SZhong Yang const Point pos = PointMainCaret();
10238af74909SZhong Yang const PRectangle rcClient = GetTextRectangle();
10248af74909SZhong Yang CANDIDATEFORM CandForm{};
10258af74909SZhong Yang CandForm.dwIndex = 0;
10268af74909SZhong Yang CandForm.dwStyle = CFS_EXCLUDE;
10278af74909SZhong Yang CandForm.ptCurrentPos.x = static_cast<int>(pos.x);
10288af74909SZhong Yang CandForm.ptCurrentPos.y = static_cast<int>(pos.y + std::max(4, vs.lineHeight/4));
10298af74909SZhong Yang // Exclude the area of the whole caret line
10308af74909SZhong Yang CandForm.rcArea.top = static_cast<int>(pos.y);
10318af74909SZhong Yang CandForm.rcArea.bottom = static_cast<int>(pos.y + vs.lineHeight);
10328af74909SZhong Yang CandForm.rcArea.left = static_cast<int>(rcClient.left);
10338af74909SZhong Yang CandForm.rcArea.right = static_cast<int>(rcClient.right);
10348af74909SZhong Yang ::ImmSetCandidateWindow(imc.hIMC, &CandForm);
10358af74909SZhong Yang }
10368af74909SZhong Yang }
10378af74909SZhong Yang
SelectionToHangul()10388af74909SZhong Yang void ScintillaWin::SelectionToHangul() {
10398af74909SZhong Yang // Convert every hanja to hangul within the main range.
10408af74909SZhong Yang const Sci::Position selStart = sel.RangeMain().Start().Position();
10418af74909SZhong Yang const Sci::Position documentStrLen = sel.RangeMain().Length();
10428af74909SZhong Yang const Sci::Position selEnd = selStart + documentStrLen;
10438af74909SZhong Yang const Sci::Position utf16Len = pdoc->CountUTF16(selStart, selEnd);
10448af74909SZhong Yang
10458af74909SZhong Yang if (utf16Len > 0) {
10468af74909SZhong Yang std::string documentStr(documentStrLen, '\0');
10478af74909SZhong Yang pdoc->GetCharRange(&documentStr[0], selStart, documentStrLen);
10488af74909SZhong Yang
10498af74909SZhong Yang std::wstring uniStr = StringDecode(documentStr, CodePageOfDocument());
10508af74909SZhong Yang const int converted = HanjaDict::GetHangulOfHanja(&uniStr[0]);
10518af74909SZhong Yang documentStr = StringEncode(uniStr, CodePageOfDocument());
10528af74909SZhong Yang
10538af74909SZhong Yang if (converted > 0) {
10548af74909SZhong Yang pdoc->BeginUndoAction();
10558af74909SZhong Yang ClearSelection();
10568af74909SZhong Yang InsertPaste(&documentStr[0], documentStr.size());
10578af74909SZhong Yang pdoc->EndUndoAction();
10588af74909SZhong Yang }
10598af74909SZhong Yang }
10608af74909SZhong Yang }
10618af74909SZhong Yang
EscapeHanja()10628af74909SZhong Yang void ScintillaWin::EscapeHanja() {
10638af74909SZhong Yang // The candidate box pops up to user to select a hanja.
10648af74909SZhong Yang // It comes into WM_IME_COMPOSITION with GCS_RESULTSTR.
10658af74909SZhong Yang // The existing hangul or hanja is replaced with it.
10668af74909SZhong Yang if (sel.Count() > 1) {
10678af74909SZhong Yang return; // Do not allow multi carets.
10688af74909SZhong Yang }
10698af74909SZhong Yang const Sci::Position currentPos = CurrentPosition();
10708af74909SZhong Yang const int oneCharLen = pdoc->LenChar(currentPos);
10718af74909SZhong Yang
10728af74909SZhong Yang if (oneCharLen < 2) {
10738af74909SZhong Yang return; // No need to handle SBCS.
10748af74909SZhong Yang }
10758af74909SZhong Yang
10768af74909SZhong Yang // ImmEscapeW() may overwrite uniChar[] with a null terminated string.
10778af74909SZhong Yang // So enlarge it enough to Maximum 4 as in UTF-8.
10788af74909SZhong Yang constexpr size_t safeLength = UTF8MaxBytes + 1;
10798af74909SZhong Yang std::string oneChar(safeLength, '\0');
10808af74909SZhong Yang pdoc->GetCharRange(&oneChar[0], currentPos, oneCharLen);
10818af74909SZhong Yang
10828af74909SZhong Yang std::wstring uniChar = StringDecode(oneChar, CodePageOfDocument());
10838af74909SZhong Yang
10848af74909SZhong Yang IMContext imc(MainHWND());
10858af74909SZhong Yang if (imc.hIMC) {
10868af74909SZhong Yang // Set the candidate box position since IME may show it.
10878af74909SZhong Yang SetCandidateWindowPos();
10888af74909SZhong Yang // IME_ESC_HANJA_MODE appears to receive the first character only.
10898af74909SZhong Yang if (::ImmEscapeW(GetKeyboardLayout(0), imc.hIMC, IME_ESC_HANJA_MODE, &uniChar[0])) {
10908af74909SZhong Yang SetSelection(currentPos, currentPos + oneCharLen);
10918af74909SZhong Yang }
10928af74909SZhong Yang }
10938af74909SZhong Yang }
10948af74909SZhong Yang
ToggleHanja()10958af74909SZhong Yang void ScintillaWin::ToggleHanja() {
10968af74909SZhong Yang // If selection, convert every hanja to hangul within the main range.
10978af74909SZhong Yang // If no selection, commit to IME.
10988af74909SZhong Yang if (sel.Count() > 1) {
10998af74909SZhong Yang return; // Do not allow multi carets.
11008af74909SZhong Yang }
11018af74909SZhong Yang
11028af74909SZhong Yang if (sel.Empty()) {
11038af74909SZhong Yang EscapeHanja();
11048af74909SZhong Yang } else {
11058af74909SZhong Yang SelectionToHangul();
11068af74909SZhong Yang }
11078af74909SZhong Yang }
11088af74909SZhong Yang
11098af74909SZhong Yang namespace {
11108af74909SZhong Yang
MapImeIndicators(std::vector<BYTE> inputStyle)11118af74909SZhong Yang std::vector<int> MapImeIndicators(std::vector<BYTE> inputStyle) {
11128af74909SZhong Yang std::vector<int> imeIndicator(inputStyle.size(), SC_INDICATOR_UNKNOWN);
11138af74909SZhong Yang for (size_t i = 0; i < inputStyle.size(); i++) {
11148af74909SZhong Yang switch (static_cast<int>(inputStyle.at(i))) {
11158af74909SZhong Yang case ATTR_INPUT:
11168af74909SZhong Yang imeIndicator[i] = SC_INDICATOR_INPUT;
11178af74909SZhong Yang break;
11188af74909SZhong Yang case ATTR_TARGET_NOTCONVERTED:
11198af74909SZhong Yang case ATTR_TARGET_CONVERTED:
11208af74909SZhong Yang imeIndicator[i] = SC_INDICATOR_TARGET;
11218af74909SZhong Yang break;
11228af74909SZhong Yang case ATTR_CONVERTED:
11238af74909SZhong Yang imeIndicator[i] = SC_INDICATOR_CONVERTED;
11248af74909SZhong Yang break;
11258af74909SZhong Yang default:
11268af74909SZhong Yang imeIndicator[i] = SC_INDICATOR_UNKNOWN;
11278af74909SZhong Yang break;
11288af74909SZhong Yang }
11298af74909SZhong Yang }
11308af74909SZhong Yang return imeIndicator;
11318af74909SZhong Yang }
11328af74909SZhong Yang
11338af74909SZhong Yang }
11348af74909SZhong Yang
AddWString(std::wstring_view wsv,CharacterSource charSource)11358af74909SZhong Yang void ScintillaWin::AddWString(std::wstring_view wsv, CharacterSource charSource) {
11368af74909SZhong Yang if (wsv.empty())
11378af74909SZhong Yang return;
11388af74909SZhong Yang
11398af74909SZhong Yang const int codePage = CodePageOfDocument();
11408af74909SZhong Yang for (size_t i = 0; i < wsv.size(); ) {
11418af74909SZhong Yang const size_t ucWidth = UTF16CharLength(wsv[i]);
11428af74909SZhong Yang const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage);
11438af74909SZhong Yang
11448af74909SZhong Yang InsertCharacter(docChar, charSource);
11458af74909SZhong Yang i += ucWidth;
11468af74909SZhong Yang }
11478af74909SZhong Yang }
11488af74909SZhong Yang
HandleCompositionInline(uptr_t,sptr_t lParam)11498af74909SZhong Yang sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) {
11508af74909SZhong Yang // Copy & paste by johnsonj with a lot of helps of Neil.
11518af74909SZhong Yang // Great thanks for my foreruners, jiniya and BLUEnLIVE.
11528af74909SZhong Yang
11538af74909SZhong Yang IMContext imc(MainHWND());
11548af74909SZhong Yang if (!imc.hIMC)
11558af74909SZhong Yang return 0;
11568af74909SZhong Yang if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
11578af74909SZhong Yang ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
11588af74909SZhong Yang return 0;
11598af74909SZhong Yang }
11608af74909SZhong Yang
11618af74909SZhong Yang bool initialCompose = false;
11628af74909SZhong Yang if (pdoc->TentativeActive()) {
11638af74909SZhong Yang pdoc->TentativeUndo();
11648af74909SZhong Yang } else {
11658af74909SZhong Yang // No tentative undo means start of this composition so
11668af74909SZhong Yang // fill in any virtual spaces.
11678af74909SZhong Yang initialCompose = true;
11688af74909SZhong Yang }
11698af74909SZhong Yang
11708af74909SZhong Yang view.imeCaretBlockOverride = false;
11718af74909SZhong Yang
11728af74909SZhong Yang if (lParam & GCS_RESULTSTR) {
11738af74909SZhong Yang AddWString(imc.GetCompositionString(GCS_RESULTSTR), CharacterSource::imeResult);
11748af74909SZhong Yang }
11758af74909SZhong Yang
11768af74909SZhong Yang if (lParam & GCS_COMPSTR) {
11778af74909SZhong Yang const std::wstring wcs = imc.GetCompositionString(GCS_COMPSTR);
11788af74909SZhong Yang if (wcs.empty()) {
11798af74909SZhong Yang ShowCaretAtCurrentPosition();
11808af74909SZhong Yang return 0;
11818af74909SZhong Yang }
11828af74909SZhong Yang
11838af74909SZhong Yang if (initialCompose) {
11848af74909SZhong Yang ClearBeforeTentativeStart();
11858af74909SZhong Yang }
11868af74909SZhong Yang
11878af74909SZhong Yang // Set candidate window left aligned to beginning of preedit string.
11888af74909SZhong Yang SetCandidateWindowPos();
11898af74909SZhong Yang pdoc->TentativeStart(); // TentativeActive from now on.
11908af74909SZhong Yang
11918af74909SZhong Yang std::vector<int> imeIndicator = MapImeIndicators(imc.GetImeAttributes());
11928af74909SZhong Yang
11938af74909SZhong Yang const int codePage = CodePageOfDocument();
11948af74909SZhong Yang const std::wstring_view wsv = wcs;
11958af74909SZhong Yang for (size_t i = 0; i < wsv.size(); ) {
11968af74909SZhong Yang const size_t ucWidth = UTF16CharLength(wsv[i]);
11978af74909SZhong Yang const std::string docChar = StringEncode(wsv.substr(i, ucWidth), codePage);
11988af74909SZhong Yang
11998af74909SZhong Yang InsertCharacter(docChar, CharacterSource::tentativeInput);
12008af74909SZhong Yang
12018af74909SZhong Yang DrawImeIndicator(imeIndicator[i], docChar.size());
12028af74909SZhong Yang i += ucWidth;
12038af74909SZhong Yang }
12048af74909SZhong Yang
12058af74909SZhong Yang // Japanese IME after pressing Tab replaces input string with first candidate item (target string);
12068af74909SZhong Yang // when selecting other candidate item, previous item will be replaced with current one.
12078af74909SZhong Yang // After candidate item been added, it's looks like been full selected, it's better to keep caret
12088af74909SZhong Yang // at end of "selection" (end of input) instead of jump to beginning of input ("selection").
12098af74909SZhong Yang const bool onlyTarget = std::all_of(imeIndicator.begin(), imeIndicator.end(), [](int i) noexcept {
12108af74909SZhong Yang return i == SC_INDICATOR_TARGET;
12118af74909SZhong Yang });
12128af74909SZhong Yang if (!onlyTarget) {
12138af74909SZhong Yang // CS_NOMOVECARET: keep caret at beginning of composition string which already moved in InsertCharacter().
12148af74909SZhong Yang // GCS_CURSORPOS: current caret position is provided by IME.
12158af74909SZhong Yang Sci::Position imeEndToImeCaretU16 = -static_cast<Sci::Position>(wcs.size());
12168af74909SZhong Yang if (!(lParam & CS_NOMOVECARET) && (lParam & GCS_CURSORPOS)) {
12178af74909SZhong Yang imeEndToImeCaretU16 += imc.GetImeCaretPos();
12188af74909SZhong Yang }
12198af74909SZhong Yang if (imeEndToImeCaretU16 != 0) {
12208af74909SZhong Yang // Move back IME caret from current last position to imeCaretPos.
12218af74909SZhong Yang const Sci::Position currentPos = CurrentPosition();
12228af74909SZhong Yang const Sci::Position imeCaretPosDoc = pdoc->GetRelativePositionUTF16(currentPos, imeEndToImeCaretU16);
12238af74909SZhong Yang
12248af74909SZhong Yang MoveImeCarets(-currentPos + imeCaretPosDoc);
12258af74909SZhong Yang
12268af74909SZhong Yang if (std::find(imeIndicator.begin(), imeIndicator.end(), SC_INDICATOR_TARGET) != imeIndicator.end()) {
12278af74909SZhong Yang // set candidate window left aligned to beginning of target string.
12288af74909SZhong Yang SetCandidateWindowPos();
12298af74909SZhong Yang }
12308af74909SZhong Yang }
12318af74909SZhong Yang }
12328af74909SZhong Yang
12338af74909SZhong Yang if (KoreanIME()) {
12348af74909SZhong Yang view.imeCaretBlockOverride = true;
12358af74909SZhong Yang }
12368af74909SZhong Yang }
12378af74909SZhong Yang EnsureCaretVisible();
12388af74909SZhong Yang ShowCaretAtCurrentPosition();
12398af74909SZhong Yang return 0;
12408af74909SZhong Yang }
12418af74909SZhong Yang
12428af74909SZhong Yang namespace {
12438af74909SZhong Yang
12448af74909SZhong Yang // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
SciMessageFromEM(unsigned int iMessage)12458af74909SZhong Yang unsigned int SciMessageFromEM(unsigned int iMessage) noexcept {
12468af74909SZhong Yang switch (iMessage) {
12478af74909SZhong Yang case EM_CANPASTE: return SCI_CANPASTE;
12488af74909SZhong Yang case EM_CANUNDO: return SCI_CANUNDO;
12498af74909SZhong Yang case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER;
12508af74909SZhong Yang case EM_FINDTEXTEX: return SCI_FINDTEXT;
12518af74909SZhong Yang case EM_FORMATRANGE: return SCI_FORMATRANGE;
12528af74909SZhong Yang case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE;
12538af74909SZhong Yang case EM_GETLINECOUNT: return SCI_GETLINECOUNT;
12548af74909SZhong Yang case EM_GETSELTEXT: return SCI_GETSELTEXT;
12558af74909SZhong Yang case EM_GETTEXTRANGE: return SCI_GETTEXTRANGE;
12568af74909SZhong Yang case EM_HIDESELECTION: return SCI_HIDESELECTION;
12578af74909SZhong Yang case EM_LINEINDEX: return SCI_POSITIONFROMLINE;
12588af74909SZhong Yang case EM_LINESCROLL: return SCI_LINESCROLL;
12598af74909SZhong Yang case EM_REPLACESEL: return SCI_REPLACESEL;
12608af74909SZhong Yang case EM_SCROLLCARET: return SCI_SCROLLCARET;
12618af74909SZhong Yang case EM_SETREADONLY: return SCI_SETREADONLY;
12628af74909SZhong Yang case WM_CLEAR: return SCI_CLEAR;
12638af74909SZhong Yang case WM_COPY: return SCI_COPY;
12648af74909SZhong Yang case WM_CUT: return SCI_CUT;
12658af74909SZhong Yang case WM_SETTEXT: return SCI_SETTEXT;
12668af74909SZhong Yang case WM_PASTE: return SCI_PASTE;
12678af74909SZhong Yang case WM_UNDO: return SCI_UNDO;
12688af74909SZhong Yang }
12698af74909SZhong Yang return iMessage;
12708af74909SZhong Yang }
12718af74909SZhong Yang
12728af74909SZhong Yang }
12738af74909SZhong Yang
12748af74909SZhong Yang namespace Scintilla {
12758af74909SZhong Yang
CodePageFromCharSet(DWORD characterSet,UINT documentCodePage)12768af74909SZhong Yang UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) noexcept {
12778af74909SZhong Yang if (documentCodePage == SC_CP_UTF8) {
12788af74909SZhong Yang return SC_CP_UTF8;
12798af74909SZhong Yang }
12808af74909SZhong Yang switch (characterSet) {
12818af74909SZhong Yang case SC_CHARSET_ANSI: return 1252;
12828af74909SZhong Yang case SC_CHARSET_DEFAULT: return documentCodePage ? documentCodePage : 1252;
12838af74909SZhong Yang case SC_CHARSET_BALTIC: return 1257;
12848af74909SZhong Yang case SC_CHARSET_CHINESEBIG5: return 950;
12858af74909SZhong Yang case SC_CHARSET_EASTEUROPE: return 1250;
12868af74909SZhong Yang case SC_CHARSET_GB2312: return 936;
12878af74909SZhong Yang case SC_CHARSET_GREEK: return 1253;
12888af74909SZhong Yang case SC_CHARSET_HANGUL: return 949;
12898af74909SZhong Yang case SC_CHARSET_MAC: return 10000;
12908af74909SZhong Yang case SC_CHARSET_OEM: return 437;
12918af74909SZhong Yang case SC_CHARSET_RUSSIAN: return 1251;
12928af74909SZhong Yang case SC_CHARSET_SHIFTJIS: return 932;
12938af74909SZhong Yang case SC_CHARSET_TURKISH: return 1254;
12948af74909SZhong Yang case SC_CHARSET_JOHAB: return 1361;
12958af74909SZhong Yang case SC_CHARSET_HEBREW: return 1255;
12968af74909SZhong Yang case SC_CHARSET_ARABIC: return 1256;
12978af74909SZhong Yang case SC_CHARSET_VIETNAMESE: return 1258;
12988af74909SZhong Yang case SC_CHARSET_THAI: return 874;
12998af74909SZhong Yang case SC_CHARSET_8859_15: return 28605;
13008af74909SZhong Yang // Not supported
13018af74909SZhong Yang case SC_CHARSET_CYRILLIC: return documentCodePage;
13028af74909SZhong Yang case SC_CHARSET_SYMBOL: return documentCodePage;
13038af74909SZhong Yang }
13048af74909SZhong Yang return documentCodePage;
13058af74909SZhong Yang }
13068af74909SZhong Yang
13078af74909SZhong Yang }
13088af74909SZhong Yang
CodePageOfDocument() const13098af74909SZhong Yang UINT ScintillaWin::CodePageOfDocument() const noexcept {
13108af74909SZhong Yang return CodePageFromCharSet(vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage);
13118af74909SZhong Yang }
13128af74909SZhong Yang
EncodeWString(std::wstring_view wsv)13138af74909SZhong Yang std::string ScintillaWin::EncodeWString(std::wstring_view wsv) {
13148af74909SZhong Yang if (IsUnicodeMode()) {
13158af74909SZhong Yang const size_t len = UTF8Length(wsv);
13168af74909SZhong Yang std::string putf(len, 0);
13178af74909SZhong Yang UTF8FromUTF16(wsv, putf.data(), len);
13188af74909SZhong Yang return putf;
13198af74909SZhong Yang } else {
13208af74909SZhong Yang // Not in Unicode mode so convert from Unicode to current Scintilla code page
13218af74909SZhong Yang return StringEncode(wsv, CodePageOfDocument());
13228af74909SZhong Yang }
13238af74909SZhong Yang }
13248af74909SZhong Yang
GetTextLength()13258af74909SZhong Yang sptr_t ScintillaWin::GetTextLength() {
13268af74909SZhong Yang return pdoc->CountUTF16(0, pdoc->Length());
13278af74909SZhong Yang }
13288af74909SZhong Yang
GetText(uptr_t wParam,sptr_t lParam)13298af74909SZhong Yang sptr_t ScintillaWin::GetText(uptr_t wParam, sptr_t lParam) {
13308af74909SZhong Yang if (lParam == 0) {
13318af74909SZhong Yang return pdoc->CountUTF16(0, pdoc->Length());
13328af74909SZhong Yang }
13338af74909SZhong Yang if (wParam == 0) {
13348af74909SZhong Yang return 0;
13358af74909SZhong Yang }
13368af74909SZhong Yang wchar_t *ptr = static_cast<wchar_t *>(PtrFromSPtr(lParam));
13378af74909SZhong Yang if (pdoc->Length() == 0) {
13388af74909SZhong Yang *ptr = L'\0';
13398af74909SZhong Yang return 0;
13408af74909SZhong Yang }
13418af74909SZhong Yang const Sci::Position lengthWanted = wParam - 1;
13428af74909SZhong Yang Sci::Position sizeRequestedRange = pdoc->GetRelativePositionUTF16(0, lengthWanted);
13438af74909SZhong Yang if (sizeRequestedRange < 0) {
13448af74909SZhong Yang // Requested more text than there is in the document.
13458af74909SZhong Yang sizeRequestedRange = pdoc->Length();
13468af74909SZhong Yang }
13478af74909SZhong Yang std::string docBytes(sizeRequestedRange, '\0');
13488af74909SZhong Yang pdoc->GetCharRange(&docBytes[0], 0, sizeRequestedRange);
13498af74909SZhong Yang if (IsUnicodeMode()) {
13508af74909SZhong Yang const size_t uLen = UTF16FromUTF8(docBytes, ptr, lengthWanted);
13518af74909SZhong Yang ptr[uLen] = L'\0';
13528af74909SZhong Yang return uLen;
13538af74909SZhong Yang } else {
13548af74909SZhong Yang // Not Unicode mode
13558af74909SZhong Yang // Convert to Unicode using the current Scintilla code page
13568af74909SZhong Yang const UINT cpSrc = CodePageOfDocument();
13578af74909SZhong Yang int lengthUTF16 = WideCharLenFromMultiByte(cpSrc, docBytes);
13588af74909SZhong Yang if (lengthUTF16 > lengthWanted)
13598af74909SZhong Yang lengthUTF16 = static_cast<int>(lengthWanted);
13608af74909SZhong Yang WideCharFromMultiByte(cpSrc, docBytes, ptr, lengthUTF16);
13618af74909SZhong Yang ptr[lengthUTF16] = L'\0';
13628af74909SZhong Yang return lengthUTF16;
13638af74909SZhong Yang }
13648af74909SZhong Yang }
13658af74909SZhong Yang
ContextCursor(Point pt)13668af74909SZhong Yang Window::Cursor ScintillaWin::ContextCursor(Point pt) {
13678af74909SZhong Yang if (inDragDrop == ddDragging) {
13688af74909SZhong Yang return Window::cursorUp;
13698af74909SZhong Yang } else {
13708af74909SZhong Yang // Display regular (drag) cursor over selection
13718af74909SZhong Yang if (PointInSelMargin(pt)) {
13728af74909SZhong Yang return GetMarginCursor(pt);
13738af74909SZhong Yang } else if (!SelectionEmpty() && PointInSelection(pt)) {
13748af74909SZhong Yang return Window::cursorArrow;
13758af74909SZhong Yang } else if (PointIsHotspot(pt)) {
13768af74909SZhong Yang return Window::cursorHand;
13778af74909SZhong Yang } else if (hoverIndicatorPos != Sci::invalidPosition) {
13788af74909SZhong Yang const Sci::Position pos = PositionFromLocation(pt, true, true);
13798af74909SZhong Yang if (pos != Sci::invalidPosition) {
13808af74909SZhong Yang return Window::cursorHand;
13818af74909SZhong Yang }
13828af74909SZhong Yang }
13838af74909SZhong Yang }
13848af74909SZhong Yang return Window::cursorText;
13858af74909SZhong Yang }
13868af74909SZhong Yang
ShowContextMenu(unsigned int iMessage,uptr_t wParam,sptr_t lParam)13878af74909SZhong Yang sptr_t ScintillaWin::ShowContextMenu(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
13888af74909SZhong Yang Point pt = PointFromLParam(lParam);
13898af74909SZhong Yang POINT rpt = POINTFromPoint(pt);
13908af74909SZhong Yang ::ScreenToClient(MainHWND(), &rpt);
13918af74909SZhong Yang const Point ptClient = PointFromPOINT(rpt);
13928af74909SZhong Yang if (ShouldDisplayPopup(ptClient)) {
13938af74909SZhong Yang if ((pt.x == -1) && (pt.y == -1)) {
13948af74909SZhong Yang // Caused by keyboard so display menu near caret
13958af74909SZhong Yang pt = PointMainCaret();
13968af74909SZhong Yang POINT spt = POINTFromPoint(pt);
13978af74909SZhong Yang ::ClientToScreen(MainHWND(), &spt);
13988af74909SZhong Yang pt = PointFromPOINT(spt);
13998af74909SZhong Yang }
14008af74909SZhong Yang ContextMenu(pt);
14018af74909SZhong Yang return 0;
14028af74909SZhong Yang }
14038af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
14048af74909SZhong Yang }
14058af74909SZhong Yang
SizeWindow()14068af74909SZhong Yang void ScintillaWin::SizeWindow() {
14078af74909SZhong Yang #if defined(USE_D2D)
14088af74909SZhong Yang if (paintState == notPainting) {
14098af74909SZhong Yang DropRenderTarget();
14108af74909SZhong Yang } else {
14118af74909SZhong Yang renderTargetValid = false;
14128af74909SZhong Yang }
14138af74909SZhong Yang #endif
14148af74909SZhong Yang //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam));
14158af74909SZhong Yang ChangeSize();
14168af74909SZhong Yang }
14178af74909SZhong Yang
MouseMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)14188af74909SZhong Yang sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
14198af74909SZhong Yang switch (iMessage) {
14208af74909SZhong Yang case WM_LBUTTONDOWN: {
14218af74909SZhong Yang // For IME, set the composition string as the result string.
14228af74909SZhong Yang IMContext imc(MainHWND());
14238af74909SZhong Yang if (imc.hIMC) {
14248af74909SZhong Yang ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
14258af74909SZhong Yang }
14268af74909SZhong Yang //
14278af74909SZhong Yang //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
14288af74909SZhong Yang // KeyboardIsKeyDown(VK_SHIFT),
14298af74909SZhong Yang // KeyboardIsKeyDown(VK_CONTROL),
14308af74909SZhong Yang // KeyboardIsKeyDown(VK_MENU));
14318af74909SZhong Yang ::SetFocus(MainHWND());
14328af74909SZhong Yang ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(),
14338af74909SZhong Yang MouseModifiers(wParam));
14348af74909SZhong Yang }
14358af74909SZhong Yang break;
14368af74909SZhong Yang
14378af74909SZhong Yang case WM_LBUTTONUP:
14388af74909SZhong Yang ButtonUpWithModifiers(PointFromLParam(lParam),
14398af74909SZhong Yang ::GetMessageTime(), MouseModifiers(wParam));
14408af74909SZhong Yang break;
14418af74909SZhong Yang
14428af74909SZhong Yang case WM_RBUTTONDOWN: {
14438af74909SZhong Yang ::SetFocus(MainHWND());
14448af74909SZhong Yang const Point pt = PointFromLParam(lParam);
14458af74909SZhong Yang if (!PointInSelection(pt)) {
14468af74909SZhong Yang CancelModes();
14478af74909SZhong Yang SetEmptySelection(PositionFromLocation(PointFromLParam(lParam)));
14488af74909SZhong Yang }
14498af74909SZhong Yang
14508af74909SZhong Yang RightButtonDownWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam));
14518af74909SZhong Yang }
14528af74909SZhong Yang break;
14538af74909SZhong Yang
14548af74909SZhong Yang case WM_MOUSEMOVE: {
14558af74909SZhong Yang const Point pt = PointFromLParam(lParam);
14568af74909SZhong Yang
14578af74909SZhong Yang // Windows might send WM_MOUSEMOVE even though the mouse has not been moved:
14588af74909SZhong Yang // http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx
14598af74909SZhong Yang if (ptMouseLast != pt) {
14608af74909SZhong Yang SetTrackMouseLeaveEvent(true);
14618af74909SZhong Yang ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam));
14628af74909SZhong Yang }
14638af74909SZhong Yang }
14648af74909SZhong Yang break;
14658af74909SZhong Yang
14668af74909SZhong Yang case WM_MOUSELEAVE:
14678af74909SZhong Yang SetTrackMouseLeaveEvent(false);
14688af74909SZhong Yang MouseLeave();
14698af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
14708af74909SZhong Yang
14718af74909SZhong Yang case WM_MOUSEWHEEL:
14728af74909SZhong Yang if (!mouseWheelCaptures) {
14738af74909SZhong Yang // if the mouse wheel is not captured, test if the mouse
14748af74909SZhong Yang // pointer is over the editor window and if not, don't
14758af74909SZhong Yang // handle the message but pass it on.
14768af74909SZhong Yang RECT rc;
14778af74909SZhong Yang GetWindowRect(MainHWND(), &rc);
14788af74909SZhong Yang const POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
14798af74909SZhong Yang if (!PtInRect(&rc, pt))
14808af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
14818af74909SZhong Yang }
14828af74909SZhong Yang // if autocomplete list active then send mousewheel message to it
14838af74909SZhong Yang if (ac.Active()) {
14848af74909SZhong Yang HWND hWnd = HwndFromWindow(*(ac.lb));
14858af74909SZhong Yang ::SendMessage(hWnd, iMessage, wParam, lParam);
14868af74909SZhong Yang break;
14878af74909SZhong Yang }
14888af74909SZhong Yang
14898af74909SZhong Yang // Don't handle datazoom.
14908af74909SZhong Yang // (A good idea for datazoom would be to "fold" or "unfold" details.
14918af74909SZhong Yang // i.e. if datazoomed out only class structures are visible, when datazooming in the control
14928af74909SZhong Yang // structures appear, then eventually the individual statements...)
14938af74909SZhong Yang if (wParam & MK_SHIFT) {
14948af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
14958af74909SZhong Yang }
14968af74909SZhong Yang // Either SCROLL or ZOOM. We handle the wheel steppings calculation
14978af74909SZhong Yang wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
14988af74909SZhong Yang if (std::abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) {
14998af74909SZhong Yang Sci::Line linesToScroll = linesPerScroll;
15008af74909SZhong Yang if (linesPerScroll == WHEEL_PAGESCROLL)
15018af74909SZhong Yang linesToScroll = LinesOnScreen() - 1;
15028af74909SZhong Yang if (linesToScroll == 0) {
15038af74909SZhong Yang linesToScroll = 1;
15048af74909SZhong Yang }
15058af74909SZhong Yang linesToScroll *= (wheelDelta / WHEEL_DELTA);
15068af74909SZhong Yang if (wheelDelta >= 0)
15078af74909SZhong Yang wheelDelta = wheelDelta % WHEEL_DELTA;
15088af74909SZhong Yang else
15098af74909SZhong Yang wheelDelta = -(-wheelDelta % WHEEL_DELTA);
15108af74909SZhong Yang
15118af74909SZhong Yang if (wParam & MK_CONTROL) {
15128af74909SZhong Yang // Zoom! We play with the font sizes in the styles.
15138af74909SZhong Yang // Number of steps/line is ignored, we just care if sizing up or down
15148af74909SZhong Yang if (linesToScroll < 0) {
15158af74909SZhong Yang KeyCommand(SCI_ZOOMIN);
15168af74909SZhong Yang } else {
15178af74909SZhong Yang KeyCommand(SCI_ZOOMOUT);
15188af74909SZhong Yang }
15198af74909SZhong Yang } else {
15208af74909SZhong Yang // Scroll
15218af74909SZhong Yang ScrollTo(topLine + linesToScroll);
15228af74909SZhong Yang }
15238af74909SZhong Yang }
15248af74909SZhong Yang return 0;
15258af74909SZhong Yang }
15268af74909SZhong Yang return 0;
15278af74909SZhong Yang }
15288af74909SZhong Yang
KeyMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)15298af74909SZhong Yang sptr_t ScintillaWin::KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
15308af74909SZhong Yang switch (iMessage) {
15318af74909SZhong Yang
15328af74909SZhong Yang case WM_SYSKEYDOWN:
15338af74909SZhong Yang case WM_KEYDOWN: {
15348af74909SZhong Yang // Platform::DebugPrintf("Keydown %c %c%c%c%c %x %x\n",
15358af74909SZhong Yang // iMessage == WM_KEYDOWN ? 'K' : 'S',
15368af74909SZhong Yang // (lParam & (1 << 24)) ? 'E' : '-',
15378af74909SZhong Yang // KeyboardIsKeyDown(VK_SHIFT) ? 'S' : '-',
15388af74909SZhong Yang // KeyboardIsKeyDown(VK_CONTROL) ? 'C' : '-',
15398af74909SZhong Yang // KeyboardIsKeyDown(VK_MENU) ? 'A' : '-',
15408af74909SZhong Yang // wParam, lParam);
15418af74909SZhong Yang lastKeyDownConsumed = false;
15428af74909SZhong Yang const bool altDown = KeyboardIsKeyDown(VK_MENU);
15438af74909SZhong Yang if (altDown && KeyboardIsNumericKeypadFunction(wParam, lParam)) {
15448af74909SZhong Yang // Don't interpret these as they may be characters entered by number.
15458af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
15468af74909SZhong Yang }
15478af74909SZhong Yang const int ret = KeyDownWithModifiers(KeyTranslate(static_cast<int>(wParam)),
15488af74909SZhong Yang ModifierFlags(KeyboardIsKeyDown(VK_SHIFT),
15498af74909SZhong Yang KeyboardIsKeyDown(VK_CONTROL),
15508af74909SZhong Yang altDown),
15518af74909SZhong Yang &lastKeyDownConsumed);
15528af74909SZhong Yang if (!ret && !lastKeyDownConsumed) {
15538af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
15548af74909SZhong Yang }
15558af74909SZhong Yang break;
15568af74909SZhong Yang }
15578af74909SZhong Yang
15588af74909SZhong Yang case WM_KEYUP:
15598af74909SZhong Yang //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
15608af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
15618af74909SZhong Yang
15628af74909SZhong Yang case WM_CHAR:
15638af74909SZhong Yang if (((wParam >= 128) || !iscntrl(static_cast<int>(wParam))) || !lastKeyDownConsumed) {
15648af74909SZhong Yang wchar_t wcs[3] = { static_cast<wchar_t>(wParam), 0 };
15658af74909SZhong Yang unsigned int wclen = 1;
15668af74909SZhong Yang if (IS_HIGH_SURROGATE(wcs[0])) {
15678af74909SZhong Yang // If this is a high surrogate character, we need a second one
15688af74909SZhong Yang lastHighSurrogateChar = wcs[0];
15698af74909SZhong Yang return 0;
15708af74909SZhong Yang } else if (IS_LOW_SURROGATE(wcs[0])) {
15718af74909SZhong Yang wcs[1] = wcs[0];
15728af74909SZhong Yang wcs[0] = lastHighSurrogateChar;
15738af74909SZhong Yang lastHighSurrogateChar = 0;
15748af74909SZhong Yang wclen = 2;
15758af74909SZhong Yang }
15768af74909SZhong Yang AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput);
15778af74909SZhong Yang }
15788af74909SZhong Yang return 0;
15798af74909SZhong Yang
15808af74909SZhong Yang case WM_UNICHAR:
15818af74909SZhong Yang if (wParam == UNICODE_NOCHAR) {
15828af74909SZhong Yang return TRUE;
15838af74909SZhong Yang } else if (lastKeyDownConsumed) {
15848af74909SZhong Yang return 1;
15858af74909SZhong Yang } else {
15868af74909SZhong Yang wchar_t wcs[3] = { 0 };
15878af74909SZhong Yang const size_t wclen = UTF16FromUTF32Character(static_cast<unsigned int>(wParam), wcs);
15888af74909SZhong Yang AddWString(std::wstring_view(wcs, wclen), CharacterSource::directInput);
15898af74909SZhong Yang return FALSE;
15908af74909SZhong Yang }
15918af74909SZhong Yang }
15928af74909SZhong Yang
15938af74909SZhong Yang return 0;
15948af74909SZhong Yang }
15958af74909SZhong Yang
FocusMessage(unsigned int iMessage,uptr_t wParam,sptr_t)15968af74909SZhong Yang sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) {
15978af74909SZhong Yang switch (iMessage) {
15988af74909SZhong Yang case WM_KILLFOCUS: {
15998af74909SZhong Yang HWND wOther = reinterpret_cast<HWND>(wParam);
16008af74909SZhong Yang HWND wThis = MainHWND();
16018af74909SZhong Yang const HWND wCT = HwndFromWindow(ct.wCallTip);
16028af74909SZhong Yang if (!wParam ||
16038af74909SZhong Yang !(::IsChild(wThis, wOther) || (wOther == wCT))) {
16048af74909SZhong Yang SetFocusState(false);
16058af74909SZhong Yang DestroySystemCaret();
16068af74909SZhong Yang }
16078af74909SZhong Yang // Explicitly complete any IME composition
16088af74909SZhong Yang IMContext imc(MainHWND());
16098af74909SZhong Yang if (imc.hIMC) {
16108af74909SZhong Yang ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
16118af74909SZhong Yang }
16128af74909SZhong Yang break;
16138af74909SZhong Yang }
16148af74909SZhong Yang
16158af74909SZhong Yang case WM_SETFOCUS:
16168af74909SZhong Yang SetFocusState(true);
16178af74909SZhong Yang DestroySystemCaret();
16188af74909SZhong Yang CreateSystemCaret();
16198af74909SZhong Yang break;
16208af74909SZhong Yang }
16218af74909SZhong Yang return 0;
16228af74909SZhong Yang }
16238af74909SZhong Yang
IMEMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)16248af74909SZhong Yang sptr_t ScintillaWin::IMEMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
16258af74909SZhong Yang switch (iMessage) {
16268af74909SZhong Yang
16278af74909SZhong Yang case WM_INPUTLANGCHANGE:
16288af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16298af74909SZhong Yang
16308af74909SZhong Yang case WM_INPUTLANGCHANGEREQUEST:
16318af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16328af74909SZhong Yang
16338af74909SZhong Yang case WM_IME_KEYDOWN: {
16348af74909SZhong Yang if (wParam == VK_HANJA) {
16358af74909SZhong Yang ToggleHanja();
16368af74909SZhong Yang }
16378af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16388af74909SZhong Yang }
16398af74909SZhong Yang
16408af74909SZhong Yang case WM_IME_REQUEST: {
16418af74909SZhong Yang if (wParam == IMR_RECONVERTSTRING) {
16428af74909SZhong Yang return ImeOnReconvert(lParam);
16438af74909SZhong Yang }
16448af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16458af74909SZhong Yang }
16468af74909SZhong Yang
16478af74909SZhong Yang case WM_IME_STARTCOMPOSITION:
16488af74909SZhong Yang if (KoreanIME() || imeInteraction == imeInline) {
16498af74909SZhong Yang return 0;
16508af74909SZhong Yang } else {
16518af74909SZhong Yang ImeStartComposition();
16528af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16538af74909SZhong Yang }
16548af74909SZhong Yang
16558af74909SZhong Yang case WM_IME_ENDCOMPOSITION:
16568af74909SZhong Yang ImeEndComposition();
16578af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16588af74909SZhong Yang
16598af74909SZhong Yang case WM_IME_COMPOSITION:
16608af74909SZhong Yang if (KoreanIME() || imeInteraction == imeInline) {
16618af74909SZhong Yang return HandleCompositionInline(wParam, lParam);
16628af74909SZhong Yang } else {
16638af74909SZhong Yang return HandleCompositionWindowed(wParam, lParam);
16648af74909SZhong Yang }
16658af74909SZhong Yang
16668af74909SZhong Yang case WM_IME_SETCONTEXT:
16678af74909SZhong Yang if (KoreanIME() || imeInteraction == imeInline) {
16688af74909SZhong Yang if (wParam) {
16698af74909SZhong Yang LPARAM NoImeWin = lParam;
16708af74909SZhong Yang NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW);
16718af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, NoImeWin);
16728af74909SZhong Yang }
16738af74909SZhong Yang }
16748af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16758af74909SZhong Yang
16768af74909SZhong Yang case WM_IME_NOTIFY:
16778af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
16788af74909SZhong Yang
16798af74909SZhong Yang }
16808af74909SZhong Yang return 0;
16818af74909SZhong Yang }
16828af74909SZhong Yang
EditMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)16838af74909SZhong Yang sptr_t ScintillaWin::EditMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
16848af74909SZhong Yang switch (iMessage) {
16858af74909SZhong Yang
16868af74909SZhong Yang case EM_LINEFROMCHAR:
16878af74909SZhong Yang if (static_cast<Sci::Position>(wParam) < 0) {
16888af74909SZhong Yang wParam = SelectionStart().Position();
16898af74909SZhong Yang }
16908af74909SZhong Yang return pdoc->LineFromPosition(wParam);
16918af74909SZhong Yang
16928af74909SZhong Yang case EM_EXLINEFROMCHAR:
16938af74909SZhong Yang return pdoc->LineFromPosition(lParam);
16948af74909SZhong Yang
16958af74909SZhong Yang case EM_GETSEL:
16968af74909SZhong Yang if (wParam) {
16978af74909SZhong Yang *reinterpret_cast<DWORD *>(wParam) = static_cast<DWORD>(SelectionStart().Position());
16988af74909SZhong Yang }
16998af74909SZhong Yang if (lParam) {
17008af74909SZhong Yang *reinterpret_cast<DWORD *>(lParam) = static_cast<DWORD>(SelectionEnd().Position());
17018af74909SZhong Yang }
17028af74909SZhong Yang return MAKELRESULT(SelectionStart().Position(), SelectionEnd().Position());
17038af74909SZhong Yang
17048af74909SZhong Yang case EM_EXGETSEL: {
17058af74909SZhong Yang if (lParam == 0) {
17068af74909SZhong Yang return 0;
17078af74909SZhong Yang }
17088af74909SZhong Yang CHARRANGE *pCR = reinterpret_cast<CHARRANGE *>(lParam);
17098af74909SZhong Yang pCR->cpMin = static_cast<LONG>(SelectionStart().Position());
17108af74909SZhong Yang pCR->cpMax = static_cast<LONG>(SelectionEnd().Position());
17118af74909SZhong Yang }
17128af74909SZhong Yang break;
17138af74909SZhong Yang
17148af74909SZhong Yang case EM_SETSEL: {
17158af74909SZhong Yang Sci::Position nStart = wParam;
17168af74909SZhong Yang Sci::Position nEnd = lParam;
17178af74909SZhong Yang if (nStart == 0 && nEnd == -1) {
17188af74909SZhong Yang nEnd = pdoc->Length();
17198af74909SZhong Yang }
17208af74909SZhong Yang if (nStart == -1) {
17218af74909SZhong Yang nStart = nEnd; // Remove selection
17228af74909SZhong Yang }
17238af74909SZhong Yang SetSelection(nEnd, nStart);
17248af74909SZhong Yang EnsureCaretVisible();
17258af74909SZhong Yang }
17268af74909SZhong Yang break;
17278af74909SZhong Yang
17288af74909SZhong Yang case EM_EXSETSEL: {
17298af74909SZhong Yang if (lParam == 0) {
17308af74909SZhong Yang return 0;
17318af74909SZhong Yang }
17328af74909SZhong Yang const CHARRANGE *pCR = reinterpret_cast<const CHARRANGE *>(lParam);
17338af74909SZhong Yang sel.selType = Selection::selStream;
17348af74909SZhong Yang if (pCR->cpMin == 0 && pCR->cpMax == -1) {
17358af74909SZhong Yang SetSelection(pCR->cpMin, pdoc->Length());
17368af74909SZhong Yang } else {
17378af74909SZhong Yang SetSelection(pCR->cpMin, pCR->cpMax);
17388af74909SZhong Yang }
17398af74909SZhong Yang EnsureCaretVisible();
17408af74909SZhong Yang return pdoc->LineFromPosition(SelectionStart().Position());
17418af74909SZhong Yang }
17428af74909SZhong Yang }
17438af74909SZhong Yang return 0;
17448af74909SZhong Yang }
17458af74909SZhong Yang
IdleMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)17468af74909SZhong Yang sptr_t ScintillaWin::IdleMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
17478af74909SZhong Yang switch (iMessage) {
17488af74909SZhong Yang case SC_WIN_IDLE:
17498af74909SZhong Yang // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
17508af74909SZhong Yang if (idler.state) {
17518af74909SZhong Yang if (lParam || (WAIT_TIMEOUT == MsgWaitForMultipleObjects(0, nullptr, 0, 0, QS_INPUT | QS_HOTKEY))) {
17528af74909SZhong Yang if (Idle()) {
17538af74909SZhong Yang // User input was given priority above, but all events do get a turn. Other
17548af74909SZhong Yang // messages, notifications, etc. will get interleaved with the idle messages.
17558af74909SZhong Yang
17568af74909SZhong Yang // However, some things like WM_PAINT are a lower priority, and will not fire
17578af74909SZhong Yang // when there's a message posted. So, several times a second, we stop and let
17588af74909SZhong Yang // the low priority events have a turn (after which the timer will fire again).
17598af74909SZhong Yang
17608af74909SZhong Yang // Suppress a warning from Code Analysis that the GetTickCount function
17618af74909SZhong Yang // wraps after 49 days. The WM_TIMER will kick off another SC_WIN_IDLE
17628af74909SZhong Yang // after the wrap.
17638af74909SZhong Yang #ifdef _MSC_VER
17648af74909SZhong Yang #pragma warning(suppress: 28159)
17658af74909SZhong Yang #endif
17668af74909SZhong Yang const DWORD dwCurrent = GetTickCount();
17678af74909SZhong Yang const DWORD dwStart = wParam ? static_cast<DWORD>(wParam) : dwCurrent;
17688af74909SZhong Yang constexpr DWORD maxWorkTime = 50;
17698af74909SZhong Yang
17708af74909SZhong Yang if (dwCurrent >= dwStart && dwCurrent > maxWorkTime &&dwCurrent - maxWorkTime < dwStart)
17718af74909SZhong Yang PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0);
17728af74909SZhong Yang } else {
17738af74909SZhong Yang SetIdle(false);
17748af74909SZhong Yang }
17758af74909SZhong Yang }
17768af74909SZhong Yang }
17778af74909SZhong Yang break;
17788af74909SZhong Yang
17798af74909SZhong Yang case SC_WORK_IDLE:
17808af74909SZhong Yang IdleWork();
17818af74909SZhong Yang break;
17828af74909SZhong Yang }
17838af74909SZhong Yang return 0;
17848af74909SZhong Yang }
17858af74909SZhong Yang
SciMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)17868af74909SZhong Yang sptr_t ScintillaWin::SciMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
17878af74909SZhong Yang switch (iMessage) {
17888af74909SZhong Yang case SCI_GETDIRECTFUNCTION:
17898af74909SZhong Yang return reinterpret_cast<sptr_t>(DirectFunction);
17908af74909SZhong Yang
17918af74909SZhong Yang case SCI_GETDIRECTPOINTER:
17928af74909SZhong Yang return reinterpret_cast<sptr_t>(this);
17938af74909SZhong Yang
17948af74909SZhong Yang case SCI_GRABFOCUS:
17958af74909SZhong Yang ::SetFocus(MainHWND());
17968af74909SZhong Yang break;
17978af74909SZhong Yang
17988af74909SZhong Yang #ifdef INCLUDE_DEPRECATED_FEATURES
17998af74909SZhong Yang case SCI_SETKEYSUNICODE:
18008af74909SZhong Yang break;
18018af74909SZhong Yang
18028af74909SZhong Yang case SCI_GETKEYSUNICODE:
18038af74909SZhong Yang return true;
18048af74909SZhong Yang #endif
18058af74909SZhong Yang
18068af74909SZhong Yang case SCI_SETTECHNOLOGY:
18078af74909SZhong Yang if ((wParam == SC_TECHNOLOGY_DEFAULT) ||
18088af74909SZhong Yang (wParam == SC_TECHNOLOGY_DIRECTWRITERETAIN) ||
18098af74909SZhong Yang (wParam == SC_TECHNOLOGY_DIRECTWRITEDC) ||
18108af74909SZhong Yang (wParam == SC_TECHNOLOGY_DIRECTWRITE)) {
18118af74909SZhong Yang const int technologyNew = static_cast<int>(wParam);
18128af74909SZhong Yang if (technology != technologyNew) {
18138af74909SZhong Yang if (technologyNew > SC_TECHNOLOGY_DEFAULT) {
18148af74909SZhong Yang #if defined(USE_D2D)
18158af74909SZhong Yang if (!LoadD2D())
18168af74909SZhong Yang // Failed to load Direct2D or DirectWrite so no effect
18178af74909SZhong Yang return 0;
18188af74909SZhong Yang #else
18198af74909SZhong Yang return 0;
18208af74909SZhong Yang #endif
18218af74909SZhong Yang } else {
18228af74909SZhong Yang bidirectional = EditModel::Bidirectional::bidiDisabled;
18238af74909SZhong Yang }
18248af74909SZhong Yang #if defined(USE_D2D)
18258af74909SZhong Yang DropRenderTarget();
18268af74909SZhong Yang #endif
18278af74909SZhong Yang technology = technologyNew;
18288af74909SZhong Yang // Invalidate all cached information including layout.
18298af74909SZhong Yang DropGraphics(true);
18308af74909SZhong Yang InvalidateStyleRedraw();
18318af74909SZhong Yang }
18328af74909SZhong Yang }
18338af74909SZhong Yang break;
18348af74909SZhong Yang
18358af74909SZhong Yang case SCI_SETBIDIRECTIONAL:
18368af74909SZhong Yang if (technology == SC_TECHNOLOGY_DEFAULT) {
18378af74909SZhong Yang bidirectional = EditModel::Bidirectional::bidiDisabled;
18388af74909SZhong Yang } else if (wParam <= SC_BIDIRECTIONAL_R2L) {
18398af74909SZhong Yang bidirectional = static_cast<EditModel::Bidirectional>(wParam);
18408af74909SZhong Yang }
18418af74909SZhong Yang // Invalidate all cached information including layout.
18428af74909SZhong Yang DropGraphics(true);
18438af74909SZhong Yang InvalidateStyleRedraw();
18448af74909SZhong Yang break;
18458af74909SZhong Yang
18468af74909SZhong Yang case SCI_TARGETASUTF8:
18478af74909SZhong Yang return TargetAsUTF8(CharPtrFromSPtr(lParam));
18488af74909SZhong Yang
18498af74909SZhong Yang case SCI_ENCODEDFROMUTF8:
18508af74909SZhong Yang return EncodedFromUTF8(ConstCharPtrFromUPtr(wParam),
18518af74909SZhong Yang CharPtrFromSPtr(lParam));
18528af74909SZhong Yang
18538af74909SZhong Yang }
18548af74909SZhong Yang return 0;
18558af74909SZhong Yang }
18568af74909SZhong Yang
WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)18578af74909SZhong Yang sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
18588af74909SZhong Yang try {
18598af74909SZhong Yang //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
18608af74909SZhong Yang iMessage = SciMessageFromEM(iMessage);
18618af74909SZhong Yang switch (iMessage) {
18628af74909SZhong Yang
18638af74909SZhong Yang case WM_CREATE:
18648af74909SZhong Yang ctrlID = ::GetDlgCtrlID(HwndFromWindow(wMain));
18658af74909SZhong Yang // Get Intellimouse scroll line parameters
18668af74909SZhong Yang GetIntelliMouseParameters();
18678af74909SZhong Yang ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget *>(&dt));
18688af74909SZhong Yang break;
18698af74909SZhong Yang
18708af74909SZhong Yang case WM_COMMAND:
18718af74909SZhong Yang Command(LOWORD(wParam));
18728af74909SZhong Yang break;
18738af74909SZhong Yang
18748af74909SZhong Yang case WM_PAINT:
18758af74909SZhong Yang return WndPaint();
18768af74909SZhong Yang
18778af74909SZhong Yang case WM_PRINTCLIENT: {
18788af74909SZhong Yang HDC hdc = reinterpret_cast<HDC>(wParam);
18798af74909SZhong Yang if (!IsCompatibleDC(hdc)) {
18808af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
18818af74909SZhong Yang }
18828af74909SZhong Yang FullPaintDC(hdc);
18838af74909SZhong Yang }
18848af74909SZhong Yang break;
18858af74909SZhong Yang
18868af74909SZhong Yang case WM_VSCROLL:
18878af74909SZhong Yang ScrollMessage(wParam);
18888af74909SZhong Yang break;
18898af74909SZhong Yang
18908af74909SZhong Yang case WM_HSCROLL:
18918af74909SZhong Yang HorizontalScrollMessage(wParam);
18928af74909SZhong Yang break;
18938af74909SZhong Yang
18948af74909SZhong Yang case WM_SIZE:
18958af74909SZhong Yang SizeWindow();
18968af74909SZhong Yang break;
18978af74909SZhong Yang
18988af74909SZhong Yang case WM_TIMER:
18998af74909SZhong Yang if (wParam == idleTimerID && idler.state) {
19008af74909SZhong Yang SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);
19018af74909SZhong Yang } else {
19028af74909SZhong Yang TickFor(static_cast<TickReason>(wParam - fineTimerStart));
19038af74909SZhong Yang }
19048af74909SZhong Yang break;
19058af74909SZhong Yang
19068af74909SZhong Yang case SC_WIN_IDLE:
19078af74909SZhong Yang case SC_WORK_IDLE:
19088af74909SZhong Yang return IdleMessage(iMessage, wParam, lParam);
19098af74909SZhong Yang
19108af74909SZhong Yang case WM_GETMINMAXINFO:
19118af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
19128af74909SZhong Yang
19138af74909SZhong Yang case WM_LBUTTONDOWN:
19148af74909SZhong Yang case WM_LBUTTONUP:
19158af74909SZhong Yang case WM_RBUTTONDOWN:
19168af74909SZhong Yang case WM_MOUSEMOVE:
19178af74909SZhong Yang case WM_MOUSELEAVE:
19188af74909SZhong Yang case WM_MOUSEWHEEL:
19198af74909SZhong Yang return MouseMessage(iMessage, wParam, lParam);
19208af74909SZhong Yang
19218af74909SZhong Yang case WM_SETCURSOR:
19228af74909SZhong Yang if (LOWORD(lParam) == HTCLIENT) {
19238af74909SZhong Yang POINT pt;
19248af74909SZhong Yang if (::GetCursorPos(&pt)) {
19258af74909SZhong Yang ::ScreenToClient(MainHWND(), &pt);
19268af74909SZhong Yang DisplayCursor(ContextCursor(PointFromPOINT(pt)));
19278af74909SZhong Yang }
19288af74909SZhong Yang return TRUE;
19298af74909SZhong Yang } else {
19308af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
19318af74909SZhong Yang }
19328af74909SZhong Yang
19338af74909SZhong Yang case WM_SYSKEYDOWN:
19348af74909SZhong Yang case WM_KEYDOWN:
19358af74909SZhong Yang case WM_KEYUP:
19368af74909SZhong Yang case WM_CHAR:
19378af74909SZhong Yang case WM_UNICHAR:
19388af74909SZhong Yang return KeyMessage(iMessage, wParam, lParam);
19398af74909SZhong Yang
19408af74909SZhong Yang case WM_SETTINGCHANGE:
19418af74909SZhong Yang //Platform::DebugPrintf("Setting Changed\n");
19428af74909SZhong Yang InvalidateStyleData();
19438af74909SZhong Yang // Get Intellimouse scroll line parameters
19448af74909SZhong Yang GetIntelliMouseParameters();
19458af74909SZhong Yang break;
19468af74909SZhong Yang
19478af74909SZhong Yang case WM_GETDLGCODE:
19488af74909SZhong Yang return DLGC_HASSETSEL | DLGC_WANTALLKEYS;
19498af74909SZhong Yang
19508af74909SZhong Yang case WM_KILLFOCUS:
19518af74909SZhong Yang case WM_SETFOCUS:
19528af74909SZhong Yang return FocusMessage(iMessage, wParam, lParam);
19538af74909SZhong Yang
19548af74909SZhong Yang case WM_SYSCOLORCHANGE:
19558af74909SZhong Yang //Platform::DebugPrintf("Setting Changed\n");
19568af74909SZhong Yang InvalidateStyleData();
19578af74909SZhong Yang break;
19588af74909SZhong Yang
19598af74909SZhong Yang case WM_DPICHANGED:
19608af74909SZhong Yang dpi = HIWORD(wParam);
19618af74909SZhong Yang InvalidateStyleRedraw();
19628af74909SZhong Yang break;
19638af74909SZhong Yang
19648af74909SZhong Yang case WM_DPICHANGED_AFTERPARENT: {
19658af74909SZhong Yang const UINT dpiNow = DpiForWindow(wMain.GetID());
19668af74909SZhong Yang if (dpi != dpiNow) {
19678af74909SZhong Yang dpi = dpiNow;
19688af74909SZhong Yang InvalidateStyleRedraw();
19698af74909SZhong Yang }
19708af74909SZhong Yang }
19718af74909SZhong Yang break;
19728af74909SZhong Yang
19738af74909SZhong Yang case WM_CONTEXTMENU:
19748af74909SZhong Yang return ShowContextMenu(iMessage, wParam, lParam);
19758af74909SZhong Yang
19768af74909SZhong Yang case WM_ERASEBKGND:
19778af74909SZhong Yang return 1; // Avoid any background erasure as whole window painted.
19788af74909SZhong Yang
19798af74909SZhong Yang case WM_CAPTURECHANGED:
19808af74909SZhong Yang capturedMouse = false;
19818af74909SZhong Yang return 0;
19828af74909SZhong Yang
19838af74909SZhong Yang // These are not handled in Scintilla and its faster to dispatch them here.
19848af74909SZhong Yang // Also moves time out to here so profile doesn't count lots of empty message calls.
19858af74909SZhong Yang
19868af74909SZhong Yang case WM_MOVE:
19878af74909SZhong Yang case WM_MOUSEACTIVATE:
19888af74909SZhong Yang case WM_NCHITTEST:
19898af74909SZhong Yang case WM_NCCALCSIZE:
19908af74909SZhong Yang case WM_NCPAINT:
19918af74909SZhong Yang case WM_NCMOUSEMOVE:
19928af74909SZhong Yang case WM_NCLBUTTONDOWN:
19938af74909SZhong Yang case WM_SYSCOMMAND:
19948af74909SZhong Yang case WM_WINDOWPOSCHANGING:
19958af74909SZhong Yang case WM_WINDOWPOSCHANGED:
19968af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
19978af74909SZhong Yang
19988af74909SZhong Yang case WM_GETTEXTLENGTH:
19998af74909SZhong Yang return GetTextLength();
20008af74909SZhong Yang
20018af74909SZhong Yang case WM_GETTEXT:
20028af74909SZhong Yang return GetText(wParam, lParam);
20038af74909SZhong Yang
20048af74909SZhong Yang case WM_INPUTLANGCHANGE:
20058af74909SZhong Yang case WM_INPUTLANGCHANGEREQUEST:
20068af74909SZhong Yang case WM_IME_KEYDOWN:
20078af74909SZhong Yang case WM_IME_REQUEST:
20088af74909SZhong Yang case WM_IME_STARTCOMPOSITION:
20098af74909SZhong Yang case WM_IME_ENDCOMPOSITION:
20108af74909SZhong Yang case WM_IME_COMPOSITION:
20118af74909SZhong Yang case WM_IME_SETCONTEXT:
20128af74909SZhong Yang case WM_IME_NOTIFY:
20138af74909SZhong Yang return IMEMessage(iMessage, wParam, lParam);
20148af74909SZhong Yang
20158af74909SZhong Yang case EM_LINEFROMCHAR:
20168af74909SZhong Yang case EM_EXLINEFROMCHAR:
20178af74909SZhong Yang case EM_GETSEL:
20188af74909SZhong Yang case EM_EXGETSEL:
20198af74909SZhong Yang case EM_SETSEL:
20208af74909SZhong Yang case EM_EXSETSEL:
20218af74909SZhong Yang return EditMessage(iMessage, wParam, lParam);
20228af74909SZhong Yang
20238af74909SZhong Yang case SCI_GETDIRECTFUNCTION:
20248af74909SZhong Yang case SCI_GETDIRECTPOINTER:
20258af74909SZhong Yang case SCI_GRABFOCUS:
20268af74909SZhong Yang #ifdef INCLUDE_DEPRECATED_FEATURES
20278af74909SZhong Yang case SCI_SETKEYSUNICODE:
20288af74909SZhong Yang case SCI_GETKEYSUNICODE:
20298af74909SZhong Yang #endif
20308af74909SZhong Yang case SCI_SETTECHNOLOGY:
20318af74909SZhong Yang case SCI_SETBIDIRECTIONAL:
20328af74909SZhong Yang case SCI_TARGETASUTF8:
20338af74909SZhong Yang case SCI_ENCODEDFROMUTF8:
20348af74909SZhong Yang return SciMessage(iMessage, wParam, lParam);
20358af74909SZhong Yang
20368af74909SZhong Yang default:
20378af74909SZhong Yang return ScintillaBase::WndProc(iMessage, wParam, lParam);
20388af74909SZhong Yang }
20398af74909SZhong Yang } catch (std::bad_alloc &) {
20408af74909SZhong Yang errorStatus = SC_STATUS_BADALLOC;
20418af74909SZhong Yang } catch (...) {
20428af74909SZhong Yang errorStatus = SC_STATUS_FAILURE;
20438af74909SZhong Yang }
20448af74909SZhong Yang return 0;
20458af74909SZhong Yang }
20468af74909SZhong Yang
ValidCodePage(int codePage) const20478af74909SZhong Yang bool ScintillaWin::ValidCodePage(int codePage) const {
20488af74909SZhong Yang return codePage == 0 || codePage == SC_CP_UTF8 ||
20498af74909SZhong Yang codePage == 932 || codePage == 936 || codePage == 949 ||
20508af74909SZhong Yang codePage == 950 || codePage == 1361;
20518af74909SZhong Yang }
20528af74909SZhong Yang
DefWndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)20538af74909SZhong Yang sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
20548af74909SZhong Yang return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
20558af74909SZhong Yang }
20568af74909SZhong Yang
FineTickerRunning(TickReason reason)20578af74909SZhong Yang bool ScintillaWin::FineTickerRunning(TickReason reason) {
20588af74909SZhong Yang return timers[reason] != 0;
20598af74909SZhong Yang }
20608af74909SZhong Yang
FineTickerStart(TickReason reason,int millis,int tolerance)20618af74909SZhong Yang void ScintillaWin::FineTickerStart(TickReason reason, int millis, int tolerance) {
20628af74909SZhong Yang FineTickerCancel(reason);
20638af74909SZhong Yang const UINT_PTR eventID = static_cast<UINT_PTR>(fineTimerStart) + reason;
20648af74909SZhong Yang if (SetCoalescableTimerFn && tolerance) {
20658af74909SZhong Yang timers[reason] = SetCoalescableTimerFn(MainHWND(), eventID, millis, nullptr, tolerance);
20668af74909SZhong Yang } else {
20678af74909SZhong Yang timers[reason] = ::SetTimer(MainHWND(), eventID, millis, nullptr);
20688af74909SZhong Yang }
20698af74909SZhong Yang }
20708af74909SZhong Yang
FineTickerCancel(TickReason reason)20718af74909SZhong Yang void ScintillaWin::FineTickerCancel(TickReason reason) {
20728af74909SZhong Yang if (timers[reason]) {
20738af74909SZhong Yang ::KillTimer(MainHWND(), timers[reason]);
20748af74909SZhong Yang timers[reason] = 0;
20758af74909SZhong Yang }
20768af74909SZhong Yang }
20778af74909SZhong Yang
20788af74909SZhong Yang
SetIdle(bool on)20798af74909SZhong Yang bool ScintillaWin::SetIdle(bool on) {
20808af74909SZhong Yang // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
20818af74909SZhong Yang // takes advantage of the fact that WM_TIMER messages are very low priority,
20828af74909SZhong Yang // and are only posted when the message queue is empty, i.e. during idle time.
20838af74909SZhong Yang if (idler.state != on) {
20848af74909SZhong Yang if (on) {
20858af74909SZhong Yang idler.idlerID = ::SetTimer(MainHWND(), idleTimerID, 10, nullptr)
20868af74909SZhong Yang ? reinterpret_cast<IdlerID>(idleTimerID) : 0;
20878af74909SZhong Yang } else {
20888af74909SZhong Yang ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(idler.idlerID));
20898af74909SZhong Yang idler.idlerID = 0;
20908af74909SZhong Yang }
20918af74909SZhong Yang idler.state = idler.idlerID != 0;
20928af74909SZhong Yang }
20938af74909SZhong Yang return idler.state;
20948af74909SZhong Yang }
20958af74909SZhong Yang
IdleWork()20968af74909SZhong Yang void ScintillaWin::IdleWork() {
20978af74909SZhong Yang styleIdleInQueue = false;
20988af74909SZhong Yang Editor::IdleWork();
20998af74909SZhong Yang }
21008af74909SZhong Yang
QueueIdleWork(WorkNeeded::workItems items,Sci::Position upTo)21018af74909SZhong Yang void ScintillaWin::QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) {
21028af74909SZhong Yang Editor::QueueIdleWork(items, upTo);
21038af74909SZhong Yang if (!styleIdleInQueue) {
21048af74909SZhong Yang if (PostMessage(MainHWND(), SC_WORK_IDLE, 0, 0)) {
21058af74909SZhong Yang styleIdleInQueue = true;
21068af74909SZhong Yang }
21078af74909SZhong Yang }
21088af74909SZhong Yang }
21098af74909SZhong Yang
SetMouseCapture(bool on)21108af74909SZhong Yang void ScintillaWin::SetMouseCapture(bool on) {
21118af74909SZhong Yang if (mouseDownCaptures) {
21128af74909SZhong Yang if (on) {
21138af74909SZhong Yang ::SetCapture(MainHWND());
21148af74909SZhong Yang } else {
21158af74909SZhong Yang ::ReleaseCapture();
21168af74909SZhong Yang }
21178af74909SZhong Yang }
21188af74909SZhong Yang capturedMouse = on;
21198af74909SZhong Yang }
21208af74909SZhong Yang
HaveMouseCapture()21218af74909SZhong Yang bool ScintillaWin::HaveMouseCapture() {
21228af74909SZhong Yang // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
21238af74909SZhong Yang return capturedMouse;
21248af74909SZhong Yang //return capturedMouse && (::GetCapture() == MainHWND());
21258af74909SZhong Yang }
21268af74909SZhong Yang
SetTrackMouseLeaveEvent(bool on)21278af74909SZhong Yang void ScintillaWin::SetTrackMouseLeaveEvent(bool on) noexcept {
21288af74909SZhong Yang if (on && !trackedMouseLeave) {
21298af74909SZhong Yang TRACKMOUSEEVENT tme;
21308af74909SZhong Yang tme.cbSize = sizeof(tme);
21318af74909SZhong Yang tme.dwFlags = TME_LEAVE;
21328af74909SZhong Yang tme.hwndTrack = MainHWND();
21338af74909SZhong Yang tme.dwHoverTime = HOVER_DEFAULT; // Unused but triggers Dr. Memory if not initialized
21348af74909SZhong Yang TrackMouseEvent(&tme);
21358af74909SZhong Yang }
21368af74909SZhong Yang trackedMouseLeave = on;
21378af74909SZhong Yang }
21388af74909SZhong Yang
PaintContains(PRectangle rc)21398af74909SZhong Yang bool ScintillaWin::PaintContains(PRectangle rc) {
21408af74909SZhong Yang if (paintState == painting) {
21418af74909SZhong Yang return BoundsContains(rcPaint, hRgnUpdate, rc);
21428af74909SZhong Yang }
21438af74909SZhong Yang return true;
21448af74909SZhong Yang }
21458af74909SZhong Yang
ScrollText(Sci::Line)21468af74909SZhong Yang void ScintillaWin::ScrollText(Sci::Line /* linesToMove */) {
21478af74909SZhong Yang //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
21488af74909SZhong Yang //::ScrollWindow(MainHWND(), 0,
21498af74909SZhong Yang // vs.lineHeight * linesToMove, 0, 0);
21508af74909SZhong Yang //::UpdateWindow(MainHWND());
21518af74909SZhong Yang Redraw();
21528af74909SZhong Yang UpdateSystemCaret();
21538af74909SZhong Yang }
21548af74909SZhong Yang
NotifyCaretMove()21558af74909SZhong Yang void ScintillaWin::NotifyCaretMove() {
21568af74909SZhong Yang NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, MainHWND(), OBJID_CARET, CHILDID_SELF);
21578af74909SZhong Yang }
21588af74909SZhong Yang
UpdateSystemCaret()21598af74909SZhong Yang void ScintillaWin::UpdateSystemCaret() {
21608af74909SZhong Yang if (hasFocus) {
21618af74909SZhong Yang if (pdoc->TentativeActive()) {
21628af74909SZhong Yang // ongoing inline mode IME composition, don't inform IME of system caret position.
21638af74909SZhong Yang // fix candidate window for Google Japanese IME moved on typing on Win7.
21648af74909SZhong Yang return;
21658af74909SZhong Yang }
21668af74909SZhong Yang if (HasCaretSizeChanged()) {
21678af74909SZhong Yang DestroySystemCaret();
21688af74909SZhong Yang CreateSystemCaret();
21698af74909SZhong Yang }
21708af74909SZhong Yang const Point pos = PointMainCaret();
21718af74909SZhong Yang ::SetCaretPos(static_cast<int>(pos.x), static_cast<int>(pos.y));
21728af74909SZhong Yang }
21738af74909SZhong Yang }
21748af74909SZhong Yang
SetScrollInfo(int nBar,LPCSCROLLINFO lpsi,BOOL bRedraw)21758af74909SZhong Yang int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) noexcept {
21768af74909SZhong Yang return ::SetScrollInfo(MainHWND(), nBar, lpsi, bRedraw);
21778af74909SZhong Yang }
21788af74909SZhong Yang
GetScrollInfo(int nBar,LPSCROLLINFO lpsi)21798af74909SZhong Yang bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) noexcept {
21808af74909SZhong Yang return ::GetScrollInfo(MainHWND(), nBar, lpsi) ? true : false;
21818af74909SZhong Yang }
21828af74909SZhong Yang
21838af74909SZhong Yang // Change the scroll position but avoid repaint if changing to same value
ChangeScrollPos(int barType,Sci::Position pos)21848af74909SZhong Yang void ScintillaWin::ChangeScrollPos(int barType, Sci::Position pos) {
21858af74909SZhong Yang SCROLLINFO sci = {
21868af74909SZhong Yang sizeof(sci), 0, 0, 0, 0, 0, 0
21878af74909SZhong Yang };
21888af74909SZhong Yang sci.fMask = SIF_POS;
21898af74909SZhong Yang GetScrollInfo(barType, &sci);
21908af74909SZhong Yang if (sci.nPos != pos) {
21918af74909SZhong Yang DwellEnd(true);
21928af74909SZhong Yang sci.nPos = static_cast<int>(pos);
21938af74909SZhong Yang SetScrollInfo(barType, &sci, TRUE);
21948af74909SZhong Yang }
21958af74909SZhong Yang }
21968af74909SZhong Yang
SetVerticalScrollPos()21978af74909SZhong Yang void ScintillaWin::SetVerticalScrollPos() {
21988af74909SZhong Yang ChangeScrollPos(SB_VERT, topLine);
21998af74909SZhong Yang }
22008af74909SZhong Yang
SetHorizontalScrollPos()22018af74909SZhong Yang void ScintillaWin::SetHorizontalScrollPos() {
22028af74909SZhong Yang ChangeScrollPos(SB_HORZ, xOffset);
22038af74909SZhong Yang }
22048af74909SZhong Yang
ModifyScrollBars(Sci::Line nMax,Sci::Line nPage)22058af74909SZhong Yang bool ScintillaWin::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) {
22068af74909SZhong Yang bool modified = false;
22078af74909SZhong Yang SCROLLINFO sci = {
22088af74909SZhong Yang sizeof(sci), 0, 0, 0, 0, 0, 0
22098af74909SZhong Yang };
22108af74909SZhong Yang sci.fMask = SIF_PAGE | SIF_RANGE;
22118af74909SZhong Yang GetScrollInfo(SB_VERT, &sci);
22128af74909SZhong Yang const Sci::Line vertEndPreferred = nMax;
22138af74909SZhong Yang if (!verticalScrollBarVisible)
22148af74909SZhong Yang nPage = vertEndPreferred + 1;
22158af74909SZhong Yang if ((sci.nMin != 0) ||
22168af74909SZhong Yang (sci.nMax != vertEndPreferred) ||
22178af74909SZhong Yang (sci.nPage != static_cast<unsigned int>(nPage)) ||
22188af74909SZhong Yang (sci.nPos != 0)) {
22198af74909SZhong Yang sci.fMask = SIF_PAGE | SIF_RANGE;
22208af74909SZhong Yang sci.nMin = 0;
22218af74909SZhong Yang sci.nMax = static_cast<int>(vertEndPreferred);
22228af74909SZhong Yang sci.nPage = static_cast<UINT>(nPage);
22238af74909SZhong Yang sci.nPos = 0;
22248af74909SZhong Yang sci.nTrackPos = 1;
22258af74909SZhong Yang SetScrollInfo(SB_VERT, &sci, TRUE);
22268af74909SZhong Yang modified = true;
22278af74909SZhong Yang }
22288af74909SZhong Yang
22298af74909SZhong Yang const PRectangle rcText = GetTextRectangle();
22308af74909SZhong Yang int horizEndPreferred = scrollWidth;
22318af74909SZhong Yang if (horizEndPreferred < 0)
22328af74909SZhong Yang horizEndPreferred = 0;
22338af74909SZhong Yang int pageWidth = static_cast<int>(rcText.Width());
22348af74909SZhong Yang if (!horizontalScrollBarVisible || Wrapping())
22358af74909SZhong Yang pageWidth = horizEndPreferred + 1;
22368af74909SZhong Yang sci.fMask = SIF_PAGE | SIF_RANGE;
22378af74909SZhong Yang GetScrollInfo(SB_HORZ, &sci);
22388af74909SZhong Yang if ((sci.nMin != 0) ||
22398af74909SZhong Yang (sci.nMax != horizEndPreferred) ||
22408af74909SZhong Yang (sci.nPage != static_cast<unsigned int>(pageWidth)) ||
22418af74909SZhong Yang (sci.nPos != 0)) {
22428af74909SZhong Yang sci.fMask = SIF_PAGE | SIF_RANGE;
22438af74909SZhong Yang sci.nMin = 0;
22448af74909SZhong Yang sci.nMax = horizEndPreferred;
22458af74909SZhong Yang sci.nPage = pageWidth;
22468af74909SZhong Yang sci.nPos = 0;
22478af74909SZhong Yang sci.nTrackPos = 1;
22488af74909SZhong Yang SetScrollInfo(SB_HORZ, &sci, TRUE);
22498af74909SZhong Yang modified = true;
22508af74909SZhong Yang if (scrollWidth < pageWidth) {
22518af74909SZhong Yang HorizontalScrollTo(0);
22528af74909SZhong Yang }
22538af74909SZhong Yang }
22548af74909SZhong Yang return modified;
22558af74909SZhong Yang }
22568af74909SZhong Yang
NotifyChange()22578af74909SZhong Yang void ScintillaWin::NotifyChange() {
22588af74909SZhong Yang ::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
22598af74909SZhong Yang MAKEWPARAM(GetCtrlID(), SCEN_CHANGE),
22608af74909SZhong Yang reinterpret_cast<LPARAM>(MainHWND()));
22618af74909SZhong Yang }
22628af74909SZhong Yang
NotifyFocus(bool focus)22638af74909SZhong Yang void ScintillaWin::NotifyFocus(bool focus) {
22648af74909SZhong Yang if (commandEvents) {
22658af74909SZhong Yang ::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
22668af74909SZhong Yang MAKEWPARAM(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS),
22678af74909SZhong Yang reinterpret_cast<LPARAM>(MainHWND()));
22688af74909SZhong Yang }
22698af74909SZhong Yang Editor::NotifyFocus(focus);
22708af74909SZhong Yang }
22718af74909SZhong Yang
SetCtrlID(int identifier)22728af74909SZhong Yang void ScintillaWin::SetCtrlID(int identifier) {
22738af74909SZhong Yang ::SetWindowID(HwndFromWindow(wMain), identifier);
22748af74909SZhong Yang }
22758af74909SZhong Yang
GetCtrlID()22768af74909SZhong Yang int ScintillaWin::GetCtrlID() {
22778af74909SZhong Yang return ::GetDlgCtrlID(HwndFromWindow(wMain));
22788af74909SZhong Yang }
22798af74909SZhong Yang
NotifyParent(SCNotification scn)22808af74909SZhong Yang void ScintillaWin::NotifyParent(SCNotification scn) {
22818af74909SZhong Yang scn.nmhdr.hwndFrom = MainHWND();
22828af74909SZhong Yang scn.nmhdr.idFrom = GetCtrlID();
22838af74909SZhong Yang ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY,
22848af74909SZhong Yang GetCtrlID(), reinterpret_cast<LPARAM>(&scn));
22858af74909SZhong Yang }
22868af74909SZhong Yang
NotifyDoubleClick(Point pt,int modifiers)22878af74909SZhong Yang void ScintillaWin::NotifyDoubleClick(Point pt, int modifiers) {
22888af74909SZhong Yang //Platform::DebugPrintf("ScintillaWin Double click 0\n");
22898af74909SZhong Yang ScintillaBase::NotifyDoubleClick(pt, modifiers);
22908af74909SZhong Yang // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
22918af74909SZhong Yang ::SendMessage(MainHWND(),
22928af74909SZhong Yang WM_LBUTTONDBLCLK,
22938af74909SZhong Yang (modifiers & SCI_SHIFT) ? MK_SHIFT : 0,
22948af74909SZhong Yang MAKELPARAM(pt.x, pt.y));
22958af74909SZhong Yang }
22968af74909SZhong Yang
22978af74909SZhong Yang class CaseFolderDBCS : public CaseFolderTable {
22988af74909SZhong Yang // Allocate the expandable storage here so that it does not need to be reallocated
22998af74909SZhong Yang // for each call to Fold.
23008af74909SZhong Yang std::vector<wchar_t> utf16Mixed;
23018af74909SZhong Yang std::vector<wchar_t> utf16Folded;
23028af74909SZhong Yang UINT cp;
23038af74909SZhong Yang public:
CaseFolderDBCS(UINT cp_)23048af74909SZhong Yang explicit CaseFolderDBCS(UINT cp_) : cp(cp_) {
23058af74909SZhong Yang StandardASCII();
23068af74909SZhong Yang }
Fold(char * folded,size_t sizeFolded,const char * mixed,size_t lenMixed)23078af74909SZhong Yang size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override {
23088af74909SZhong Yang if ((lenMixed == 1) && (sizeFolded > 0)) {
23098af74909SZhong Yang folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
23108af74909SZhong Yang return 1;
23118af74909SZhong Yang } else {
23128af74909SZhong Yang if (lenMixed > utf16Mixed.size()) {
23138af74909SZhong Yang utf16Mixed.resize(lenMixed + 8);
23148af74909SZhong Yang }
23158af74909SZhong Yang const size_t nUtf16Mixed = WideCharFromMultiByte(cp,
23168af74909SZhong Yang std::string_view(mixed, lenMixed),
23178af74909SZhong Yang &utf16Mixed[0],
23188af74909SZhong Yang utf16Mixed.size());
23198af74909SZhong Yang
23208af74909SZhong Yang if (nUtf16Mixed == 0) {
23218af74909SZhong Yang // Failed to convert -> bad input
23228af74909SZhong Yang folded[0] = '\0';
23238af74909SZhong Yang return 1;
23248af74909SZhong Yang }
23258af74909SZhong Yang
23268af74909SZhong Yang size_t lenFlat = 0;
23278af74909SZhong Yang for (size_t mixIndex=0; mixIndex < nUtf16Mixed; mixIndex++) {
23288af74909SZhong Yang if ((lenFlat + 20) > utf16Folded.size())
23298af74909SZhong Yang utf16Folded.resize(lenFlat + 60);
23308af74909SZhong Yang const char *foldedUTF8 = CaseConvert(utf16Mixed[mixIndex], CaseConversionFold);
23318af74909SZhong Yang if (foldedUTF8) {
23328af74909SZhong Yang // Maximum length of a case conversion is 6 bytes, 3 characters
23338af74909SZhong Yang wchar_t wFolded[20];
23348af74909SZhong Yang const size_t charsConverted = UTF16FromUTF8(std::string_view(foldedUTF8),
23358af74909SZhong Yang wFolded, std::size(wFolded));
23368af74909SZhong Yang for (size_t j=0; j<charsConverted; j++)
23378af74909SZhong Yang utf16Folded[lenFlat++] = wFolded[j];
23388af74909SZhong Yang } else {
23398af74909SZhong Yang utf16Folded[lenFlat++] = utf16Mixed[mixIndex];
23408af74909SZhong Yang }
23418af74909SZhong Yang }
23428af74909SZhong Yang
23438af74909SZhong Yang const std::wstring_view wsvFolded(&utf16Folded[0], lenFlat);
23448af74909SZhong Yang const size_t lenOut = MultiByteLenFromWideChar(cp, wsvFolded);
23458af74909SZhong Yang
23468af74909SZhong Yang if (lenOut < sizeFolded) {
23478af74909SZhong Yang MultiByteFromWideChar(cp, wsvFolded, folded, lenOut);
23488af74909SZhong Yang return lenOut;
23498af74909SZhong Yang } else {
23508af74909SZhong Yang return 0;
23518af74909SZhong Yang }
23528af74909SZhong Yang }
23538af74909SZhong Yang }
23548af74909SZhong Yang };
23558af74909SZhong Yang
CaseFolderForEncoding()23568af74909SZhong Yang CaseFolder *ScintillaWin::CaseFolderForEncoding() {
23578af74909SZhong Yang const UINT cpDest = CodePageOfDocument();
23588af74909SZhong Yang if (cpDest == SC_CP_UTF8) {
23598af74909SZhong Yang return new CaseFolderUnicode();
23608af74909SZhong Yang } else {
23618af74909SZhong Yang if (pdoc->dbcsCodePage == 0) {
23628af74909SZhong Yang CaseFolderTable *pcf = new CaseFolderTable();
23638af74909SZhong Yang pcf->StandardASCII();
23648af74909SZhong Yang // Only for single byte encodings
23658af74909SZhong Yang for (int i=0x80; i<0x100; i++) {
23668af74909SZhong Yang char sCharacter[2] = "A";
23678af74909SZhong Yang sCharacter[0] = static_cast<char>(i);
23688af74909SZhong Yang wchar_t wCharacter[20];
23698af74909SZhong Yang const unsigned int lengthUTF16 = WideCharFromMultiByte(cpDest, sCharacter,
23708af74909SZhong Yang wCharacter, std::size(wCharacter));
23718af74909SZhong Yang if (lengthUTF16 == 1) {
23728af74909SZhong Yang const char *caseFolded = CaseConvert(wCharacter[0], CaseConversionFold);
23738af74909SZhong Yang if (caseFolded) {
23748af74909SZhong Yang wchar_t wLower[20];
23758af74909SZhong Yang const size_t charsConverted = UTF16FromUTF8(std::string_view(caseFolded),
23768af74909SZhong Yang wLower, std::size(wLower));
23778af74909SZhong Yang if (charsConverted == 1) {
23788af74909SZhong Yang char sCharacterLowered[20];
23798af74909SZhong Yang const unsigned int lengthConverted = MultiByteFromWideChar(cpDest,
23808af74909SZhong Yang std::wstring_view(wLower, charsConverted),
23818af74909SZhong Yang sCharacterLowered, std::size(sCharacterLowered));
23828af74909SZhong Yang if ((lengthConverted == 1) && (sCharacter[0] != sCharacterLowered[0])) {
23838af74909SZhong Yang pcf->SetTranslation(sCharacter[0], sCharacterLowered[0]);
23848af74909SZhong Yang }
23858af74909SZhong Yang }
23868af74909SZhong Yang }
23878af74909SZhong Yang }
23888af74909SZhong Yang }
23898af74909SZhong Yang return pcf;
23908af74909SZhong Yang } else {
23918af74909SZhong Yang return new CaseFolderDBCS(cpDest);
23928af74909SZhong Yang }
23938af74909SZhong Yang }
23948af74909SZhong Yang }
23958af74909SZhong Yang
CaseMapString(const std::string & s,int caseMapping)23968af74909SZhong Yang std::string ScintillaWin::CaseMapString(const std::string &s, int caseMapping) {
23978af74909SZhong Yang if ((s.size() == 0) || (caseMapping == cmSame))
23988af74909SZhong Yang return s;
23998af74909SZhong Yang
24008af74909SZhong Yang const UINT cpDoc = CodePageOfDocument();
24018af74909SZhong Yang if (cpDoc == SC_CP_UTF8) {
24028af74909SZhong Yang return CaseConvertString(s, (caseMapping == cmUpper) ? CaseConversionUpper : CaseConversionLower);
24038af74909SZhong Yang }
24048af74909SZhong Yang
24058af74909SZhong Yang // Change text to UTF-16
24068af74909SZhong Yang const std::wstring wsText = StringDecode(s, cpDoc);
24078af74909SZhong Yang
24088af74909SZhong Yang const DWORD mapFlags = LCMAP_LINGUISTIC_CASING |
24098af74909SZhong Yang ((caseMapping == cmUpper) ? LCMAP_UPPERCASE : LCMAP_LOWERCASE);
24108af74909SZhong Yang
24118af74909SZhong Yang // Change case
24128af74909SZhong Yang const std::wstring wsConverted = StringMapCase(wsText, mapFlags);
24138af74909SZhong Yang
24148af74909SZhong Yang // Change back to document encoding
24158af74909SZhong Yang std::string sConverted = StringEncode(wsConverted, cpDoc);
24168af74909SZhong Yang
24178af74909SZhong Yang return sConverted;
24188af74909SZhong Yang }
24198af74909SZhong Yang
Copy()24208af74909SZhong Yang void ScintillaWin::Copy() {
24218af74909SZhong Yang //Platform::DebugPrintf("Copy\n");
24228af74909SZhong Yang if (!sel.Empty()) {
24238af74909SZhong Yang SelectionText selectedText;
24248af74909SZhong Yang CopySelectionRange(&selectedText);
24258af74909SZhong Yang CopyToClipboard(selectedText);
24268af74909SZhong Yang }
24278af74909SZhong Yang }
24288af74909SZhong Yang
CanPaste()24298af74909SZhong Yang bool ScintillaWin::CanPaste() {
24308af74909SZhong Yang if (!Editor::CanPaste())
24318af74909SZhong Yang return false;
24328af74909SZhong Yang return ::IsClipboardFormatAvailable(CF_UNICODETEXT) != FALSE;
24338af74909SZhong Yang }
24348af74909SZhong Yang
24358af74909SZhong Yang namespace {
24368af74909SZhong Yang
24378af74909SZhong Yang class GlobalMemory {
24388af74909SZhong Yang HGLOBAL hand {};
24398af74909SZhong Yang public:
24408af74909SZhong Yang void *ptr {};
GlobalMemory()24418af74909SZhong Yang GlobalMemory() noexcept {
24428af74909SZhong Yang }
GlobalMemory(HGLOBAL hand_)24438af74909SZhong Yang explicit GlobalMemory(HGLOBAL hand_) noexcept : hand(hand_) {
24448af74909SZhong Yang if (hand) {
24458af74909SZhong Yang ptr = ::GlobalLock(hand);
24468af74909SZhong Yang }
24478af74909SZhong Yang }
24488af74909SZhong Yang // Deleted so GlobalMemory objects can not be copied.
24498af74909SZhong Yang GlobalMemory(const GlobalMemory &) = delete;
24508af74909SZhong Yang GlobalMemory(GlobalMemory &&) = delete;
24518af74909SZhong Yang GlobalMemory &operator=(const GlobalMemory &) = delete;
24528af74909SZhong Yang GlobalMemory &operator=(GlobalMemory &&) = delete;
~GlobalMemory()24538af74909SZhong Yang ~GlobalMemory() {
24548af74909SZhong Yang assert(!ptr);
24558af74909SZhong Yang assert(!hand);
24568af74909SZhong Yang }
Allocate(size_t bytes)24578af74909SZhong Yang void Allocate(size_t bytes) noexcept {
24588af74909SZhong Yang assert(!hand);
24598af74909SZhong Yang hand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bytes);
24608af74909SZhong Yang if (hand) {
24618af74909SZhong Yang ptr = ::GlobalLock(hand);
24628af74909SZhong Yang }
24638af74909SZhong Yang }
Unlock()24648af74909SZhong Yang HGLOBAL Unlock() noexcept {
24658af74909SZhong Yang assert(ptr);
24668af74909SZhong Yang HGLOBAL handCopy = hand;
24678af74909SZhong Yang ::GlobalUnlock(hand);
24688af74909SZhong Yang ptr = nullptr;
24698af74909SZhong Yang hand = {};
24708af74909SZhong Yang return handCopy;
24718af74909SZhong Yang }
SetClip(UINT uFormat)24728af74909SZhong Yang void SetClip(UINT uFormat) noexcept {
24738af74909SZhong Yang ::SetClipboardData(uFormat, Unlock());
24748af74909SZhong Yang }
operator bool() const24758af74909SZhong Yang operator bool() const noexcept {
24768af74909SZhong Yang return ptr != nullptr;
24778af74909SZhong Yang }
Size() const24788af74909SZhong Yang SIZE_T Size() const noexcept {
24798af74909SZhong Yang return ::GlobalSize(hand);
24808af74909SZhong Yang }
24818af74909SZhong Yang };
24828af74909SZhong Yang
24838af74909SZhong Yang // OpenClipboard may fail if another application has opened the clipboard.
24848af74909SZhong Yang // Try up to 8 times, with an initial delay of 1 ms and an exponential back off
24858af74909SZhong Yang // for a maximum total delay of 127 ms (1+2+4+8+16+32+64).
OpenClipboardRetry(HWND hwnd)24868af74909SZhong Yang bool OpenClipboardRetry(HWND hwnd) noexcept {
24878af74909SZhong Yang for (int attempt=0; attempt<8; attempt++) {
24888af74909SZhong Yang if (attempt > 0) {
24898af74909SZhong Yang ::Sleep(1 << (attempt-1));
24908af74909SZhong Yang }
24918af74909SZhong Yang if (::OpenClipboard(hwnd)) {
24928af74909SZhong Yang return true;
24938af74909SZhong Yang }
24948af74909SZhong Yang }
24958af74909SZhong Yang return false;
24968af74909SZhong Yang }
24978af74909SZhong Yang
IsValidFormatEtc(const FORMATETC * pFE)24988af74909SZhong Yang bool IsValidFormatEtc(const FORMATETC *pFE) noexcept {
24998af74909SZhong Yang return pFE->ptd == nullptr &&
25008af74909SZhong Yang (pFE->dwAspect & DVASPECT_CONTENT) != 0 &&
25018af74909SZhong Yang pFE->lindex == -1 &&
25028af74909SZhong Yang (pFE->tymed & TYMED_HGLOBAL) != 0;
25038af74909SZhong Yang }
25048af74909SZhong Yang
SupportedFormat(const FORMATETC * pFE)25058af74909SZhong Yang bool SupportedFormat(const FORMATETC *pFE) noexcept {
25068af74909SZhong Yang return pFE->cfFormat == CF_UNICODETEXT &&
25078af74909SZhong Yang IsValidFormatEtc(pFE);
25088af74909SZhong Yang }
25098af74909SZhong Yang
25108af74909SZhong Yang }
25118af74909SZhong Yang
Paste()25128af74909SZhong Yang void ScintillaWin::Paste() {
25138af74909SZhong Yang if (!::OpenClipboardRetry(MainHWND())) {
25148af74909SZhong Yang return;
25158af74909SZhong Yang }
25168af74909SZhong Yang UndoGroup ug(pdoc);
25178af74909SZhong Yang const bool isLine = SelectionEmpty() &&
25188af74909SZhong Yang (::IsClipboardFormatAvailable(cfLineSelect) || ::IsClipboardFormatAvailable(cfVSLineTag));
25198af74909SZhong Yang ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH);
25208af74909SZhong Yang bool isRectangular = (::IsClipboardFormatAvailable(cfColumnSelect) != 0);
25218af74909SZhong Yang
25228af74909SZhong Yang if (!isRectangular) {
25238af74909SZhong Yang // Evaluate "Borland IDE Block Type" explicitly
25248af74909SZhong Yang GlobalMemory memBorlandSelection(::GetClipboardData(cfBorlandIDEBlockType));
25258af74909SZhong Yang if (memBorlandSelection) {
25268af74909SZhong Yang isRectangular = (memBorlandSelection.Size() == 1) && (static_cast<BYTE *>(memBorlandSelection.ptr)[0] == 0x02);
25278af74909SZhong Yang memBorlandSelection.Unlock();
25288af74909SZhong Yang }
25298af74909SZhong Yang }
25308af74909SZhong Yang const PasteShape pasteShape = isRectangular ? pasteRectangular : (isLine ? pasteLine : pasteStream);
25318af74909SZhong Yang
25328af74909SZhong Yang // Use CF_UNICODETEXT if available
25338af74909SZhong Yang GlobalMemory memUSelection(::GetClipboardData(CF_UNICODETEXT));
25348af74909SZhong Yang if (const wchar_t *uptr = static_cast<const wchar_t *>(memUSelection.ptr)) {
25358af74909SZhong Yang const std::string putf = EncodeWString(uptr);
25368af74909SZhong Yang InsertPasteShape(putf.c_str(), putf.length(), pasteShape);
25378af74909SZhong Yang memUSelection.Unlock();
25388af74909SZhong Yang }
25398af74909SZhong Yang ::CloseClipboard();
25408af74909SZhong Yang Redraw();
25418af74909SZhong Yang }
25428af74909SZhong Yang
CreateCallTipWindow(PRectangle)25438af74909SZhong Yang void ScintillaWin::CreateCallTipWindow(PRectangle) {
25448af74909SZhong Yang if (!ct.wCallTip.Created()) {
25458af74909SZhong Yang HWND wnd = ::CreateWindow(callClassName, TEXT("ACallTip"),
25468af74909SZhong Yang WS_POPUP, 100, 100, 150, 20,
25478af74909SZhong Yang MainHWND(), 0,
25488af74909SZhong Yang GetWindowInstance(MainHWND()),
25498af74909SZhong Yang this);
25508af74909SZhong Yang ct.wCallTip = wnd;
25518af74909SZhong Yang ct.wDraw = wnd;
25528af74909SZhong Yang }
25538af74909SZhong Yang }
25548af74909SZhong Yang
AddToPopUp(const wchar_t * label,int cmd,bool enabled)2555*f9763b28Slrisora void ScintillaWin::AddToPopUp(const wchar_t* label, int cmd, bool enabled) {
25568af74909SZhong Yang HMENU hmenuPopup = static_cast<HMENU>(popup.GetID());
25578af74909SZhong Yang if (!label[0])
2558*f9763b28Slrisora ::AppendMenu(hmenuPopup, MF_SEPARATOR, 0, L"");
25598af74909SZhong Yang else if (enabled)
25608af74909SZhong Yang ::AppendMenu(hmenuPopup, MF_STRING, cmd, label);
25618af74909SZhong Yang else
25628af74909SZhong Yang ::AppendMenu(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label);
25638af74909SZhong Yang }
25648af74909SZhong Yang
ClaimSelection()25658af74909SZhong Yang void ScintillaWin::ClaimSelection() {
25668af74909SZhong Yang // Windows does not have a primary selection
25678af74909SZhong Yang }
25688af74909SZhong Yang
25698af74909SZhong Yang /// Implement IUnknown
25708af74909SZhong Yang
25718af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe);
FormatEnumerator_QueryInterface(FormatEnumerator * fe,REFIID riid,PVOID * ppv)25728af74909SZhong Yang STDMETHODIMP FormatEnumerator_QueryInterface(FormatEnumerator *fe, REFIID riid, PVOID *ppv) {
25738af74909SZhong Yang //Platform::DebugPrintf("EFE QI");
25748af74909SZhong Yang *ppv = nullptr;
25758af74909SZhong Yang if (riid == IID_IUnknown)
25768af74909SZhong Yang *ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
25778af74909SZhong Yang if (riid == IID_IEnumFORMATETC)
25788af74909SZhong Yang *ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
25798af74909SZhong Yang if (!*ppv)
25808af74909SZhong Yang return E_NOINTERFACE;
25818af74909SZhong Yang FormatEnumerator_AddRef(fe);
25828af74909SZhong Yang return S_OK;
25838af74909SZhong Yang }
FormatEnumerator_AddRef(FormatEnumerator * fe)25848af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) {
25858af74909SZhong Yang return ++fe->ref;
25868af74909SZhong Yang }
FormatEnumerator_Release(FormatEnumerator * fe)25878af74909SZhong Yang STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) {
25888af74909SZhong Yang fe->ref--;
25898af74909SZhong Yang if (fe->ref > 0)
25908af74909SZhong Yang return fe->ref;
25918af74909SZhong Yang delete fe;
25928af74909SZhong Yang return 0;
25938af74909SZhong Yang }
25948af74909SZhong Yang /// Implement IEnumFORMATETC
FormatEnumerator_Next(FormatEnumerator * fe,ULONG celt,FORMATETC * rgelt,ULONG * pceltFetched)25958af74909SZhong Yang STDMETHODIMP FormatEnumerator_Next(FormatEnumerator *fe, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
25968af74909SZhong Yang if (!rgelt) return E_POINTER;
25978af74909SZhong Yang ULONG putPos = 0;
25988af74909SZhong Yang while ((fe->pos < fe->formats.size()) && (putPos < celt)) {
25998af74909SZhong Yang rgelt->cfFormat = fe->formats[fe->pos];
26008af74909SZhong Yang rgelt->ptd = nullptr;
26018af74909SZhong Yang rgelt->dwAspect = DVASPECT_CONTENT;
26028af74909SZhong Yang rgelt->lindex = -1;
26038af74909SZhong Yang rgelt->tymed = TYMED_HGLOBAL;
26048af74909SZhong Yang rgelt++;
26058af74909SZhong Yang fe->pos++;
26068af74909SZhong Yang putPos++;
26078af74909SZhong Yang }
26088af74909SZhong Yang if (pceltFetched)
26098af74909SZhong Yang *pceltFetched = putPos;
26108af74909SZhong Yang return putPos ? S_OK : S_FALSE;
26118af74909SZhong Yang }
FormatEnumerator_Skip(FormatEnumerator * fe,ULONG celt)26128af74909SZhong Yang STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) {
26138af74909SZhong Yang fe->pos += celt;
26148af74909SZhong Yang return S_OK;
26158af74909SZhong Yang }
FormatEnumerator_Reset(FormatEnumerator * fe)26168af74909SZhong Yang STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) {
26178af74909SZhong Yang fe->pos = 0;
26188af74909SZhong Yang return S_OK;
26198af74909SZhong Yang }
FormatEnumerator_Clone(FormatEnumerator * fe,IEnumFORMATETC ** ppenum)26208af74909SZhong Yang STDMETHODIMP FormatEnumerator_Clone(FormatEnumerator *fe, IEnumFORMATETC **ppenum) {
26218af74909SZhong Yang FormatEnumerator *pfe;
26228af74909SZhong Yang try {
26238af74909SZhong Yang pfe = new FormatEnumerator(fe->pos, &fe->formats[0], fe->formats.size());
26248af74909SZhong Yang } catch (...) {
26258af74909SZhong Yang return E_OUTOFMEMORY;
26268af74909SZhong Yang }
26278af74909SZhong Yang return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
26288af74909SZhong Yang reinterpret_cast<void **>(ppenum));
26298af74909SZhong Yang }
26308af74909SZhong Yang
26318af74909SZhong Yang static VFunction *vtFormatEnumerator[] = {
26328af74909SZhong Yang (VFunction *)(FormatEnumerator_QueryInterface),
26338af74909SZhong Yang (VFunction *)(FormatEnumerator_AddRef),
26348af74909SZhong Yang (VFunction *)(FormatEnumerator_Release),
26358af74909SZhong Yang (VFunction *)(FormatEnumerator_Next),
26368af74909SZhong Yang (VFunction *)(FormatEnumerator_Skip),
26378af74909SZhong Yang (VFunction *)(FormatEnumerator_Reset),
26388af74909SZhong Yang (VFunction *)(FormatEnumerator_Clone)
26398af74909SZhong Yang };
26408af74909SZhong Yang
FormatEnumerator(ULONG pos_,const CLIPFORMAT formats_[],size_t formatsLen_)26418af74909SZhong Yang FormatEnumerator::FormatEnumerator(ULONG pos_, const CLIPFORMAT formats_[], size_t formatsLen_) {
26428af74909SZhong Yang vtbl = vtFormatEnumerator;
26438af74909SZhong Yang ref = 0; // First QI adds first reference...
26448af74909SZhong Yang pos = pos_;
26458af74909SZhong Yang formats.insert(formats.begin(), formats_, formats_+formatsLen_);
26468af74909SZhong Yang }
26478af74909SZhong Yang
26488af74909SZhong Yang /// Implement IUnknown
DropSource_QueryInterface(DropSource * ds,REFIID riid,PVOID * ppv)26498af74909SZhong Yang STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) {
26508af74909SZhong Yang return ds->sci->QueryInterface(riid, ppv);
26518af74909SZhong Yang }
DropSource_AddRef(DropSource * ds)26528af74909SZhong Yang STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) {
26538af74909SZhong Yang return ds->sci->AddRef();
26548af74909SZhong Yang }
DropSource_Release(DropSource * ds)26558af74909SZhong Yang STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) {
26568af74909SZhong Yang return ds->sci->Release();
26578af74909SZhong Yang }
26588af74909SZhong Yang
26598af74909SZhong Yang /// Implement IDropSource
DropSource_QueryContinueDrag(DropSource *,BOOL fEsc,DWORD grfKeyState)26608af74909SZhong Yang STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) {
26618af74909SZhong Yang if (fEsc)
26628af74909SZhong Yang return DRAGDROP_S_CANCEL;
26638af74909SZhong Yang if (!(grfKeyState & MK_LBUTTON))
26648af74909SZhong Yang return DRAGDROP_S_DROP;
26658af74909SZhong Yang return S_OK;
26668af74909SZhong Yang }
26678af74909SZhong Yang
DropSource_GiveFeedback(DropSource *,DWORD)26688af74909SZhong Yang STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) {
26698af74909SZhong Yang return DRAGDROP_S_USEDEFAULTCURSORS;
26708af74909SZhong Yang }
26718af74909SZhong Yang
26728af74909SZhong Yang static VFunction *vtDropSource[] = {
26738af74909SZhong Yang (VFunction *)(DropSource_QueryInterface),
26748af74909SZhong Yang (VFunction *)(DropSource_AddRef),
26758af74909SZhong Yang (VFunction *)(DropSource_Release),
26768af74909SZhong Yang (VFunction *)(DropSource_QueryContinueDrag),
26778af74909SZhong Yang (VFunction *)(DropSource_GiveFeedback)
26788af74909SZhong Yang };
26798af74909SZhong Yang
DropSource()26808af74909SZhong Yang DropSource::DropSource() noexcept {
26818af74909SZhong Yang vtbl = vtDropSource;
26828af74909SZhong Yang sci = nullptr;
26838af74909SZhong Yang }
26848af74909SZhong Yang
26858af74909SZhong Yang /// Implement IUnkown
DataObject_QueryInterface(DataObject * pd,REFIID riid,PVOID * ppv)26868af74909SZhong Yang STDMETHODIMP DataObject_QueryInterface(DataObject *pd, REFIID riid, PVOID *ppv) {
26878af74909SZhong Yang //Platform::DebugPrintf("DO QI %x\n", pd);
26888af74909SZhong Yang return pd->sci->QueryInterface(riid, ppv);
26898af74909SZhong Yang }
DataObject_AddRef(DataObject * pd)26908af74909SZhong Yang STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) {
26918af74909SZhong Yang return pd->sci->AddRef();
26928af74909SZhong Yang }
DataObject_Release(DataObject * pd)26938af74909SZhong Yang STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) {
26948af74909SZhong Yang return pd->sci->Release();
26958af74909SZhong Yang }
26968af74909SZhong Yang /// Implement IDataObject
DataObject_GetData(DataObject * pd,FORMATETC * pFEIn,STGMEDIUM * pSTM)26978af74909SZhong Yang STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) {
26988af74909SZhong Yang return pd->sci->GetData(pFEIn, pSTM);
26998af74909SZhong Yang }
27008af74909SZhong Yang
DataObject_GetDataHere(DataObject *,FORMATETC *,STGMEDIUM *)27018af74909SZhong Yang STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) {
27028af74909SZhong Yang //Platform::DebugPrintf("DOB GetDataHere\n");
27038af74909SZhong Yang return E_NOTIMPL;
27048af74909SZhong Yang }
27058af74909SZhong Yang
DataObject_QueryGetData(DataObject * pd,FORMATETC * pFE)27068af74909SZhong Yang STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) {
27078af74909SZhong Yang if (pd->sci->DragIsRectangularOK(pFE->cfFormat) && IsValidFormatEtc(pFE)) {
27088af74909SZhong Yang return S_OK;
27098af74909SZhong Yang }
27108af74909SZhong Yang
27118af74909SZhong Yang if (SupportedFormat(pFE)) {
27128af74909SZhong Yang return S_OK;
27138af74909SZhong Yang } else {
27148af74909SZhong Yang return S_FALSE;
27158af74909SZhong Yang }
27168af74909SZhong Yang }
27178af74909SZhong Yang
DataObject_GetCanonicalFormatEtc(DataObject *,FORMATETC *,FORMATETC * pFEOut)27188af74909SZhong Yang STDMETHODIMP DataObject_GetCanonicalFormatEtc(DataObject *, FORMATETC *, FORMATETC *pFEOut) {
27198af74909SZhong Yang //Platform::DebugPrintf("DOB GetCanon\n");
27208af74909SZhong Yang pFEOut->cfFormat = CF_UNICODETEXT;
27218af74909SZhong Yang pFEOut->ptd = nullptr;
27228af74909SZhong Yang pFEOut->dwAspect = DVASPECT_CONTENT;
27238af74909SZhong Yang pFEOut->lindex = -1;
27248af74909SZhong Yang pFEOut->tymed = TYMED_HGLOBAL;
27258af74909SZhong Yang return S_OK;
27268af74909SZhong Yang }
27278af74909SZhong Yang
DataObject_SetData(DataObject *,FORMATETC *,STGMEDIUM *,BOOL)27288af74909SZhong Yang STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) {
27298af74909SZhong Yang //Platform::DebugPrintf("DOB SetData\n");
27308af74909SZhong Yang return E_FAIL;
27318af74909SZhong Yang }
27328af74909SZhong Yang
DataObject_EnumFormatEtc(DataObject * pd,DWORD dwDirection,IEnumFORMATETC ** ppEnum)27338af74909SZhong Yang STDMETHODIMP DataObject_EnumFormatEtc(DataObject *pd, DWORD dwDirection, IEnumFORMATETC **ppEnum) {
27348af74909SZhong Yang try {
27358af74909SZhong Yang //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
27368af74909SZhong Yang if (dwDirection != DATADIR_GET) {
27378af74909SZhong Yang *ppEnum = nullptr;
27388af74909SZhong Yang return E_FAIL;
27398af74909SZhong Yang }
27408af74909SZhong Yang
27418af74909SZhong Yang const CLIPFORMAT formats[] = {CF_UNICODETEXT};
27428af74909SZhong Yang FormatEnumerator *pfe = new FormatEnumerator(0, formats, std::size(formats));
27438af74909SZhong Yang return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
27448af74909SZhong Yang reinterpret_cast<void **>(ppEnum));
27458af74909SZhong Yang } catch (std::bad_alloc &) {
27468af74909SZhong Yang pd->sci->errorStatus = SC_STATUS_BADALLOC;
27478af74909SZhong Yang return E_OUTOFMEMORY;
27488af74909SZhong Yang } catch (...) {
27498af74909SZhong Yang pd->sci->errorStatus = SC_STATUS_FAILURE;
27508af74909SZhong Yang return E_FAIL;
27518af74909SZhong Yang }
27528af74909SZhong Yang }
27538af74909SZhong Yang
DataObject_DAdvise(DataObject *,FORMATETC *,DWORD,IAdviseSink *,PDWORD)27548af74909SZhong Yang STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) {
27558af74909SZhong Yang //Platform::DebugPrintf("DOB DAdvise\n");
27568af74909SZhong Yang return E_FAIL;
27578af74909SZhong Yang }
27588af74909SZhong Yang
DataObject_DUnadvise(DataObject *,DWORD)27598af74909SZhong Yang STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) {
27608af74909SZhong Yang //Platform::DebugPrintf("DOB DUnadvise\n");
27618af74909SZhong Yang return E_FAIL;
27628af74909SZhong Yang }
27638af74909SZhong Yang
DataObject_EnumDAdvise(DataObject *,IEnumSTATDATA **)27648af74909SZhong Yang STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) {
27658af74909SZhong Yang //Platform::DebugPrintf("DOB EnumDAdvise\n");
27668af74909SZhong Yang return E_FAIL;
27678af74909SZhong Yang }
27688af74909SZhong Yang
27698af74909SZhong Yang static VFunction *vtDataObject[] = {
27708af74909SZhong Yang (VFunction *)(DataObject_QueryInterface),
27718af74909SZhong Yang (VFunction *)(DataObject_AddRef),
27728af74909SZhong Yang (VFunction *)(DataObject_Release),
27738af74909SZhong Yang (VFunction *)(DataObject_GetData),
27748af74909SZhong Yang (VFunction *)(DataObject_GetDataHere),
27758af74909SZhong Yang (VFunction *)(DataObject_QueryGetData),
27768af74909SZhong Yang (VFunction *)(DataObject_GetCanonicalFormatEtc),
27778af74909SZhong Yang (VFunction *)(DataObject_SetData),
27788af74909SZhong Yang (VFunction *)(DataObject_EnumFormatEtc),
27798af74909SZhong Yang (VFunction *)(DataObject_DAdvise),
27808af74909SZhong Yang (VFunction *)(DataObject_DUnadvise),
27818af74909SZhong Yang (VFunction *)(DataObject_EnumDAdvise)
27828af74909SZhong Yang };
27838af74909SZhong Yang
DataObject()27848af74909SZhong Yang DataObject::DataObject() noexcept {
27858af74909SZhong Yang vtbl = vtDataObject;
27868af74909SZhong Yang sci = nullptr;
27878af74909SZhong Yang }
27888af74909SZhong Yang
27898af74909SZhong Yang /// Implement IUnknown
DropTarget_QueryInterface(DropTarget * dt,REFIID riid,PVOID * ppv)27908af74909SZhong Yang STDMETHODIMP DropTarget_QueryInterface(DropTarget *dt, REFIID riid, PVOID *ppv) {
27918af74909SZhong Yang //Platform::DebugPrintf("DT QI %x\n", dt);
27928af74909SZhong Yang return dt->sci->QueryInterface(riid, ppv);
27938af74909SZhong Yang }
DropTarget_AddRef(DropTarget * dt)27948af74909SZhong Yang STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) {
27958af74909SZhong Yang return dt->sci->AddRef();
27968af74909SZhong Yang }
DropTarget_Release(DropTarget * dt)27978af74909SZhong Yang STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) {
27988af74909SZhong Yang return dt->sci->Release();
27998af74909SZhong Yang }
28008af74909SZhong Yang
28018af74909SZhong Yang /// Implement IDropTarget by forwarding to Scintilla
DropTarget_DragEnter(DropTarget * dt,LPDATAOBJECT pIDataSource,DWORD grfKeyState,POINTL pt,PDWORD pdwEffect)28028af74909SZhong Yang STDMETHODIMP DropTarget_DragEnter(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
28038af74909SZhong Yang POINTL pt, PDWORD pdwEffect) {
28048af74909SZhong Yang try {
28058af74909SZhong Yang return dt->sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect);
28068af74909SZhong Yang } catch (...) {
28078af74909SZhong Yang dt->sci->errorStatus = SC_STATUS_FAILURE;
28088af74909SZhong Yang }
28098af74909SZhong Yang return E_FAIL;
28108af74909SZhong Yang }
DropTarget_DragOver(DropTarget * dt,DWORD grfKeyState,POINTL pt,PDWORD pdwEffect)28118af74909SZhong Yang STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
28128af74909SZhong Yang try {
28138af74909SZhong Yang return dt->sci->DragOver(grfKeyState, pt, pdwEffect);
28148af74909SZhong Yang } catch (...) {
28158af74909SZhong Yang dt->sci->errorStatus = SC_STATUS_FAILURE;
28168af74909SZhong Yang }
28178af74909SZhong Yang return E_FAIL;
28188af74909SZhong Yang }
DropTarget_DragLeave(DropTarget * dt)28198af74909SZhong Yang STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) {
28208af74909SZhong Yang try {
28218af74909SZhong Yang return dt->sci->DragLeave();
28228af74909SZhong Yang } catch (...) {
28238af74909SZhong Yang dt->sci->errorStatus = SC_STATUS_FAILURE;
28248af74909SZhong Yang }
28258af74909SZhong Yang return E_FAIL;
28268af74909SZhong Yang }
DropTarget_Drop(DropTarget * dt,LPDATAOBJECT pIDataSource,DWORD grfKeyState,POINTL pt,PDWORD pdwEffect)28278af74909SZhong Yang STDMETHODIMP DropTarget_Drop(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
28288af74909SZhong Yang POINTL pt, PDWORD pdwEffect) {
28298af74909SZhong Yang try {
28308af74909SZhong Yang return dt->sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect);
28318af74909SZhong Yang } catch (...) {
28328af74909SZhong Yang dt->sci->errorStatus = SC_STATUS_FAILURE;
28338af74909SZhong Yang }
28348af74909SZhong Yang return E_FAIL;
28358af74909SZhong Yang }
28368af74909SZhong Yang
28378af74909SZhong Yang static VFunction *vtDropTarget[] = {
28388af74909SZhong Yang (VFunction *)(DropTarget_QueryInterface),
28398af74909SZhong Yang (VFunction *)(DropTarget_AddRef),
28408af74909SZhong Yang (VFunction *)(DropTarget_Release),
28418af74909SZhong Yang (VFunction *)(DropTarget_DragEnter),
28428af74909SZhong Yang (VFunction *)(DropTarget_DragOver),
28438af74909SZhong Yang (VFunction *)(DropTarget_DragLeave),
28448af74909SZhong Yang (VFunction *)(DropTarget_Drop)
28458af74909SZhong Yang };
28468af74909SZhong Yang
DropTarget()28478af74909SZhong Yang DropTarget::DropTarget() noexcept {
28488af74909SZhong Yang vtbl = vtDropTarget;
28498af74909SZhong Yang sci = nullptr;
28508af74909SZhong Yang }
28518af74909SZhong Yang
28528af74909SZhong Yang /**
28538af74909SZhong Yang * DBCS: support Input Method Editor (IME).
28548af74909SZhong Yang * Called when IME Window opened.
28558af74909SZhong Yang */
ImeStartComposition()28568af74909SZhong Yang void ScintillaWin::ImeStartComposition() {
28578af74909SZhong Yang if (caret.active) {
28588af74909SZhong Yang // Move IME Window to current caret position
28598af74909SZhong Yang IMContext imc(MainHWND());
28608af74909SZhong Yang const Point pos = PointMainCaret();
28618af74909SZhong Yang COMPOSITIONFORM CompForm;
28628af74909SZhong Yang CompForm.dwStyle = CFS_POINT;
28638af74909SZhong Yang CompForm.ptCurrentPos = POINTFromPoint(pos);
28648af74909SZhong Yang
28658af74909SZhong Yang ::ImmSetCompositionWindow(imc.hIMC, &CompForm);
28668af74909SZhong Yang
28678af74909SZhong Yang // Set font of IME window to same as surrounded text.
28688af74909SZhong Yang if (stylesValid) {
28698af74909SZhong Yang // Since the style creation code has been made platform independent,
28708af74909SZhong Yang // The logfont for the IME is recreated here.
28718af74909SZhong Yang //const int styleHere = pdoc->StyleIndexAt(sel.MainCaret());
28728af74909SZhong Yang const int styleHere = STYLE_DEFAULT;
28738af74909SZhong Yang LOGFONTW lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L""};
28748af74909SZhong Yang int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER;
28758af74909SZhong Yang if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1
28768af74909SZhong Yang sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
28778af74909SZhong Yang // The negative is to allow for leading
28788af74909SZhong Yang lf.lfHeight = -::MulDiv(sizeZoomed, dpi, 72*SC_FONT_SIZE_MULTIPLIER);
28798af74909SZhong Yang lf.lfWeight = vs.styles[styleHere].weight;
28808af74909SZhong Yang lf.lfItalic = vs.styles[styleHere].italic ? 1 : 0;
28818af74909SZhong Yang lf.lfCharSet = DEFAULT_CHARSET;
28828af74909SZhong Yang lf.lfFaceName[0] = L'\0';
28838af74909SZhong Yang if (vs.styles[styleHere].fontName) {
28848af74909SZhong Yang const char* fontName = vs.styles[styleHere].fontName;
28858af74909SZhong Yang UTF16FromUTF8(std::string_view(fontName), lf.lfFaceName, LF_FACESIZE);
28868af74909SZhong Yang }
28878af74909SZhong Yang
28888af74909SZhong Yang ::ImmSetCompositionFontW(imc.hIMC, &lf);
28898af74909SZhong Yang }
28908af74909SZhong Yang // Caret is displayed in IME window. So, caret in Scintilla is useless.
28918af74909SZhong Yang DropCaret();
28928af74909SZhong Yang }
28938af74909SZhong Yang }
28948af74909SZhong Yang
28958af74909SZhong Yang /** Called when IME Window closed. */
ImeEndComposition()28968af74909SZhong Yang void ScintillaWin::ImeEndComposition() {
28978af74909SZhong Yang // clear IME composition state.
28988af74909SZhong Yang view.imeCaretBlockOverride = false;
28998af74909SZhong Yang pdoc->TentativeUndo();
29008af74909SZhong Yang ShowCaretAtCurrentPosition();
29018af74909SZhong Yang }
29028af74909SZhong Yang
ImeOnReconvert(LPARAM lParam)29038af74909SZhong Yang LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) {
29048af74909SZhong Yang // Reconversion on windows limits within one line without eol.
29058af74909SZhong Yang // Look around: baseStart <-- (|mainStart| -- mainEnd) --> baseEnd.
29068af74909SZhong Yang const Sci::Position mainStart = sel.RangeMain().Start().Position();
29078af74909SZhong Yang const Sci::Position mainEnd = sel.RangeMain().End().Position();
29088af74909SZhong Yang const Sci::Line curLine = pdoc->SciLineFromPosition(mainStart);
29098af74909SZhong Yang if (curLine != pdoc->LineFromPosition(mainEnd))
29108af74909SZhong Yang return 0;
29118af74909SZhong Yang const Sci::Position baseStart = pdoc->LineStart(curLine);
29128af74909SZhong Yang const Sci::Position baseEnd = pdoc->LineEnd(curLine);
29138af74909SZhong Yang if ((baseStart == baseEnd) || (mainEnd > baseEnd))
29148af74909SZhong Yang return 0;
29158af74909SZhong Yang
29168af74909SZhong Yang const int codePage = CodePageOfDocument();
29178af74909SZhong Yang const std::wstring rcFeed = StringDecode(RangeText(baseStart, baseEnd), codePage);
29188af74909SZhong Yang const int rcFeedLen = static_cast<int>(rcFeed.length()) * sizeof(wchar_t);
29198af74909SZhong Yang const int rcSize = sizeof(RECONVERTSTRING) + rcFeedLen + sizeof(wchar_t);
29208af74909SZhong Yang
29218af74909SZhong Yang RECONVERTSTRING *rc = static_cast<RECONVERTSTRING *>(PtrFromSPtr(lParam));
29228af74909SZhong Yang if (!rc)
29238af74909SZhong Yang return rcSize; // Immediately be back with rcSize of memory block.
29248af74909SZhong Yang
29258af74909SZhong Yang wchar_t *rcFeedStart = reinterpret_cast<wchar_t*>(rc + 1);
29268af74909SZhong Yang memcpy(rcFeedStart, &rcFeed[0], rcFeedLen);
29278af74909SZhong Yang
29288af74909SZhong Yang std::string rcCompString = RangeText(mainStart, mainEnd);
29298af74909SZhong Yang std::wstring rcCompWstring = StringDecode(rcCompString, codePage);
29308af74909SZhong Yang std::string rcCompStart = RangeText(baseStart, mainStart);
29318af74909SZhong Yang std::wstring rcCompWstart = StringDecode(rcCompStart, codePage);
29328af74909SZhong Yang
29338af74909SZhong Yang // Map selection to dwCompStr.
29348af74909SZhong Yang // No selection assumes current caret as rcCompString without length.
29358af74909SZhong Yang rc->dwVersion = 0; // It should be absolutely 0.
29368af74909SZhong Yang rc->dwStrLen = static_cast<DWORD>(rcFeed.length());
29378af74909SZhong Yang rc->dwStrOffset = sizeof(RECONVERTSTRING);
29388af74909SZhong Yang rc->dwCompStrLen = static_cast<DWORD>(rcCompWstring.length());
29398af74909SZhong Yang rc->dwCompStrOffset = static_cast<DWORD>(rcCompWstart.length()) * sizeof(wchar_t);
29408af74909SZhong Yang rc->dwTargetStrLen = rc->dwCompStrLen;
29418af74909SZhong Yang rc->dwTargetStrOffset =rc->dwCompStrOffset;
29428af74909SZhong Yang
29438af74909SZhong Yang IMContext imc(MainHWND());
29448af74909SZhong Yang if (!imc.hIMC)
29458af74909SZhong Yang return 0;
29468af74909SZhong Yang
29478af74909SZhong Yang if (!::ImmSetCompositionStringW(imc.hIMC, SCS_QUERYRECONVERTSTRING, rc, rcSize, nullptr, 0))
29488af74909SZhong Yang return 0;
29498af74909SZhong Yang
29508af74909SZhong Yang // No selection asks IME to fill target fields with its own value.
29518af74909SZhong Yang const int tgWlen = rc->dwTargetStrLen;
29528af74909SZhong Yang const int tgWstart = rc->dwTargetStrOffset / sizeof(wchar_t);
29538af74909SZhong Yang
29548af74909SZhong Yang std::string tgCompStart = StringEncode(rcFeed.substr(0, tgWstart), codePage);
29558af74909SZhong Yang std::string tgComp = StringEncode(rcFeed.substr(tgWstart, tgWlen), codePage);
29568af74909SZhong Yang
29578af74909SZhong Yang // No selection needs to adjust reconvert start position for IME set.
29588af74909SZhong Yang const int adjust = static_cast<int>(tgCompStart.length() - rcCompStart.length());
29598af74909SZhong Yang const int docCompLen = static_cast<int>(tgComp.length());
29608af74909SZhong Yang
29618af74909SZhong Yang // Make place for next composition string to sit in.
29628af74909SZhong Yang for (size_t r=0; r<sel.Count(); r++) {
29638af74909SZhong Yang const Sci::Position rBase = sel.Range(r).Start().Position();
29648af74909SZhong Yang const Sci::Position docCompStart = rBase + adjust;
29658af74909SZhong Yang
29668af74909SZhong Yang if (inOverstrike) { // the docCompLen of bytes will be overstriked.
29678af74909SZhong Yang sel.Range(r).caret.SetPosition(docCompStart);
29688af74909SZhong Yang sel.Range(r).anchor.SetPosition(docCompStart);
29698af74909SZhong Yang } else {
29708af74909SZhong Yang // Ensure docCompStart+docCompLen be not beyond lineEnd.
29718af74909SZhong Yang // since docCompLen by byte might break eol.
29728af74909SZhong Yang const Sci::Position lineEnd = pdoc->LineEnd(pdoc->LineFromPosition(rBase));
29738af74909SZhong Yang const Sci::Position overflow = (docCompStart + docCompLen) - lineEnd;
29748af74909SZhong Yang if (overflow > 0) {
29758af74909SZhong Yang pdoc->DeleteChars(docCompStart, docCompLen - overflow);
29768af74909SZhong Yang } else {
29778af74909SZhong Yang pdoc->DeleteChars(docCompStart, docCompLen);
29788af74909SZhong Yang }
29798af74909SZhong Yang }
29808af74909SZhong Yang }
29818af74909SZhong Yang // Immediately Target Input or candidate box choice with GCS_COMPSTR.
29828af74909SZhong Yang return rcSize;
29838af74909SZhong Yang }
29848af74909SZhong Yang
GetIntelliMouseParameters()29858af74909SZhong Yang void ScintillaWin::GetIntelliMouseParameters() noexcept {
29868af74909SZhong Yang // This retrieves the number of lines per scroll as configured in the Mouse Properties sheet in Control Panel
29878af74909SZhong Yang ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
29888af74909SZhong Yang }
29898af74909SZhong Yang
CopyToGlobal(GlobalMemory & gmUnicode,const SelectionText & selectedText)29908af74909SZhong Yang void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText) {
29918af74909SZhong Yang const std::string_view svSelected(selectedText.Data(), selectedText.LengthWithTerminator());
29928af74909SZhong Yang if (IsUnicodeMode()) {
29938af74909SZhong Yang const size_t uchars = UTF16Length(svSelected);
29948af74909SZhong Yang gmUnicode.Allocate(2 * uchars);
29958af74909SZhong Yang if (gmUnicode) {
29968af74909SZhong Yang UTF16FromUTF8(svSelected,
29978af74909SZhong Yang static_cast<wchar_t *>(gmUnicode.ptr), uchars);
29988af74909SZhong Yang }
29998af74909SZhong Yang } else {
30008af74909SZhong Yang // Not Unicode mode
30018af74909SZhong Yang // Convert to Unicode using the current Scintilla code page
30028af74909SZhong Yang const UINT cpSrc = CodePageFromCharSet(
30038af74909SZhong Yang selectedText.characterSet, selectedText.codePage);
30048af74909SZhong Yang const size_t uLen = WideCharLenFromMultiByte(cpSrc, svSelected);
30058af74909SZhong Yang gmUnicode.Allocate(2 * uLen);
30068af74909SZhong Yang if (gmUnicode) {
30078af74909SZhong Yang WideCharFromMultiByte(cpSrc, svSelected,
30088af74909SZhong Yang static_cast<wchar_t *>(gmUnicode.ptr), uLen);
30098af74909SZhong Yang }
30108af74909SZhong Yang }
30118af74909SZhong Yang }
30128af74909SZhong Yang
CopyToClipboard(const SelectionText & selectedText)30138af74909SZhong Yang void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
30148af74909SZhong Yang if (!::OpenClipboardRetry(MainHWND())) {
30158af74909SZhong Yang return;
30168af74909SZhong Yang }
30178af74909SZhong Yang ::EmptyClipboard();
30188af74909SZhong Yang
30198af74909SZhong Yang GlobalMemory uniText;
30208af74909SZhong Yang CopyToGlobal(uniText, selectedText);
30218af74909SZhong Yang if (uniText) {
30228af74909SZhong Yang uniText.SetClip(CF_UNICODETEXT);
30238af74909SZhong Yang }
30248af74909SZhong Yang
30258af74909SZhong Yang if (selectedText.rectangular) {
30268af74909SZhong Yang ::SetClipboardData(cfColumnSelect, 0);
30278af74909SZhong Yang
30288af74909SZhong Yang GlobalMemory borlandSelection;
30298af74909SZhong Yang borlandSelection.Allocate(1);
30308af74909SZhong Yang if (borlandSelection) {
30318af74909SZhong Yang static_cast<BYTE *>(borlandSelection.ptr)[0] = 0x02;
30328af74909SZhong Yang borlandSelection.SetClip(cfBorlandIDEBlockType);
30338af74909SZhong Yang }
30348af74909SZhong Yang }
30358af74909SZhong Yang
30368af74909SZhong Yang if (selectedText.lineCopy) {
30378af74909SZhong Yang ::SetClipboardData(cfLineSelect, 0);
30388af74909SZhong Yang ::SetClipboardData(cfVSLineTag, 0);
30398af74909SZhong Yang }
30408af74909SZhong Yang
30418af74909SZhong Yang ::CloseClipboard();
30428af74909SZhong Yang }
30438af74909SZhong Yang
ScrollMessage(WPARAM wParam)30448af74909SZhong Yang void ScintillaWin::ScrollMessage(WPARAM wParam) {
30458af74909SZhong Yang //DWORD dwStart = timeGetTime();
30468af74909SZhong Yang //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
30478af74909SZhong Yang
30488af74909SZhong Yang SCROLLINFO sci = {};
30498af74909SZhong Yang sci.cbSize = sizeof(sci);
30508af74909SZhong Yang sci.fMask = SIF_ALL;
30518af74909SZhong Yang
30528af74909SZhong Yang GetScrollInfo(SB_VERT, &sci);
30538af74909SZhong Yang
30548af74909SZhong Yang //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
30558af74909SZhong Yang //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
30568af74909SZhong Yang Sci::Line topLineNew = topLine;
30578af74909SZhong Yang switch (LOWORD(wParam)) {
30588af74909SZhong Yang case SB_LINEUP:
30598af74909SZhong Yang topLineNew -= 1;
30608af74909SZhong Yang break;
30618af74909SZhong Yang case SB_LINEDOWN:
30628af74909SZhong Yang topLineNew += 1;
30638af74909SZhong Yang break;
30648af74909SZhong Yang case SB_PAGEUP:
30658af74909SZhong Yang topLineNew -= LinesToScroll(); break;
30668af74909SZhong Yang case SB_PAGEDOWN: topLineNew += LinesToScroll(); break;
30678af74909SZhong Yang case SB_TOP: topLineNew = 0; break;
30688af74909SZhong Yang case SB_BOTTOM: topLineNew = MaxScrollPos(); break;
30698af74909SZhong Yang case SB_THUMBPOSITION: topLineNew = sci.nTrackPos; break;
30708af74909SZhong Yang case SB_THUMBTRACK: topLineNew = sci.nTrackPos; break;
30718af74909SZhong Yang }
30728af74909SZhong Yang ScrollTo(topLineNew);
30738af74909SZhong Yang }
30748af74909SZhong Yang
HorizontalScrollMessage(WPARAM wParam)30758af74909SZhong Yang void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) {
30768af74909SZhong Yang int xPos = xOffset;
30778af74909SZhong Yang const PRectangle rcText = GetTextRectangle();
30788af74909SZhong Yang const int pageWidth = static_cast<int>(rcText.Width() * 2 / 3);
30798af74909SZhong Yang switch (LOWORD(wParam)) {
30808af74909SZhong Yang case SB_LINEUP:
30818af74909SZhong Yang xPos -= 20;
30828af74909SZhong Yang break;
30838af74909SZhong Yang case SB_LINEDOWN: // May move past the logical end
30848af74909SZhong Yang xPos += 20;
30858af74909SZhong Yang break;
30868af74909SZhong Yang case SB_PAGEUP:
30878af74909SZhong Yang xPos -= pageWidth;
30888af74909SZhong Yang break;
30898af74909SZhong Yang case SB_PAGEDOWN:
30908af74909SZhong Yang xPos += pageWidth;
30918af74909SZhong Yang if (xPos > scrollWidth - rcText.Width()) { // Hit the end exactly
30928af74909SZhong Yang xPos = scrollWidth - static_cast<int>(rcText.Width());
30938af74909SZhong Yang }
30948af74909SZhong Yang break;
30958af74909SZhong Yang case SB_TOP:
30968af74909SZhong Yang xPos = 0;
30978af74909SZhong Yang break;
30988af74909SZhong Yang case SB_BOTTOM:
30998af74909SZhong Yang xPos = scrollWidth;
31008af74909SZhong Yang break;
31018af74909SZhong Yang case SB_THUMBPOSITION:
31028af74909SZhong Yang case SB_THUMBTRACK: {
31038af74909SZhong 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 =]
31048af74909SZhong Yang SCROLLINFO si;
31058af74909SZhong Yang si.cbSize = sizeof(si);
31068af74909SZhong Yang si.fMask = SIF_TRACKPOS;
31078af74909SZhong Yang if (GetScrollInfo(SB_HORZ, &si)) {
31088af74909SZhong Yang xPos = si.nTrackPos;
31098af74909SZhong Yang }
31108af74909SZhong Yang }
31118af74909SZhong Yang break;
31128af74909SZhong Yang }
31138af74909SZhong Yang HorizontalScrollTo(xPos);
31148af74909SZhong Yang }
31158af74909SZhong Yang
31168af74909SZhong Yang /**
31178af74909SZhong Yang * Redraw all of text area.
31188af74909SZhong Yang * This paint will not be abandoned.
31198af74909SZhong Yang */
FullPaint()31208af74909SZhong Yang void ScintillaWin::FullPaint() {
31218af74909SZhong Yang if ((technology == SC_TECHNOLOGY_DEFAULT) || (technology == SC_TECHNOLOGY_DIRECTWRITEDC)) {
31228af74909SZhong Yang HDC hdc = ::GetDC(MainHWND());
31238af74909SZhong Yang FullPaintDC(hdc);
31248af74909SZhong Yang ::ReleaseDC(MainHWND(), hdc);
31258af74909SZhong Yang } else {
31268af74909SZhong Yang FullPaintDC({});
31278af74909SZhong Yang }
31288af74909SZhong Yang }
31298af74909SZhong Yang
31308af74909SZhong Yang /**
31318af74909SZhong Yang * Redraw all of text area on the specified DC.
31328af74909SZhong Yang * This paint will not be abandoned.
31338af74909SZhong Yang */
FullPaintDC(HDC hdc)31348af74909SZhong Yang void ScintillaWin::FullPaintDC(HDC hdc) {
31358af74909SZhong Yang paintState = painting;
31368af74909SZhong Yang rcPaint = GetClientRectangle();
31378af74909SZhong Yang paintingAllText = true;
31388af74909SZhong Yang PaintDC(hdc);
31398af74909SZhong Yang paintState = notPainting;
31408af74909SZhong Yang }
31418af74909SZhong Yang
31428af74909SZhong Yang namespace {
31438af74909SZhong Yang
CompareDevCap(HDC hdc,HDC hOtherDC,int nIndex)31448af74909SZhong Yang bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) noexcept {
31458af74909SZhong Yang return ::GetDeviceCaps(hdc, nIndex) == ::GetDeviceCaps(hOtherDC, nIndex);
31468af74909SZhong Yang }
31478af74909SZhong Yang
31488af74909SZhong Yang }
31498af74909SZhong Yang
IsCompatibleDC(HDC hOtherDC)31508af74909SZhong Yang bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) noexcept {
31518af74909SZhong Yang HDC hdc = ::GetDC(MainHWND());
31528af74909SZhong Yang const bool isCompatible =
31538af74909SZhong Yang CompareDevCap(hdc, hOtherDC, TECHNOLOGY) &&
31548af74909SZhong Yang CompareDevCap(hdc, hOtherDC, LOGPIXELSY) &&
31558af74909SZhong Yang CompareDevCap(hdc, hOtherDC, LOGPIXELSX) &&
31568af74909SZhong Yang CompareDevCap(hdc, hOtherDC, BITSPIXEL) &&
31578af74909SZhong Yang CompareDevCap(hdc, hOtherDC, PLANES);
31588af74909SZhong Yang ::ReleaseDC(MainHWND(), hdc);
31598af74909SZhong Yang return isCompatible;
31608af74909SZhong Yang }
31618af74909SZhong Yang
EffectFromState(DWORD grfKeyState) const31628af74909SZhong Yang DWORD ScintillaWin::EffectFromState(DWORD grfKeyState) const noexcept {
31638af74909SZhong Yang // These are the Wordpad semantics.
31648af74909SZhong Yang DWORD dwEffect;
31658af74909SZhong Yang if (inDragDrop == ddDragging) // Internal defaults to move
31668af74909SZhong Yang dwEffect = DROPEFFECT_MOVE;
31678af74909SZhong Yang else
31688af74909SZhong Yang dwEffect = DROPEFFECT_COPY;
31698af74909SZhong Yang if (grfKeyState & MK_ALT)
31708af74909SZhong Yang dwEffect = DROPEFFECT_MOVE;
31718af74909SZhong Yang if (grfKeyState & MK_CONTROL)
31728af74909SZhong Yang dwEffect = DROPEFFECT_COPY;
31738af74909SZhong Yang return dwEffect;
31748af74909SZhong Yang }
31758af74909SZhong Yang
31768af74909SZhong Yang /// Implement IUnknown
QueryInterface(REFIID riid,PVOID * ppv)31778af74909SZhong Yang STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) {
31788af74909SZhong Yang *ppv = nullptr;
31798af74909SZhong Yang if (riid == IID_IUnknown)
31808af74909SZhong Yang *ppv = reinterpret_cast<IDropTarget *>(&dt);
31818af74909SZhong Yang if (riid == IID_IDropSource)
31828af74909SZhong Yang *ppv = reinterpret_cast<IDropSource *>(&ds);
31838af74909SZhong Yang if (riid == IID_IDropTarget)
31848af74909SZhong Yang *ppv = reinterpret_cast<IDropTarget *>(&dt);
31858af74909SZhong Yang if (riid == IID_IDataObject)
31868af74909SZhong Yang *ppv = reinterpret_cast<IDataObject *>(&dob);
31878af74909SZhong Yang if (!*ppv)
31888af74909SZhong Yang return E_NOINTERFACE;
31898af74909SZhong Yang return S_OK;
31908af74909SZhong Yang }
31918af74909SZhong Yang
STDMETHODIMP_(ULONG)31928af74909SZhong Yang STDMETHODIMP_(ULONG) ScintillaWin::AddRef() {
31938af74909SZhong Yang return 1;
31948af74909SZhong Yang }
31958af74909SZhong Yang
STDMETHODIMP_(ULONG)31968af74909SZhong Yang STDMETHODIMP_(ULONG) ScintillaWin::Release() {
31978af74909SZhong Yang return 1;
31988af74909SZhong Yang }
31998af74909SZhong Yang
32008af74909SZhong Yang /// Implement IDropTarget
DragEnter(LPDATAOBJECT pIDataSource,DWORD grfKeyState,POINTL,PDWORD pdwEffect)32018af74909SZhong Yang STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
32028af74909SZhong Yang POINTL, PDWORD pdwEffect) {
32038af74909SZhong Yang if (!pIDataSource )
32048af74909SZhong Yang return E_POINTER;
32058af74909SZhong Yang FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
32068af74909SZhong Yang const HRESULT hrHasUText = pIDataSource->QueryGetData(&fmtu);
32078af74909SZhong Yang hasOKText = (hrHasUText == S_OK);
32088af74909SZhong Yang if (hasOKText) {
32098af74909SZhong Yang *pdwEffect = EffectFromState(grfKeyState);
32108af74909SZhong Yang } else {
32118af74909SZhong Yang *pdwEffect = DROPEFFECT_NONE;
32128af74909SZhong Yang }
32138af74909SZhong Yang
32148af74909SZhong Yang return S_OK;
32158af74909SZhong Yang }
32168af74909SZhong Yang
DragOver(DWORD grfKeyState,POINTL pt,PDWORD pdwEffect)32178af74909SZhong Yang STDMETHODIMP ScintillaWin::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
32188af74909SZhong Yang try {
32198af74909SZhong Yang if (!hasOKText || pdoc->IsReadOnly()) {
32208af74909SZhong Yang *pdwEffect = DROPEFFECT_NONE;
32218af74909SZhong Yang return S_OK;
32228af74909SZhong Yang }
32238af74909SZhong Yang
32248af74909SZhong Yang *pdwEffect = EffectFromState(grfKeyState);
32258af74909SZhong Yang
32268af74909SZhong Yang // Update the cursor.
32278af74909SZhong Yang POINT rpt = {pt.x, pt.y};
32288af74909SZhong Yang ::ScreenToClient(MainHWND(), &rpt);
32298af74909SZhong Yang SetDragPosition(SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace()));
32308af74909SZhong Yang
32318af74909SZhong Yang return S_OK;
32328af74909SZhong Yang } catch (...) {
32338af74909SZhong Yang errorStatus = SC_STATUS_FAILURE;
32348af74909SZhong Yang }
32358af74909SZhong Yang return E_FAIL;
32368af74909SZhong Yang }
32378af74909SZhong Yang
DragLeave()32388af74909SZhong Yang STDMETHODIMP ScintillaWin::DragLeave() {
32398af74909SZhong Yang try {
32408af74909SZhong Yang SetDragPosition(SelectionPosition(Sci::invalidPosition));
32418af74909SZhong Yang return S_OK;
32428af74909SZhong Yang } catch (...) {
32438af74909SZhong Yang errorStatus = SC_STATUS_FAILURE;
32448af74909SZhong Yang }
32458af74909SZhong Yang return E_FAIL;
32468af74909SZhong Yang }
32478af74909SZhong Yang
Drop(LPDATAOBJECT pIDataSource,DWORD grfKeyState,POINTL pt,PDWORD pdwEffect)32488af74909SZhong Yang STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
32498af74909SZhong Yang POINTL pt, PDWORD pdwEffect) {
32508af74909SZhong Yang try {
32518af74909SZhong Yang *pdwEffect = EffectFromState(grfKeyState);
32528af74909SZhong Yang
32538af74909SZhong Yang if (!pIDataSource)
32548af74909SZhong Yang return E_POINTER;
32558af74909SZhong Yang
32568af74909SZhong Yang SetDragPosition(SelectionPosition(Sci::invalidPosition));
32578af74909SZhong Yang
32588af74909SZhong Yang std::string putf;
32598af74909SZhong Yang FORMATETC fmtu = {CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
32608af74909SZhong Yang STGMEDIUM medium{};
32618af74909SZhong Yang const HRESULT hr = pIDataSource->GetData(&fmtu, &medium);
32628af74909SZhong Yang if (!SUCCEEDED(hr)) {
32638af74909SZhong Yang return hr;
32648af74909SZhong Yang }
32658af74909SZhong Yang if (medium.hGlobal) {
32668af74909SZhong Yang GlobalMemory memUDrop(medium.hGlobal);
32678af74909SZhong Yang if (const wchar_t *uptr = static_cast<const wchar_t *>(memUDrop.ptr)) {
32688af74909SZhong Yang putf = EncodeWString(uptr);
32698af74909SZhong Yang }
32708af74909SZhong Yang memUDrop.Unlock();
32718af74909SZhong Yang }
32728af74909SZhong Yang
32738af74909SZhong Yang if (putf.empty()) {
32748af74909SZhong Yang return S_OK;
32758af74909SZhong Yang }
32768af74909SZhong Yang
32778af74909SZhong Yang FORMATETC fmtr = {cfColumnSelect, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
32788af74909SZhong Yang const bool isRectangular = S_OK == pIDataSource->QueryGetData(&fmtr);
32798af74909SZhong Yang
32808af74909SZhong Yang POINT rpt = {pt.x, pt.y};
32818af74909SZhong Yang ::ScreenToClient(MainHWND(), &rpt);
32828af74909SZhong Yang const SelectionPosition movePos = SPositionFromLocation(PointFromPOINT(rpt), false, false, UserVirtualSpace());
32838af74909SZhong Yang
32848af74909SZhong Yang DropAt(movePos, putf.c_str(), putf.size(), *pdwEffect == DROPEFFECT_MOVE, isRectangular);
32858af74909SZhong Yang
32868af74909SZhong Yang // Free data
32878af74909SZhong Yang ::ReleaseStgMedium(&medium);
32888af74909SZhong Yang
32898af74909SZhong Yang return S_OK;
32908af74909SZhong Yang } catch (...) {
32918af74909SZhong Yang errorStatus = SC_STATUS_FAILURE;
32928af74909SZhong Yang }
32938af74909SZhong Yang return E_FAIL;
32948af74909SZhong Yang }
32958af74909SZhong Yang
32968af74909SZhong Yang /// Implement important part of IDataObject
GetData(FORMATETC * pFEIn,STGMEDIUM * pSTM)32978af74909SZhong Yang STDMETHODIMP ScintillaWin::GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) {
32988af74909SZhong Yang if (!SupportedFormat(pFEIn)) {
32998af74909SZhong Yang //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
33008af74909SZhong Yang return DATA_E_FORMATETC;
33018af74909SZhong Yang }
33028af74909SZhong Yang
33038af74909SZhong Yang pSTM->tymed = TYMED_HGLOBAL;
33048af74909SZhong Yang //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
33058af74909SZhong Yang
33068af74909SZhong Yang GlobalMemory uniText;
33078af74909SZhong Yang CopyToGlobal(uniText, drag);
33088af74909SZhong Yang pSTM->hGlobal = uniText ? uniText.Unlock() : 0;
33098af74909SZhong Yang pSTM->pUnkForRelease = nullptr;
33108af74909SZhong Yang return S_OK;
33118af74909SZhong Yang }
33128af74909SZhong Yang
Prepare()33138af74909SZhong Yang void ScintillaWin::Prepare() noexcept {
33148af74909SZhong Yang Platform_Initialise(hInstance);
33158af74909SZhong Yang
33168af74909SZhong Yang // Register the CallTip class
33178af74909SZhong Yang WNDCLASSEX wndclassc{};
33188af74909SZhong Yang wndclassc.cbSize = sizeof(wndclassc);
33198af74909SZhong Yang wndclassc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
33208af74909SZhong Yang wndclassc.cbWndExtra = sizeof(ScintillaWin *);
33218af74909SZhong Yang wndclassc.hInstance = hInstance;
33228af74909SZhong Yang wndclassc.lpfnWndProc = ScintillaWin::CTWndProc;
33238af74909SZhong Yang wndclassc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
33248af74909SZhong Yang wndclassc.lpszClassName = callClassName;
33258af74909SZhong Yang
33268af74909SZhong Yang callClassAtom = ::RegisterClassEx(&wndclassc);
33278af74909SZhong Yang }
33288af74909SZhong Yang
Register(HINSTANCE hInstance_)33298af74909SZhong Yang bool ScintillaWin::Register(HINSTANCE hInstance_) noexcept {
33308af74909SZhong Yang
33318af74909SZhong Yang hInstance = hInstance_;
33328af74909SZhong Yang
33338af74909SZhong Yang // Register the Scintilla class
33348af74909SZhong Yang // Register Scintilla as a wide character window
33358af74909SZhong Yang WNDCLASSEXW wndclass {};
33368af74909SZhong Yang wndclass.cbSize = sizeof(wndclass);
33378af74909SZhong Yang wndclass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
33388af74909SZhong Yang wndclass.lpfnWndProc = ScintillaWin::SWndProc;
33398af74909SZhong Yang wndclass.cbWndExtra = sizeof(ScintillaWin *);
33408af74909SZhong Yang wndclass.hInstance = hInstance;
33418af74909SZhong Yang wndclass.lpszClassName = L"Scintilla";
33428af74909SZhong Yang scintillaClassAtom = ::RegisterClassExW(&wndclass);
33438af74909SZhong Yang const bool result = 0 != scintillaClassAtom;
33448af74909SZhong Yang
33458af74909SZhong Yang return result;
33468af74909SZhong Yang }
33478af74909SZhong Yang
Unregister()33488af74909SZhong Yang bool ScintillaWin::Unregister() noexcept {
33498af74909SZhong Yang bool result = true;
33508af74909SZhong Yang if (0 != scintillaClassAtom) {
33518af74909SZhong Yang if (::UnregisterClass(MAKEINTATOM(scintillaClassAtom), hInstance) == 0) {
33528af74909SZhong Yang result = false;
33538af74909SZhong Yang }
33548af74909SZhong Yang scintillaClassAtom = 0;
33558af74909SZhong Yang }
33568af74909SZhong Yang if (0 != callClassAtom) {
33578af74909SZhong Yang if (::UnregisterClass(MAKEINTATOM(callClassAtom), hInstance) == 0) {
33588af74909SZhong Yang result = false;
33598af74909SZhong Yang }
33608af74909SZhong Yang callClassAtom = 0;
33618af74909SZhong Yang }
33628af74909SZhong Yang return result;
33638af74909SZhong Yang }
33648af74909SZhong Yang
HasCaretSizeChanged() const33658af74909SZhong Yang bool ScintillaWin::HasCaretSizeChanged() const noexcept {
33668af74909SZhong Yang if (
33678af74909SZhong Yang ( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) )
33688af74909SZhong Yang || ((0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight))
33698af74909SZhong Yang ) {
33708af74909SZhong Yang return true;
33718af74909SZhong Yang }
33728af74909SZhong Yang return false;
33738af74909SZhong Yang }
33748af74909SZhong Yang
CreateSystemCaret()33758af74909SZhong Yang BOOL ScintillaWin::CreateSystemCaret() {
33768af74909SZhong Yang sysCaretWidth = vs.caretWidth;
33778af74909SZhong Yang if (0 == sysCaretWidth) {
33788af74909SZhong Yang sysCaretWidth = 1;
33798af74909SZhong Yang }
33808af74909SZhong Yang sysCaretHeight = vs.lineHeight;
33818af74909SZhong Yang const int bitmapSize = (((sysCaretWidth + 15) & ~15) >> 3) *
33828af74909SZhong Yang sysCaretHeight;
33838af74909SZhong Yang std::vector<BYTE> bits(bitmapSize);
33848af74909SZhong Yang sysCaretBitmap = ::CreateBitmap(sysCaretWidth, sysCaretHeight, 1,
33858af74909SZhong Yang 1, &bits[0]);
33868af74909SZhong Yang const BOOL retval = ::CreateCaret(
33878af74909SZhong Yang MainHWND(), sysCaretBitmap,
33888af74909SZhong Yang sysCaretWidth, sysCaretHeight);
33898af74909SZhong Yang if (technology == SC_TECHNOLOGY_DEFAULT) {
33908af74909SZhong Yang // System caret interferes with Direct2D drawing so only show it for GDI.
33918af74909SZhong Yang ::ShowCaret(MainHWND());
33928af74909SZhong Yang }
33938af74909SZhong Yang return retval;
33948af74909SZhong Yang }
33958af74909SZhong Yang
DestroySystemCaret()33968af74909SZhong Yang BOOL ScintillaWin::DestroySystemCaret() noexcept {
33978af74909SZhong Yang ::HideCaret(MainHWND());
33988af74909SZhong Yang const BOOL retval = ::DestroyCaret();
33998af74909SZhong Yang if (sysCaretBitmap) {
34008af74909SZhong Yang ::DeleteObject(sysCaretBitmap);
34018af74909SZhong Yang sysCaretBitmap = {};
34028af74909SZhong Yang }
34038af74909SZhong Yang return retval;
34048af74909SZhong Yang }
34058af74909SZhong Yang
CTWndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)34068af74909SZhong Yang LRESULT PASCAL ScintillaWin::CTWndProc(
34078af74909SZhong Yang HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
34088af74909SZhong Yang // Find C++ object associated with window.
34098af74909SZhong Yang ScintillaWin *sciThis = static_cast<ScintillaWin *>(PointerFromWindow(hWnd));
34108af74909SZhong Yang try {
34118af74909SZhong Yang // ctp will be zero if WM_CREATE not seen yet
34128af74909SZhong Yang if (sciThis == nullptr) {
34138af74909SZhong Yang if (iMessage == WM_CREATE) {
34148af74909SZhong Yang // Associate CallTip object with window
34158af74909SZhong Yang CREATESTRUCT *pCreate = static_cast<CREATESTRUCT *>(PtrFromSPtr(lParam));
34168af74909SZhong Yang SetWindowPointer(hWnd, pCreate->lpCreateParams);
34178af74909SZhong Yang return 0;
34188af74909SZhong Yang } else {
34198af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
34208af74909SZhong Yang }
34218af74909SZhong Yang } else {
34228af74909SZhong Yang if (iMessage == WM_NCDESTROY) {
34238af74909SZhong Yang SetWindowPointer(hWnd, nullptr);
34248af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
34258af74909SZhong Yang } else if (iMessage == WM_PAINT) {
34268af74909SZhong Yang PAINTSTRUCT ps;
34278af74909SZhong Yang ::BeginPaint(hWnd, &ps);
34288af74909SZhong Yang std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(sciThis->technology));
34298af74909SZhong Yang #if defined(USE_D2D)
34308af74909SZhong Yang ID2D1HwndRenderTarget *pCTRenderTarget = nullptr;
34318af74909SZhong Yang #endif
34328af74909SZhong Yang RECT rc;
34338af74909SZhong Yang GetClientRect(hWnd, &rc);
34348af74909SZhong Yang // Create a Direct2D render target.
34358af74909SZhong Yang if (sciThis->technology == SC_TECHNOLOGY_DEFAULT) {
34368af74909SZhong Yang surfaceWindow->Init(ps.hdc, hWnd);
34378af74909SZhong Yang } else {
34388af74909SZhong Yang #if defined(USE_D2D)
34398af74909SZhong Yang D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp;
34408af74909SZhong Yang dhrtp.hwnd = hWnd;
34418af74909SZhong Yang dhrtp.pixelSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
34428af74909SZhong Yang dhrtp.presentOptions = (sciThis->technology == SC_TECHNOLOGY_DIRECTWRITERETAIN) ?
34438af74909SZhong Yang D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE;
34448af74909SZhong Yang
34458af74909SZhong Yang D2D1_RENDER_TARGET_PROPERTIES drtp;
34468af74909SZhong Yang drtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
34478af74909SZhong Yang drtp.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
34488af74909SZhong Yang drtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
34498af74909SZhong Yang drtp.dpiX = 96.0;
34508af74909SZhong Yang drtp.dpiY = 96.0;
34518af74909SZhong Yang drtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
34528af74909SZhong Yang drtp.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
34538af74909SZhong Yang
34548af74909SZhong Yang if (!SUCCEEDED(pD2DFactory->CreateHwndRenderTarget(drtp, dhrtp, &pCTRenderTarget))) {
34558af74909SZhong Yang surfaceWindow->Release();
34568af74909SZhong Yang ::EndPaint(hWnd, &ps);
34578af74909SZhong Yang return 0;
34588af74909SZhong Yang }
34598af74909SZhong Yang // If above SUCCEEDED, then pCTRenderTarget not nullptr
34608af74909SZhong Yang assert(pCTRenderTarget);
34618af74909SZhong Yang if (pCTRenderTarget) {
34628af74909SZhong Yang surfaceWindow->Init(pCTRenderTarget, hWnd);
34638af74909SZhong Yang pCTRenderTarget->BeginDraw();
34648af74909SZhong Yang }
34658af74909SZhong Yang #endif
34668af74909SZhong Yang }
34678af74909SZhong Yang surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);
34688af74909SZhong Yang surfaceWindow->SetDBCSMode(sciThis->ct.codePage);
34698af74909SZhong Yang surfaceWindow->SetBidiR2L(sciThis->BidirectionalR2L());
34708af74909SZhong Yang sciThis->ct.PaintCT(surfaceWindow.get());
34718af74909SZhong Yang #if defined(USE_D2D)
34728af74909SZhong Yang if (pCTRenderTarget)
34738af74909SZhong Yang pCTRenderTarget->EndDraw();
34748af74909SZhong Yang #endif
34758af74909SZhong Yang surfaceWindow->Release();
34768af74909SZhong Yang #if defined(USE_D2D)
34778af74909SZhong Yang ReleaseUnknown(pCTRenderTarget);
34788af74909SZhong Yang #endif
34798af74909SZhong Yang ::EndPaint(hWnd, &ps);
34808af74909SZhong Yang return 0;
34818af74909SZhong Yang } else if ((iMessage == WM_NCLBUTTONDOWN) || (iMessage == WM_NCLBUTTONDBLCLK)) {
34828af74909SZhong Yang POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
34838af74909SZhong Yang ScreenToClient(hWnd, &pt);
34848af74909SZhong Yang sciThis->ct.MouseClick(PointFromPOINT(pt));
34858af74909SZhong Yang sciThis->CallTipClick();
34868af74909SZhong Yang return 0;
34878af74909SZhong Yang } else if (iMessage == WM_LBUTTONDOWN) {
34888af74909SZhong Yang // This does not fire due to the hit test code
34898af74909SZhong Yang sciThis->ct.MouseClick(PointFromLParam(lParam));
34908af74909SZhong Yang sciThis->CallTipClick();
34918af74909SZhong Yang return 0;
34928af74909SZhong Yang } else if (iMessage == WM_SETCURSOR) {
34938af74909SZhong Yang ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
34948af74909SZhong Yang return 0;
34958af74909SZhong Yang } else if (iMessage == WM_NCHITTEST) {
34968af74909SZhong Yang return HTCAPTION;
34978af74909SZhong Yang } else {
34988af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
34998af74909SZhong Yang }
35008af74909SZhong Yang }
35018af74909SZhong Yang } catch (...) {
35028af74909SZhong Yang sciThis->errorStatus = SC_STATUS_FAILURE;
35038af74909SZhong Yang }
35048af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
35058af74909SZhong Yang }
35068af74909SZhong Yang
DirectFunction(sptr_t ptr,UINT iMessage,uptr_t wParam,sptr_t lParam)35078af74909SZhong Yang sptr_t ScintillaWin::DirectFunction(
35088af74909SZhong Yang sptr_t ptr, UINT iMessage, uptr_t wParam, sptr_t lParam) {
35098af74909SZhong Yang PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(reinterpret_cast<ScintillaWin *>(ptr)->MainHWND(), nullptr));
35108af74909SZhong Yang return reinterpret_cast<ScintillaWin *>(ptr)->WndProc(iMessage, wParam, lParam);
35118af74909SZhong Yang }
35128af74909SZhong Yang
35138af74909SZhong Yang namespace Scintilla {
35148af74909SZhong Yang
DirectFunction(ScintillaWin * sci,UINT iMessage,uptr_t wParam,sptr_t lParam)35158af74909SZhong Yang sptr_t DirectFunction(
35168af74909SZhong Yang ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam) {
35178af74909SZhong Yang return sci->WndProc(iMessage, wParam, lParam);
35188af74909SZhong Yang }
35198af74909SZhong Yang
35208af74909SZhong Yang }
35218af74909SZhong Yang
SWndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)35228af74909SZhong Yang LRESULT PASCAL ScintillaWin::SWndProc(
35238af74909SZhong Yang HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
35248af74909SZhong Yang //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
35258af74909SZhong Yang
35268af74909SZhong Yang // Find C++ object associated with window.
35278af74909SZhong Yang ScintillaWin *sci = static_cast<ScintillaWin *>(PointerFromWindow(hWnd));
35288af74909SZhong Yang // sci will be zero if WM_CREATE not seen yet
35298af74909SZhong Yang if (sci == nullptr) {
35308af74909SZhong Yang try {
35318af74909SZhong Yang if (iMessage == WM_CREATE) {
35328af74909SZhong Yang static std::once_flag once;
35338af74909SZhong Yang std::call_once(once, Prepare);
35348af74909SZhong Yang // Create C++ object associated with window
35358af74909SZhong Yang sci = new ScintillaWin(hWnd);
35368af74909SZhong Yang SetWindowPointer(hWnd, sci);
35378af74909SZhong Yang return sci->WndProc(iMessage, wParam, lParam);
35388af74909SZhong Yang }
35398af74909SZhong Yang } catch (...) {
35408af74909SZhong Yang }
35418af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
35428af74909SZhong Yang } else {
35438af74909SZhong Yang if (iMessage == WM_NCDESTROY) {
35448af74909SZhong Yang try {
35458af74909SZhong Yang sci->Finalise();
35468af74909SZhong Yang delete sci;
35478af74909SZhong Yang } catch (...) {
35488af74909SZhong Yang }
35498af74909SZhong Yang SetWindowPointer(hWnd, nullptr);
35508af74909SZhong Yang return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
35518af74909SZhong Yang } else {
35528af74909SZhong Yang return sci->WndProc(iMessage, wParam, lParam);
35538af74909SZhong Yang }
35548af74909SZhong Yang }
35558af74909SZhong Yang }
35568af74909SZhong Yang
35578af74909SZhong Yang // This function is externally visible so it can be called from container when building statically.
35588af74909SZhong Yang // Must be called once only.
Scintilla_RegisterClasses(void * hInstance)35598af74909SZhong Yang int Scintilla_RegisterClasses(void *hInstance) {
35608af74909SZhong Yang const bool result = ScintillaWin::Register(static_cast<HINSTANCE>(hInstance));
35618af74909SZhong Yang return result;
35628af74909SZhong Yang }
35638af74909SZhong Yang
35648af74909SZhong Yang namespace Scintilla {
35658af74909SZhong Yang
ResourcesRelease(bool fromDllMain)35668af74909SZhong Yang int ResourcesRelease(bool fromDllMain) noexcept {
35678af74909SZhong Yang const bool result = ScintillaWin::Unregister();
35688af74909SZhong Yang Platform_Finalise(fromDllMain);
35698af74909SZhong Yang return result;
35708af74909SZhong Yang }
35718af74909SZhong Yang
35728af74909SZhong Yang }
35738af74909SZhong Yang
35748af74909SZhong Yang // This function is externally visible so it can be called from container when building statically.
Scintilla_ReleaseResources()35758af74909SZhong Yang int Scintilla_ReleaseResources() {
35768af74909SZhong Yang return Scintilla::ResourcesRelease(false);
35778af74909SZhong Yang }
3578