📄 scintillawin.cxx
字号:
// Restore debug output state
Platform::ShowAssertionPopUps(assertsPopup);
//Platform::DebugPrintf("Paint took %g\n", et.Duration());
return 0l;
}
sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
#ifdef __DMC__
// Digital Mars compiler does not include Imm library
return 0;
#else
if (lParam & GCS_RESULTSTR) {
HIMC hIMC = ::ImmGetContext(MainHWND());
if (hIMC) {
const int maxLenInputIME = 200;
wchar_t wcs[maxLenInputIME];
LONG bytes = ::ImmGetCompositionStringW(hIMC,
GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
int wides = bytes / 2;
if (IsUnicodeMode()) {
char utfval[maxLenInputIME * 3];
unsigned int len = UTF8Length(wcs, wides);
UTF8FromUCS2(wcs, wides, utfval, len);
utfval[len] = '\0';
AddCharUTF(utfval, len);
} else {
char dbcsval[maxLenInputIME * 2];
int size = ::WideCharToMultiByte(InputCodePage(),
0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
for (int i=0; i<size; i++) {
AddChar(dbcsval[i]);
}
}
// Set new position after converted
Point pos = LocationFromPosition(currentPos);
COMPOSITIONFORM CompForm;
CompForm.dwStyle = CFS_POINT;
CompForm.ptCurrentPos.x = pos.x;
CompForm.ptCurrentPos.y = pos.y;
::ImmSetCompositionWindow(hIMC, &CompForm);
::ImmReleaseContext(MainHWND(), hIMC);
}
return 0;
}
return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
#endif
}
// Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
static unsigned int SciMessageFromEM(unsigned int iMessage) {
switch (iMessage) {
case EM_CANPASTE: return SCI_CANPASTE;
case EM_CANUNDO: return SCI_CANUNDO;
case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER;
case EM_FINDTEXTEX: return SCI_FINDTEXT;
case EM_FORMATRANGE: return SCI_FORMATRANGE;
case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE;
case EM_GETLINECOUNT: return SCI_GETLINECOUNT;
case EM_GETSELTEXT: return SCI_GETSELTEXT;
case EM_GETTEXTRANGE: return SCI_GETTEXTRANGE;
case EM_HIDESELECTION: return SCI_HIDESELECTION;
case EM_LINEINDEX: return SCI_POSITIONFROMLINE;
case EM_LINESCROLL: return SCI_LINESCROLL;
case EM_REPLACESEL: return SCI_REPLACESEL;
case EM_SCROLLCARET: return SCI_SCROLLCARET;
case EM_SETREADONLY: return SCI_SETREADONLY;
case WM_CLEAR: return SCI_CLEAR;
case WM_COPY: return SCI_COPY;
case WM_CUT: return SCI_CUT;
case WM_GETTEXT: return SCI_GETTEXT;
case WM_SETTEXT: return SCI_SETTEXT;
case WM_GETTEXTLENGTH: return SCI_GETTEXTLENGTH;
case WM_PASTE: return SCI_PASTE;
case WM_UNDO: return SCI_UNDO;
}
return iMessage;
}
sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
//Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
iMessage = SciMessageFromEM(iMessage);
switch (iMessage) {
case WM_CREATE:
ctrlID = ::GetDlgCtrlID(reinterpret_cast<HWND>(wMain.GetID()));
// Get Intellimouse scroll line parameters
GetIntelliMouseParameters();
::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget *>(&dt));
break;
case WM_COMMAND:
#ifdef TOTAL_CONTROL
Command(LoWord(wParam));
#endif
break;
case WM_PAINT:
return WndPaint(wParam);
case WM_PRINTCLIENT: {
HDC hdc = reinterpret_cast<HDC>(wParam);
if (!IsCompatibleDC(hdc)) {
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
FullPaintDC(hdc);
}
break;
case WM_VSCROLL:
ScrollMessage(wParam);
break;
case WM_HSCROLL:
HorizontalScrollMessage(wParam);
break;
case WM_SIZE: {
//Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
ChangeSize();
}
break;
case WM_MOUSEWHEEL:
// Don't handle datazoom.
// (A good idea for datazoom would be to "fold" or "unfold" details.
// i.e. if datazoomed out only class structures are visible, when datazooming in the control
// structures appear, then eventually the individual statements...)
if (wParam & MK_SHIFT) {
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
// Either SCROLL or ZOOM. We handle the wheel steppings calculation
wheelDelta -= static_cast<short>(HiWord(wParam));
if (abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) {
int linesToScroll = linesPerScroll;
if (linesPerScroll == WHEEL_PAGESCROLL)
linesToScroll = LinesOnScreen() - 1;
if (linesToScroll == 0) {
linesToScroll = 1;
}
linesToScroll *= (wheelDelta / WHEEL_DELTA);
if (wheelDelta >= 0)
wheelDelta = wheelDelta % WHEEL_DELTA;
else
wheelDelta = - (-wheelDelta % WHEEL_DELTA);
if (wParam & MK_CONTROL) {
// Zoom! We play with the font sizes in the styles.
// Number of steps/line is ignored, we just care if sizing up or down
if (linesToScroll < 0) {
KeyCommand(SCI_ZOOMIN);
} else {
KeyCommand(SCI_ZOOMOUT);
}
} else {
// Scroll
ScrollTo(topLine + linesToScroll);
}
}
return 0;
case WM_TIMER:
if (wParam == standardTimerID && timer.ticking) {
Tick();
} else if (wParam == idleTimerID && idler.state) {
SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);
} else {
return 1;
}
break;
case SC_WIN_IDLE:
// wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
if (idler.state) {
if (lParam || (WAIT_TIMEOUT==MsgWaitForMultipleObjects(0,0,0,0, QS_INPUT|QS_HOTKEY))) {
if (Idle()) {
// User input was given priority above, but all events do get a turn. Other
// messages, notifications, etc. will get interleaved with the idle messages.
// However, some things like WM_PAINT are a lower priority, and will not fire
// when there's a message posted. So, several times a second, we stop and let
// the low priority events have a turn (after which the timer will fire again).
DWORD dwCurrent = GetTickCount();
DWORD dwStart = wParam ? wParam : dwCurrent;
if (dwCurrent >= dwStart && dwCurrent > 200 && dwCurrent - 200 < dwStart)
PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0);
} else {
SetIdle(false);
}
}
}
break;
case WM_GETMINMAXINFO:
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_LBUTTONDOWN: {
#ifndef __DMC__
// Digital Mars compiler does not include Imm library
// For IME, set the composition string as the result string.
HIMC hIMC = ::ImmGetContext(MainHWND());
::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
::ImmReleaseContext(MainHWND(), hIMC);
#endif
//
//Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
// Platform::IsKeyDown(VK_SHIFT),
// Platform::IsKeyDown(VK_CONTROL),
// Platform::IsKeyDown(VK_MENU));
ButtonDown(Point::FromLong(lParam), ::GetMessageTime(),
(wParam & MK_SHIFT) != 0,
(wParam & MK_CONTROL) != 0,
Platform::IsKeyDown(VK_MENU));
::SetFocus(MainHWND());
}
break;
case WM_MOUSEMOVE:
ButtonMove(Point::FromLong(lParam));
break;
case WM_LBUTTONUP:
ButtonUp(Point::FromLong(lParam),
::GetMessageTime(),
(wParam & MK_CONTROL) != 0);
break;
case WM_SETCURSOR:
if (LoWord(lParam) == HTCLIENT) {
if (inDragDrop) {
DisplayCursor(Window::cursorUp);
} else {
// Display regular (drag) cursor over selection
POINT pt;
::GetCursorPos(&pt);
::ScreenToClient(MainHWND(), &pt);
if (PointInSelMargin(Point(pt.x, pt.y))) {
DisplayCursor(Window::cursorReverseArrow);
} else if (PointInSelection(Point(pt.x, pt.y)) && !SelectionEmpty()) {
DisplayCursor(Window::cursorArrow);
} else if (PointIsHotspot(Point(pt.x, pt.y))) {
DisplayCursor(Window::cursorHand);
} else {
DisplayCursor(Window::cursorText);
}
}
return TRUE;
} else {
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
case WM_CHAR:
if (!iscntrl(wParam&0xff) || !lastKeyDownConsumed) {
if (IsUnicodeMode()) {
// For a wide character version of the window:
//char utfval[4];
//wchar_t wcs[2] = {wParam, 0};
//unsigned int len = UTF8Length(wcs, 1);
//UTF8FromUCS2(wcs, 1, utfval, len);
//AddCharUTF(utfval, len);
AddCharBytes('\0', LOBYTE(wParam));
} else {
AddChar(LOBYTE(wParam));
}
}
return 0;
case WM_UNICHAR:
if (wParam == UNICODE_NOCHAR) {
return 1;
} else if (lastKeyDownConsumed) {
return 1;
} else {
if (IsUnicodeMode()) {
char utfval[4];
wchar_t wcs[2] = {wParam, 0};
unsigned int len = UTF8Length(wcs, 1);
UTF8FromUCS2(wcs, 1, utfval, len);
AddCharUTF(utfval, len);
return 1;
} else {
return 0;
}
}
case WM_SYSKEYDOWN:
case WM_KEYDOWN: {
//Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
lastKeyDownConsumed = false;
int ret = KeyDown(KeyTranslate(wParam),
Platform::IsKeyDown(VK_SHIFT),
Platform::IsKeyDown(VK_CONTROL),
Platform::IsKeyDown(VK_MENU),
&lastKeyDownConsumed);
if (!ret && !lastKeyDownConsumed) {
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
break;
}
case WM_IME_KEYDOWN:
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_KEYUP:
//Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_SETTINGCHANGE:
//Platform::DebugPrintf("Setting Changed\n");
InvalidateStyleData();
// Get Intellimouse scroll line parameters
GetIntelliMouseParameters();
break;
case WM_GETDLGCODE:
return DLGC_HASSETSEL | DLGC_WANTALLKEYS;
case WM_KILLFOCUS: {
HWND wOther = reinterpret_cast<HWND>(wParam);
HWND wThis = MainHWND();
HWND wCT = reinterpret_cast<HWND>(ct.wCallTip.GetID());
if (!wParam ||
!(::IsChild(wThis,wOther) || (wOther == wCT))) {
SetFocusState(false);
DestroySystemCaret();
}
}
//RealizeWindowPalette(true);
break;
case WM_SETFOCUS:
SetFocusState(true);
RealizeWindowPalette(false);
DestroySystemCaret();
CreateSystemCaret();
break;
case WM_SYSCOLORCHANGE:
//Platform::DebugPrintf("Setting Changed\n");
InvalidateStyleData();
break;
case WM_PALETTECHANGED:
if (wParam != reinterpret_cast<uptr_t>(MainHWND())) {
//Platform::DebugPrintf("** Palette Changed\n");
RealizeWindowPalette(true);
}
break;
case WM_QUERYNEWPALETTE:
//Platform::DebugPrintf("** Query palette\n");
RealizeWindowPalette(false);
break;
case WM_IME_STARTCOMPOSITION: // dbcs
ImeStartComposition();
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_IME_ENDCOMPOSITION: // dbcs
ImeEndComposition();
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_IME_COMPOSITION:
return HandleComposition(wParam, lParam);
case WM_IME_CHAR: {
AddCharBytes(HIBYTE(wParam), LOBYTE(wParam));
return 0;
}
case WM_CONTEXTMENU:
#ifdef TOTAL_CONTROL
if (displayPopupMenu) {
Point pt = Point::FromLong(lParam);
if ((pt.x == -1) && (pt.y == -1)) {
// Caused by keyboard so display menu near caret
pt = LocationFromPosition(currentPos);
POINT spt = {pt.x, pt.y};
::ClientToScreen(MainHWND(), &spt);
pt = Point(spt.x, spt.y);
}
ContextMenu(pt);
return 0;
}
#endif
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_INPUTLANGCHANGE:
//::SetThreadLocale(LOWORD(lParam));
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_INPUTLANGCHANGEREQUEST:
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_ERASEBKGND:
return 1; // Avoid any background erasure as whole window painted.
case WM_CAPTURECHANGED:
capturedMouse = false;
return 0;
// These are not handled in Scintilla and its faster to dispatch them here.
// Also moves time out to here so profile doesn't count lots of empty message calls.
case WM_MOVE:
case WM_MOUSEACTIVATE:
case WM_NCHITTEST:
case WM_NCCALCSIZE:
case WM_NCPAINT:
case WM_NCMOUSEMOVE:
case WM_NCLBUTTONDOWN:
case WM_IME_SETCONTEXT:
case WM_IME_NOTIFY:
case WM_SYSCOMMAND:
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case EM_LINEFROMCHAR:
if (static_cast<int>(wParam) < 0) {
wParam = SelectionStart();
}
return pdoc->LineFromPosition(wParam);
case EM_EXLINEFROMCHAR:
return pdoc->LineFromPosition(lParam);
case EM_GETSEL:
if (wParam) {
*reinterpret_cast<int *>(wParam) = SelectionStart();
}
if (lParam) {
*reinterpret_cast<int *>(lParam) = SelectionEnd();
}
return MAKELONG(SelectionStart(), SelectionEnd());
case EM_EXGETSEL: {
if (lParam == 0) {
return 0;
}
CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);
pCR->cpMin = SelectionStart();
pCR->cpMax = SelectionEnd();
}
break;
case EM_SETSEL: {
int nStart = static_cast<int>(wParam);
int nEnd = static_cast<int>(lParam);
if (nStart == 0 && nEnd == -1) {
nEnd = pdoc->Length();
}
if (nStart == -1) {
nStart = nEnd; // Remove selection
}
if (nStart > nEnd) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -