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