📄 editor.c
字号:
ME_CommitUndo(editor);
if (bRepaint)
ME_UpdateRepaint(editor);
return 0;
}
case EM_GETCHARFORMAT:
{
CHARFORMAT2W tmp, *dst = (CHARFORMAT2W *)lParam;
if (dst->cbSize != sizeof(CHARFORMATA) &&
dst->cbSize != sizeof(CHARFORMATW) &&
dst->cbSize != sizeof(CHARFORMAT2A) &&
dst->cbSize != sizeof(CHARFORMAT2W))
return 0;
tmp.cbSize = sizeof(tmp);
if (!wParam)
ME_GetDefaultCharFormat(editor, &tmp);
else
ME_GetSelectionCharFormat(editor, &tmp);
ME_CopyToCFAny(dst, &tmp);
return tmp.dwMask;
}
case EM_SETPARAFORMAT:
ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
ME_UpdateRepaint(editor);
ME_CommitUndo(editor);
return 0;
case EM_GETPARAFORMAT:
ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
return 0;
case EM_GETFIRSTVISIBLELINE:
{
ME_DisplayItem *p = editor->pBuffer->pFirst;
int y = editor->nScrollPosY;
int ypara = 0;
int count = 0;
int ystart, yend;
while(p) {
p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
if (p->type == diTextEnd)
break;
if (p->type == diParagraph) {
ypara = p->member.para.nYPos;
continue;
}
ystart = ypara + p->member.row.nYPos;
yend = ystart + p->member.row.nHeight;
if (y < yend) {
break;
}
count++;
}
return count;
}
case EM_LINESCROLL:
{
int nPos = editor->nScrollPosY, nEnd= editor->nTotalLength - editor->sizeWindow.cy;
nPos += 8 * lParam; /* FIXME follow the original */
if (nPos>=nEnd)
nPos = nEnd;
if (nPos<0)
nPos = 0;
if (nPos != editor->nScrollPosY) {
int dy = editor->nScrollPosY - nPos;
editor->nScrollPosY = nPos;
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
if (editor->bRedraw)
{
ScrollWindow(hWnd, 0, dy, NULL, NULL);
UpdateWindow(hWnd);
}
}
return TRUE; /* Should return false if a single line richedit control */
}
case WM_CLEAR:
{
int from, to;
ME_GetSelection(editor, &from, &to);
ME_InternalDeleteText(editor, from, to-from);
ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
return 0;
}
case EM_REPLACESEL:
{
int from, to;
ME_Style *style;
LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
size_t len = lstrlenW(wszText);
TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText));
ME_GetSelection(editor, &from, &to);
style = ME_GetSelectionInsertStyle(editor);
ME_InternalDeleteText(editor, from, to-from);
ME_InsertTextFromCursor(editor, 0, wszText, len, style);
ME_ReleaseStyle(style);
ME_EndToUnicode(hWnd, wszText);
/* drop temporary style if line end */
/* FIXME question: does abc\n mean: put abc, clear temp style, put \n? (would require a change) */
if (len>0 && wszText[len-1] == '\n')
ME_ClearTempStyle(editor);
ME_CommitUndo(editor);
if (!wParam)
ME_EmptyUndoStack(editor);
ME_UpdateRepaint(editor);
return 0;
}
case WM_SETTEXT:
{
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
if (lParam)
{
LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
TRACE("WM_SETTEXT lParam==%lx\n",lParam);
TRACE("WM_SETTEXT - %s\n", debugstr_w(wszText)); /* debugstr_w() */
if (lstrlenW(wszText) > 0)
{
/* uses default style! */
ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
}
ME_EndToUnicode(hWnd, wszText);
}
else
TRACE("WM_SETTEXT - NULL\n");
ME_CommitUndo(editor);
ME_EmptyUndoStack(editor);
ME_SetSelection(editor, 0, 0);
ME_UpdateRepaint(editor);
return 0;
}
case EM_CANPASTE:
{
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
if (IsClipboardFormatAvailable(nRTFFormat))
return TRUE;
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
return TRUE;
return FALSE;
}
case WM_PASTE:
{
DWORD dwFormat = 0;
EDITSTREAM es;
ME_GlobalDestStruct gds;
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
UINT cf = 0;
if (IsClipboardFormatAvailable(nRTFFormat))
cf = nRTFFormat, dwFormat = SF_RTF;
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE;
else
return 0;
if (!OpenClipboard(hWnd))
return 0;
gds.hData = GetClipboardData(cf);
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es);
CloseClipboard();
return 0;
}
case WM_CUT:
case WM_COPY:
{
int from, to, pars;
WCHAR *data;
HANDLE hData;
EDITSTREAM es;
ME_GlobalDestStruct gds;
if (!OpenClipboard(hWnd))
return 0;
EmptyClipboard();
ME_GetSelection(editor, &from, &to);
pars = ME_CountParagraphsBetween(editor, from, to);
hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR)*(to-from+pars+1));
data = (WCHAR *)GlobalLock(hData);
ME_GetTextW(editor, data, from, to-from, TRUE);
GlobalUnlock(hData);
gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0);
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = ME_AppendToHGLOBAL;
SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es);
GlobalReAlloc(gds.hData, gds.nLength+1, 0);
SetClipboardData(CF_UNICODETEXT, hData);
SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData);
CloseClipboard();
if (msg == WM_CUT)
{
ME_InternalDeleteText(editor, from, to-from);
ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
}
return 0;
}
case WM_GETTEXTLENGTH:
return ME_GetTextLength(editor);
case EM_GETTEXTLENGTHEX:
return ME_GetTextLengthEx(editor, (GETTEXTLENGTHEX *)wParam);
case WM_GETTEXT:
{
TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
tr.chrg.cpMin = 0;
tr.chrg.cpMax = wParam-1;
tr.lpstrText = (WCHAR *)lParam;
return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
}
case EM_GETTEXTEX:
{
GETTEXTEX *ex = (GETTEXTEX*)wParam;
int nStart, nCount;
if (ex->flags & ~(GT_SELECTION | GT_USECRLF))
FIXME("GETTEXTEX flags 0x%08lx not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF));
if (ex->flags & GT_SELECTION)
{
ME_GetSelection(editor, &nStart, &nCount);
nCount -= nStart;
nCount = min(nCount, ex->cb - 1);
}
else
{
nStart = 0;
nCount = ex->cb - 1;
}
if (ex->codepage == 1200 || IsWindowUnicode(hWnd))
{
nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1);
return ME_GetTextW(editor, (LPWSTR)lParam, nStart, nCount, ex->flags & GT_USECRLF);
}
else
{
/* potentially each char may be a CR, why calculate the exact value with O(N) when
we can just take a bigger buffer? :) */
int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1;
LPWSTR buffer = HeapAlloc(GetProcessHeap(), 0, (crlfmul*nCount + 1) * sizeof(WCHAR));
DWORD buflen = ex->cb;
LRESULT rc;
DWORD flags = 0;
buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF);
rc = WideCharToMultiByte(ex->codepage, flags, buffer, buflen, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar);
HeapFree(GetProcessHeap(),0,buffer);
return rc;
}
}
case EM_GETSELTEXT:
{
int from, to;
TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
ME_GetSelection(editor, &from, &to);
tr.chrg.cpMin = from;
tr.chrg.cpMax = to;
tr.lpstrText = (WCHAR *)lParam;
return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
}
case EM_GETTEXTRANGE:
{
TEXTRANGEW *rng = (TEXTRANGEW *)lParam;
TRACE("EM_GETTEXTRANGE min=%ld max=%ld unicode=%d emul1.0=%d length=%d\n",
rng->chrg.cpMin, rng->chrg.cpMax, IsWindowUnicode(hWnd),
editor->bEmulateVersion10, ME_GetTextLength(editor));
if (IsWindowUnicode(hWnd))
return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10);
else
{
int nLen = rng->chrg.cpMax-rng->chrg.cpMin;
WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, editor->bEmulateVersion10);
/* FIXME this is a potential security hole (buffer overrun)
if you know more about wchar->mbyte conversion please explain
*/
WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)rng->lpstrText, nLen+1, NULL, NULL);
FREE_OBJ(p);
return nChars;
}
}
case EM_GETLINECOUNT:
{
ME_DisplayItem *item = editor->pBuffer->pFirst->next;
int nRows = 0;
while (item != editor->pBuffer->pLast)
{
assert(item->type == diParagraph);
nRows += item->member.para.nRows;
item = item->member.para.next_para;
}
TRACE("EM_GETLINECOUNT: nRows==%d\n", nRows);
return max(1, nRows);
}
case EM_LINEFROMCHAR:
{
if (wParam == -1)
return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor, 1));
else
return ME_RowNumberFromCharOfs(editor, wParam);
}
case EM_EXLINEFROMCHAR:
{
return ME_RowNumberFromCharOfs(editor, lParam);
}
case EM_LINEINDEX:
{
ME_DisplayItem *item, *para;
int nCharOfs;
if (wParam == -1)
item = ME_FindItemBack(editor->pCursors[0].pRun, diStartRow);
else
item = ME_FindRowWithNumber(editor, wParam);
if (!item)
return -1;
para = ME_GetParagraph(item);
item = ME_FindItemFwd(item, diRun);
nCharOfs = para->member.para.nCharOfs + item->member.run.nCharOfs;
TRACE("EM_LINEINDEX: nCharOfs==%d\n", nCharOfs);
return nCharOfs;
}
case EM_LINELENGTH:
{
ME_DisplayItem *item, *item_end;
int nChars = 0, nThisLineOfs = 0, nNextLineOfs = 0;
if (wParam > ME_GetTextLength(editor))
return 0;
if (wParam == -1)
{
FIXME("EM_LINELENGTH: returning number of unselected characters on lines with selection unsupported.\n");
return 0;
}
item = ME_FindItemAtOffset(editor, diRun, wParam, NULL);
item = ME_RowStart(item);
nThisLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item, diRun), 0);
item_end = ME_FindItemFwd(item, diStartRow);
if (item_end)
nNextLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item_end, diRun), 0);
else
nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs
- (editor->bEmulateVersion10?2:1);
nChars = nNextLineOfs - nThisLineOfs;
TRACE("EM_LINELENGTH(%d)==%d\n",wParam, nChars);
return nChars;
}
case EM_FINDTEXT:
{
FINDTEXTA *ft = (FINDTEXTA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0);
WCHAR *tmp;
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, tmp, nChars);
return ME_FindText(editor, wParam, &ft->chrg, tmp, NULL);
}
case EM_FINDTEXTEX:
{
FINDTEXTEXA *ex = (FINDTEXTEXA *)lParam;
int nChars = MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, NULL, 0);
WCHAR *tmp;
if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, tmp, nChars);
return ME_FindText(editor, wParam, &ex->chrg, tmp, &ex->chrgText);
}
case EM_FINDTEXTW:
{
FINDTEXTW *ft = (FINDTEXTW *)lParam;
return ME_FindText(editor, wParam, &ft->chrg, ft->lpstrText, NULL);
}
case EM_FINDTEXTEXW:
{
FINDTEXTEXW *ex = (FINDTEXTEXW *)lParam;
return ME_FindText(editor, wParam, &ex->chrg, ex->lpstrText, &ex->chrgText);
}
case EM_GETZOOM:
if (!wParam || !lParam)
return FALSE;
*(int *)wParam = editor->nZoomNumerator;
*(int *)lParam = editor->nZoomDenominator;
return TRUE;
case EM_SETZOOM:
return ME_SetZoom(editor, wParam, lParam);
case EM_CHARFROMPOS:
return ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y);
case EM_POSFROMCHAR:
{
ME_DisplayItem *pRun;
int nCharOfs, nOffset, nLength;
POINTL pt = {0,0};
nCharOfs = wParam;
/* detect which API version we're dealing with */
if (wParam >= 0x40000)
nCharOfs = lParam;
nLength = ME_GetTextLength(editor);
if (nCharOfs < nLength) {
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
assert(pRun->type == diRun);
pt.y = pRun->member.run.pt.y;
pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset);
pt.y += ME_GetParagraph(pRun)->member.para.nYPos;
} else {
pt.x = 0;
pt.y = editor->pBuffer->pLast->member.para.nYPos;
}
if (wParam >= 0x40000) {
*(POINTL *)wParam = pt;
}
return MAKELONG( pt.x, pt.y );
}
case WM_CREATE:
ME_CommitUndo(editor);
ME_WrapMarkedParagraphs(editor);
ME_MoveCaret(editor);
return 0;
case WM_DESTROY:
ME_DestroyEditor(editor);
SetWindowLongW(hWnd, 0, 0);
return 0;
case WM_LBUTTONDOWN:
SetFocus(hWnd);
ME_LButtonDown(editor, (short)LOWORD(lParam), (short)HIWORD(lParam));
SetCapture(hWnd);
break;
case WM_MOUSEMOVE:
if (GetCapture() == hWnd)
ME_MouseMove(editor, (short)LOWORD(lParam), (short)HIWORD(lParam));
break;
case WM_LBUTTONUP:
if (GetCapture() == hWnd)
ReleaseCapture();
break;
case WM_PAINT:
if (editor->bRedraw)
{
HDC hDC;
PAINTSTRUCT ps;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -