Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define WIN32_LEAN_AND_MEAN
- #define _CRT_SECURE_NO_WARNINGS
- #define _SCL_SECURE_NO_WARNINGS
- #include <Windows.h>
- #include <cstdio>
- #include <utility>
- #include <string>
- #include <vector>
- struct TextEdit
- {
- std::wstring buffer;
- int caret = 0;
- wchar_t const* Buffer()
- {
- return buffer.data();
- }
- int Length()
- {
- return buffer.size();
- }
- void NormalizeCaret()
- {
- if (caret < 0) {
- caret = 0;
- } else if (caret > Length()) {
- caret = buffer.size();
- }
- }
- void Insert(wchar_t ch)
- {
- NormalizeCaret();
- buffer.insert(caret, 1, ch);
- caret += 1;
- }
- void Insert(std::wstring const& str)
- {
- NormalizeCaret();
- if (!str.empty()) {
- buffer.insert(caret, str);
- caret += str.size();
- }
- }
- void EraseLeft()
- {
- NormalizeCaret();
- if (caret > 0) {
- buffer.erase(caret - 1, 1);
- caret -= 1;
- }
- }
- void EraseRight()
- {
- NormalizeCaret();
- if (caret < Length()) {
- buffer.erase(caret);
- }
- }
- void MoveLeft()
- {
- if (caret > 0) {
- caret -= 1;
- }
- }
- void MoveRight()
- {
- if (caret < Length()) {
- caret += 1;
- }
- }
- void MoveHome()
- {
- caret = 0;
- }
- void MoveEnd()
- {
- caret = buffer.size();
- }
- };
- enum class CompositionAttribute
- {
- Input,
- Selected,
- Converted,
- };
- struct CompositionClause
- {
- std::wstring text;
- CompositionAttribute attr;
- };
- struct CompositionState
- {
- std::vector<CompositionClause> clauses;
- int cursorclause;
- int cursorpos;
- std::wstring UpdateAndGetResult(HWND hwnd)
- {
- cursorclause = 0;
- cursorpos = 0;
- HIMC imc = ImmGetContext(hwnd);
- std::wstring result;
- result.resize(ImmGetCompositionStringW(imc, GCS_RESULTSTR, nullptr, 0) / 2);
- if (!result.empty()) {
- ImmGetCompositionStringW(imc, GCS_RESULTSTR, (wchar_t*)result.data(), result.size() * 2);
- }
- std::vector<wchar_t> str;
- std::vector<BYTE> attr;
- std::vector<DWORD> pos;
- str.resize(ImmGetCompositionStringW(imc, GCS_COMPSTR, nullptr, 0) / 2);
- if (str.empty()) {
- clauses.clear();
- }
- ImmGetCompositionStringW(imc, GCS_COMPSTR, str.data(), str.size() * 2);
- attr.resize(ImmGetCompositionStringW(imc, GCS_COMPATTR, nullptr, 0));
- ImmGetCompositionStringW(imc, GCS_COMPATTR, attr.data(), attr.size());
- pos.resize(ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, nullptr, 0) / 4);
- ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, pos.data(), pos.size() * 4);
- if (pos.size() < 1) {
- return result;
- }
- clauses.resize(pos.size() - 1);
- for (int i = 0; i < (int)clauses.size(); ++i) {
- int begin = pos[i];
- int end = pos[i + 1];
- if (begin >= 0 && end <= (int)str.size() && begin < end) {
- clauses[i].text.resize(end - begin);
- std::copy(str.data() + begin, str.data() + end, (wchar_t*)clauses[i].text.data());
- } else {
- clauses[i].text.clear();
- }
- clauses[i].attr = CompositionAttribute::Input;
- if (begin >= 0 && begin < (int)attr.size()) {
- switch (attr[begin]) {
- case ATTR_CONVERTED:
- clauses[i].attr = CompositionAttribute::Converted;
- break;
- case ATTR_TARGET_CONVERTED:
- clauses[i].attr = CompositionAttribute::Selected;
- break;
- }
- }
- }
- int cursor = ImmGetCompositionStringW(imc, GCS_CURSORPOS, nullptr, 0) & 0xffff;
- for (int i = 0; i < (int)clauses.size(); ++i) {
- int length = clauses[i].text.size();
- if (cursor >= 0 && cursor <= length) {
- cursorclause = i;
- cursorpos = cursor;
- break;
- } else {
- cursor -= length;
- }
- }
- ImmReleaseContext(hwnd, imc);
- return result;
- }
- };
- TextEdit Current;
- CompositionState CurrentComposition;
- HPEN CaretPen;
- HPEN InputAttrPen;
- HPEN SelectedAttrPen;
- HPEN ConvertedAttrPen;
- void WindowPaint(HWND hwnd)
- {
- RECT clientrect;
- GetClientRect(hwnd, &clientrect);
- SIZE wndsize = { clientrect.right - clientrect.left, clientrect.bottom - clientrect.top };
- PAINTSTRUCT ps;
- HDC wnddc = BeginPaint(hwnd, &ps);
- HBITMAP bitmap = CreateCompatibleBitmap(wnddc, wndsize.cx, wndsize.cy);
- HDC dc = CreateCompatibleDC(wnddc);
- SelectObject(dc, bitmap);
- RECT wndrect = { 0, 0, wndsize.cx, wndsize.cy };
- HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(dc, &wndrect, brush);
- TEXTMETRICW textmetric;
- GetTextMetricsW(dc, &textmetric);
- int currentx = textmetric.tmHeight;
- int currenty = textmetric.tmHeight;
- SIZE textsize;
- if (CurrentComposition.clauses.empty()) {
- TextOutW(dc, currentx, currenty, Current.Buffer(), Current.Length());
- GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
- SelectObject(dc, CaretPen);
- MoveToEx(dc, currentx + textsize.cx, currenty, nullptr);
- LineTo(dc, currentx + textsize.cx, currenty + textmetric.tmHeight);
- } else {
- TextOutW(dc, currentx, currenty, Current.Buffer(), Current.caret);
- GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
- currentx += textsize.cx;
- for (int i = 0; i < (int)CurrentComposition.clauses.size(); ++i) {
- CompositionClause const& clause = CurrentComposition.clauses[i];
- TextOutW(dc, currentx, currenty, clause.text.data(), clause.text.size());
- if (CurrentComposition.cursorclause == i) {
- GetTextExtentPointW(dc, clause.text.data(), CurrentComposition.cursorpos, &textsize);
- SelectObject(dc, CaretPen);
- MoveToEx(dc, currentx + textsize.cx, currenty, nullptr);
- LineTo(dc, currentx + textsize.cx, currenty + textmetric.tmHeight);
- }
- GetTextExtentPointW(dc, clause.text.data(), clause.text.size(), &textsize);
- switch (clause.attr) {
- case CompositionAttribute::Input:
- SelectObject(dc, InputAttrPen);
- break;
- case CompositionAttribute::Selected:
- SelectObject(dc, SelectedAttrPen);
- break;
- case CompositionAttribute::Converted:
- SelectObject(dc, ConvertedAttrPen);
- break;
- }
- MoveToEx(dc, currentx + 1, currenty + textmetric.tmHeight + 1, nullptr);
- LineTo(dc, currentx + textsize.cx - 1, currenty + textmetric.tmHeight + 1);
- currentx += textsize.cx;
- }
- TextOutW(dc, currentx, currenty, Current.Buffer() + Current.caret, Current.Length() - Current.caret);
- }
- BitBlt(wnddc, 0, 0, wndsize.cx, wndsize.cy, dc, 0, 0, SRCCOPY);
- DeleteObject(brush);
- DeleteDC(dc);
- DeleteObject(bitmap);
- EndPaint(hwnd, &ps);
- }
- void ImrQueryCharPosition(HWND hwnd, IMECHARPOSITION* chpos)
- {
- int charpos = chpos->dwCharPos;
- wprintf(L"WM_IME_REQUEST IMR_QUERYCHARPOSITION %i\n", charpos);
- CurrentComposition.UpdateAndGetResult(hwnd);
- RECT clientrect;
- GetClientRect(hwnd, &clientrect);
- HDC dc = GetDC(hwnd);
- TEXTMETRICW textmetric;
- GetTextMetricsW(dc, &textmetric);
- int currentx = textmetric.tmHeight;
- int currenty = textmetric.tmHeight;
- SIZE textsize;
- GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
- currentx += textsize.cx;
- for (int i = 0; i < (int)CurrentComposition.clauses.size(); ++i) {
- CompositionClause const& clause = CurrentComposition.clauses[i];
- if (charpos < (int)clause.text.size()) {
- GetTextExtentPointW(dc, clause.text.data(), charpos, &textsize);
- currentx += textsize.cx;
- break;
- } else {
- GetTextExtentPointW(dc, clause.text.data(), clause.text.size(), &textsize);
- currentx += textsize.cx;
- charpos -= (int)clause.text.size();
- }
- }
- POINT pt = { currentx, currenty + 5 };
- ClientToScreen(hwnd, &pt);
- chpos->pt = pt;
- chpos->cLineHeight = textmetric.tmHeight;
- POINT client1 = { 0, 0 };
- POINT client2 = { clientrect.right - clientrect.left, currenty + textmetric.tmHeight };
- ClientToScreen(hwnd, &client1);
- ClientToScreen(hwnd, &client2);
- chpos->rcDocument = { client1.x, client1.y, client2.x, client2.y };
- ReleaseDC(hwnd, dc);
- }
- LRESULT CALLBACK WindowProc(
- HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- switch (uMsg) {
- case WM_CREATE:
- CaretPen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
- InputAttrPen = CreatePen(PS_DOT, 0, RGB(0, 0, 0));
- SelectedAttrPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
- ConvertedAttrPen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
- return 0;
- case WM_DESTROY:
- DeleteObject(CaretPen);
- DeleteObject(InputAttrPen);
- DeleteObject(SelectedAttrPen);
- DeleteObject(ConvertedAttrPen);
- PostQuitMessage(0);
- return 0;
- case WM_CHAR:
- wprintf(L"WM_CHAR %#4x'%lc' %3i\n", wParam, (wchar_t)wParam, (lParam >> 16) & 0xff);
- if (wParam == 8) {
- Current.EraseLeft();
- } else if (wParam >= 32) {
- Current.Insert(wParam);
- }
- InvalidateRect(hwnd, nullptr, false);
- return 0;
- case WM_KEYDOWN:
- wprintf(L"WM_KEYDOWN %4i %3i\n", wParam, (lParam >> 16) & 0xff);
- if (wParam == VK_LEFT) {
- Current.MoveLeft();
- InvalidateRect(hwnd, nullptr, false);
- } else if (wParam == VK_RIGHT) {
- Current.MoveRight();
- InvalidateRect(hwnd, nullptr, false);
- } else if (wParam == VK_HOME || wParam == VK_PRIOR || wParam == VK_UP) {
- Current.MoveHome();
- InvalidateRect(hwnd, nullptr, false);
- } else if (wParam == VK_END || wParam == VK_NEXT || wParam == VK_DOWN) {
- Current.MoveEnd();
- InvalidateRect(hwnd, nullptr, false);
- } else if (wParam == VK_DELETE) {
- Current.EraseRight();
- InvalidateRect(hwnd, nullptr, false);
- }
- return 0;
- case WM_KEYUP:
- return 0;
- case WM_IME_SETCONTEXT:
- wprintf(L"WM_IME_SETCONTEXT %i\n", wParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case WM_IME_STARTCOMPOSITION:
- wprintf(L"WM_IME_STARTCOMPOSITION\n");
- Current.Insert(CurrentComposition.UpdateAndGetResult(hwnd));
- InvalidateRect(hwnd, nullptr, false);
- return 0;
- case WM_IME_COMPOSITION:
- wprintf(L"WM_IME_COMPOSITION\n");
- Current.Insert(CurrentComposition.UpdateAndGetResult(hwnd));
- InvalidateRect(hwnd, nullptr, false);
- return 0;
- case WM_IME_ENDCOMPOSITION:
- wprintf(L"WM_IME_ENDCOMPOSITION\n");
- CurrentComposition.clauses.clear();
- InvalidateRect(hwnd, nullptr, false);
- return 0;
- case WM_IME_SELECT:
- wprintf(L"WM_IME_SELECT %i\n", wParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case WM_IME_REQUEST:
- switch (wParam) {
- case IMR_CANDIDATEWINDOW:
- wprintf(L"WM_IME_REQUEST IMR_CANDIDATEWINDOW\n");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case IMR_COMPOSITIONFONT:
- wprintf(L"WM_IME_REQUEST IMR_COMPOSITIONFONT\n");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case IMR_COMPOSITIONWINDOW:
- wprintf(L"WM_IME_REQUEST IMR_COMPOSITIONWINDOW\n");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case IMR_CONFIRMRECONVERTSTRING:
- wprintf(L"WM_IME_REQUEST IMR_CONFIRMRECONVERTSTRING\n");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- case IMR_DOCUMENTFEED:
- wprintf(L"WM_IME_REQUEST IMR_DOCUMENTFEED\n");
- return 0;
- case IMR_QUERYCHARPOSITION:
- ImrQueryCharPosition(hwnd, (IMECHARPOSITION*)lParam);
- return true;
- case IMR_RECONVERTSTRING:
- wprintf(L"WM_IME_REQUEST IMR_RECONVERTSTRING\n");
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- default:
- wprintf(L"WM_IME_REQUEST %i\n", wParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- case WM_IME_NOTIFY:
- switch (wParam) {
- case IMN_CHANGECANDIDATE:
- wprintf(L"WM_IME_NOTIFY IMN_CHANGECANDIDATE\n");
- return 0;
- case IMN_CLOSECANDIDATE:
- wprintf(L"WM_IME_NOTIFY IMN_CLOSECANDIDATE\n");
- return 0;
- case IMN_CLOSESTATUSWINDOW:
- wprintf(L"WM_IME_NOTIFY IMN_CLOSESTATUSWINDOW\n");
- return 0;
- case IMN_GUIDELINE:
- wprintf(L"WM_IME_NOTIFY IMN_GUIDELINE\n");
- return 0;
- case IMN_OPENCANDIDATE:
- wprintf(L"WM_IME_NOTIFY IMN_OPENCANDIDATE\n");
- return 0;
- case IMN_OPENSTATUSWINDOW:
- wprintf(L"WM_IME_NOTIFY IMN_OPENSTATUSWINDOW\n");
- return 0;
- case IMN_SETCANDIDATEPOS:
- wprintf(L"WM_IME_NOTIFY IMN_SETCANDIDATEPOS\n");
- return 0;
- case IMN_SETCOMPOSITIONFONT:
- wprintf(L"WM_IME_NOTIFY IMN_SETCOMPOSITIONFONT\n");
- return 0;
- case IMN_SETCOMPOSITIONWINDOW:
- wprintf(L"WM_IME_NOTIFY IMN_SETCOMPOSITIONWINDOW\n");
- return 0;
- case IMN_SETCONVERSIONMODE:
- wprintf(L"WM_IME_NOTIFY IMN_SETCONVERSIONMODE\n");
- return 0;
- case IMN_SETOPENSTATUS:
- wprintf(L"WM_IME_NOTIFY IMN_SETOPENSTATUS\n");
- return 0;
- case IMN_SETSENTENCEMODE:
- wprintf(L"WM_IME_NOTIFY IMN_SETSENTENCEMODE\n");
- return 0;
- case IMN_SETSTATUSWINDOWPOS:
- wprintf(L"WM_IME_NOTIFY IMN_SETSTATUSWINDOWPOS\n");
- return 0;
- default:
- wprintf(L"WM_IME_NOTIFY %i\n", wParam);
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- case WM_PAINT:
- WindowPaint(hwnd);
- return 0;
- default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
- }
- }
- int CALLBACK WinMain(
- HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- AllocConsole();
- freopen("CONOUT$", "w", stdout);
- const DWORD WindowStyle = WS_OVERLAPPEDWINDOW;
- WNDCLASSW wndclass;
- wndclass.style = CS_VREDRAW | CS_HREDRAW;
- wndclass.lpfnWndProc = &WindowProc;
- wndclass.cbClsExtra = 8;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInstance;
- wndclass.hIcon = LoadIcon(0, IDI_APPLICATION);
- wndclass.hCursor = LoadCursor(0, IDC_ARROW);
- wndclass.hbrBackground = 0;
- wndclass.lpszMenuName = 0;
- wndclass.lpszClassName = L"MyWindowClass";
- ATOM wndclassatom = RegisterClassW(&wndclass);
- RECT WindowRect = { 0, 0, 800, 600 };
- AdjustWindowRect(
- &WindowRect, WindowStyle, false);
- HWND hwnd = CreateWindowW(
- (LPCWSTR)wndclassatom,
- L"window",
- WindowStyle,
- 20,
- 20,
- WindowRect.right - WindowRect.left,
- WindowRect.bottom - WindowRect.top,
- 0,
- 0,
- hInstance,
- 0);
- ShowWindow(hwnd, SW_SHOW);
- UpdateWindow(hwnd);
- MSG message = { 0, 0, 0, 0 };
- while (GetMessageW(&message, nullptr, 0, 0)) {
- TranslateMessage(&message);
- DispatchMessageW(&message);
- }
- return 0;
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement