Advertisement
Delfigamer

microsoft ime kk done

Apr 17th, 2020
593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.00 KB | None | 0 0
  1. #define WIN32_LEAN_AND_MEAN
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #define _SCL_SECURE_NO_WARNINGS
  4.  
  5. #include <Windows.h>
  6. #include <cstdio>
  7. #include <utility>
  8. #include <string>
  9. #include <vector>
  10.  
  11. struct TextEdit
  12. {
  13.     std::wstring buffer;
  14.     int caret = 0;
  15.  
  16.     wchar_t const* Buffer()
  17.     {
  18.         return buffer.data();
  19.     }
  20.  
  21.     int Length()
  22.     {
  23.         return buffer.size();
  24.     }
  25.  
  26.     void NormalizeCaret()
  27.     {
  28.         if (caret < 0) {
  29.             caret = 0;
  30.         } else if (caret > Length()) {
  31.             caret = buffer.size();
  32.         }
  33.     }
  34.  
  35.     void Insert(wchar_t ch)
  36.     {
  37.         NormalizeCaret();
  38.         buffer.insert(caret, 1, ch);
  39.         caret += 1;
  40.     }
  41.  
  42.     void Insert(std::wstring const& str)
  43.     {
  44.         NormalizeCaret();
  45.         if (!str.empty()) {
  46.             buffer.insert(caret, str);
  47.             caret += str.size();
  48.         }
  49.     }
  50.  
  51.     void EraseLeft()
  52.     {
  53.         NormalizeCaret();
  54.         if (caret > 0) {
  55.             buffer.erase(caret - 1, 1);
  56.             caret -= 1;
  57.         }
  58.     }
  59.  
  60.     void EraseRight()
  61.     {
  62.         NormalizeCaret();
  63.         if (caret < Length()) {
  64.             buffer.erase(caret);
  65.         }
  66.     }
  67.  
  68.     void MoveLeft()
  69.     {
  70.         if (caret > 0) {
  71.             caret -= 1;
  72.         }
  73.     }
  74.  
  75.     void MoveRight()
  76.     {
  77.         if (caret < Length()) {
  78.             caret += 1;
  79.         }
  80.     }
  81.  
  82.     void MoveHome()
  83.     {
  84.         caret = 0;
  85.     }
  86.  
  87.     void MoveEnd()
  88.     {
  89.         caret = buffer.size();
  90.     }
  91. };
  92.  
  93. enum class CompositionAttribute
  94. {
  95.     Input,
  96.     Selected,
  97.     Converted,
  98. };
  99.  
  100. struct CompositionClause
  101. {
  102.     std::wstring text;
  103.     CompositionAttribute attr;
  104. };
  105.  
  106. struct CompositionState
  107. {
  108.     std::vector<CompositionClause> clauses;
  109.     int cursorclause;
  110.     int cursorpos;
  111.  
  112.     std::wstring UpdateAndGetResult(HWND hwnd)
  113.     {
  114.         cursorclause = 0;
  115.         cursorpos = 0;
  116.         HIMC imc = ImmGetContext(hwnd);
  117.         std::wstring result;
  118.         result.resize(ImmGetCompositionStringW(imc, GCS_RESULTSTR, nullptr, 0) / 2);
  119.         if (!result.empty()) {
  120.             ImmGetCompositionStringW(imc, GCS_RESULTSTR, (wchar_t*)result.data(), result.size() * 2);
  121.         }
  122.         std::vector<wchar_t> str;
  123.         std::vector<BYTE> attr;
  124.         std::vector<DWORD> pos;
  125.         str.resize(ImmGetCompositionStringW(imc, GCS_COMPSTR, nullptr, 0) / 2);
  126.         if (str.empty()) {
  127.             clauses.clear();
  128.         }
  129.         ImmGetCompositionStringW(imc, GCS_COMPSTR, str.data(), str.size() * 2);
  130.         attr.resize(ImmGetCompositionStringW(imc, GCS_COMPATTR, nullptr, 0));
  131.         ImmGetCompositionStringW(imc, GCS_COMPATTR, attr.data(), attr.size());
  132.         pos.resize(ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, nullptr, 0) / 4);
  133.         ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, pos.data(), pos.size() * 4);
  134.         if (pos.size() < 1) {
  135.             return result;
  136.         }
  137.         clauses.resize(pos.size() - 1);
  138.         for (int i = 0; i < (int)clauses.size(); ++i) {
  139.             int begin = pos[i];
  140.             int end = pos[i + 1];
  141.             if (begin >= 0 && end <= (int)str.size() && begin < end) {
  142.                 clauses[i].text.resize(end - begin);
  143.                 std::copy(str.data() + begin, str.data() + end, (wchar_t*)clauses[i].text.data());
  144.             } else {
  145.                 clauses[i].text.clear();
  146.             }
  147.             clauses[i].attr = CompositionAttribute::Input;
  148.             if (begin >= 0 && begin < (int)attr.size()) {
  149.                 switch (attr[begin]) {
  150.                 case ATTR_CONVERTED:
  151.                     clauses[i].attr = CompositionAttribute::Converted;
  152.                     break;
  153.                 case ATTR_TARGET_CONVERTED:
  154.                     clauses[i].attr = CompositionAttribute::Selected;
  155.                     break;
  156.                 }
  157.             }
  158.         }
  159.         int cursor = ImmGetCompositionStringW(imc, GCS_CURSORPOS, nullptr, 0) & 0xffff;
  160.         for (int i = 0; i < (int)clauses.size(); ++i) {
  161.             int length = clauses[i].text.size();
  162.             if (cursor >= 0 && cursor <= length) {
  163.                 cursorclause = i;
  164.                 cursorpos = cursor;
  165.                 break;
  166.             } else {
  167.                 cursor -= length;
  168.             }
  169.         }
  170.         ImmReleaseContext(hwnd, imc);
  171.         return result;
  172.     }
  173. };
  174.  
  175. TextEdit Current;
  176. CompositionState CurrentComposition;
  177. HPEN CaretPen;
  178. HPEN InputAttrPen;
  179. HPEN SelectedAttrPen;
  180. HPEN ConvertedAttrPen;
  181.  
  182. void WindowPaint(HWND hwnd)
  183. {
  184.     RECT clientrect;
  185.     GetClientRect(hwnd, &clientrect);
  186.     SIZE wndsize = { clientrect.right - clientrect.left, clientrect.bottom - clientrect.top };
  187.  
  188.     PAINTSTRUCT ps;
  189.     HDC wnddc = BeginPaint(hwnd, &ps);
  190.     HBITMAP bitmap = CreateCompatibleBitmap(wnddc, wndsize.cx, wndsize.cy);
  191.     HDC dc = CreateCompatibleDC(wnddc);
  192.     SelectObject(dc, bitmap);
  193.  
  194.     RECT wndrect = { 0, 0, wndsize.cx, wndsize.cy };
  195.     HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));
  196.     FillRect(dc, &wndrect, brush);
  197.  
  198.     TEXTMETRICW textmetric;
  199.     GetTextMetricsW(dc, &textmetric);
  200.  
  201.     int currentx = textmetric.tmHeight;
  202.     int currenty = textmetric.tmHeight;
  203.     SIZE textsize;
  204.  
  205.     if (CurrentComposition.clauses.empty()) {
  206.         TextOutW(dc, currentx, currenty, Current.Buffer(), Current.Length());
  207.  
  208.         GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
  209.         SelectObject(dc, CaretPen);
  210.         MoveToEx(dc, currentx + textsize.cx, currenty, nullptr);
  211.         LineTo(dc, currentx + textsize.cx, currenty + textmetric.tmHeight);
  212.     } else {
  213.         TextOutW(dc, currentx, currenty, Current.Buffer(), Current.caret);
  214.  
  215.         GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
  216.         currentx += textsize.cx;
  217.  
  218.         for (int i = 0; i < (int)CurrentComposition.clauses.size(); ++i) {
  219.             CompositionClause const& clause = CurrentComposition.clauses[i];
  220.             TextOutW(dc, currentx, currenty, clause.text.data(), clause.text.size());
  221.  
  222.             if (CurrentComposition.cursorclause == i) {
  223.                 GetTextExtentPointW(dc, clause.text.data(), CurrentComposition.cursorpos, &textsize);
  224.                 SelectObject(dc, CaretPen);
  225.                 MoveToEx(dc, currentx + textsize.cx, currenty, nullptr);
  226.                 LineTo(dc, currentx + textsize.cx, currenty + textmetric.tmHeight);
  227.             }
  228.  
  229.             GetTextExtentPointW(dc, clause.text.data(), clause.text.size(), &textsize);
  230.  
  231.             switch (clause.attr) {
  232.             case CompositionAttribute::Input:
  233.                 SelectObject(dc, InputAttrPen);
  234.                 break;
  235.             case CompositionAttribute::Selected:
  236.                 SelectObject(dc, SelectedAttrPen);
  237.                 break;
  238.             case CompositionAttribute::Converted:
  239.                 SelectObject(dc, ConvertedAttrPen);
  240.                 break;
  241.             }
  242.             MoveToEx(dc, currentx + 1, currenty + textmetric.tmHeight + 1, nullptr);
  243.             LineTo(dc, currentx + textsize.cx - 1, currenty + textmetric.tmHeight + 1);
  244.  
  245.             currentx += textsize.cx;
  246.         }
  247.  
  248.         TextOutW(dc, currentx, currenty, Current.Buffer() + Current.caret, Current.Length() - Current.caret);
  249.     }
  250.  
  251.     BitBlt(wnddc, 0, 0, wndsize.cx, wndsize.cy, dc, 0, 0, SRCCOPY);
  252.     DeleteObject(brush);
  253.     DeleteDC(dc);
  254.     DeleteObject(bitmap);
  255.     EndPaint(hwnd, &ps);
  256. }
  257.  
  258. void ImrQueryCharPosition(HWND hwnd, IMECHARPOSITION* chpos)
  259. {
  260.     int charpos = chpos->dwCharPos;
  261.     wprintf(L"WM_IME_REQUEST IMR_QUERYCHARPOSITION %i\n", charpos);
  262.     CurrentComposition.UpdateAndGetResult(hwnd);
  263.     RECT clientrect;
  264.     GetClientRect(hwnd, &clientrect);
  265.     HDC dc = GetDC(hwnd);
  266.     TEXTMETRICW textmetric;
  267.     GetTextMetricsW(dc, &textmetric);
  268.     int currentx = textmetric.tmHeight;
  269.     int currenty = textmetric.tmHeight;
  270.     SIZE textsize;
  271.     GetTextExtentPointW(dc, Current.Buffer(), Current.caret, &textsize);
  272.     currentx += textsize.cx;
  273.     for (int i = 0; i < (int)CurrentComposition.clauses.size(); ++i) {
  274.         CompositionClause const& clause = CurrentComposition.clauses[i];
  275.         if (charpos < (int)clause.text.size()) {
  276.             GetTextExtentPointW(dc, clause.text.data(), charpos, &textsize);
  277.             currentx += textsize.cx;
  278.             break;
  279.         } else {
  280.             GetTextExtentPointW(dc, clause.text.data(), clause.text.size(), &textsize);
  281.             currentx += textsize.cx;
  282.             charpos -= (int)clause.text.size();
  283.         }
  284.     }
  285.     POINT pt = { currentx, currenty + 5 };
  286.     ClientToScreen(hwnd, &pt);
  287.     chpos->pt = pt;
  288.     chpos->cLineHeight = textmetric.tmHeight;
  289.     POINT client1 = { 0, 0 };
  290.     POINT client2 = { clientrect.right - clientrect.left, currenty + textmetric.tmHeight };
  291.     ClientToScreen(hwnd, &client1);
  292.     ClientToScreen(hwnd, &client2);
  293.     chpos->rcDocument = { client1.x, client1.y, client2.x, client2.y };
  294.     ReleaseDC(hwnd, dc);
  295. }
  296.  
  297. LRESULT CALLBACK WindowProc(
  298.     HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  299. {
  300.     switch (uMsg) {
  301.     case WM_CREATE:
  302.         CaretPen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  303.         InputAttrPen = CreatePen(PS_DOT, 0, RGB(0, 0, 0));
  304.         SelectedAttrPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
  305.         ConvertedAttrPen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  306.         return 0;
  307.     case WM_DESTROY:
  308.         DeleteObject(CaretPen);
  309.         DeleteObject(InputAttrPen);
  310.         DeleteObject(SelectedAttrPen);
  311.         DeleteObject(ConvertedAttrPen);
  312.         PostQuitMessage(0);
  313.         return 0;
  314.     case WM_CHAR:
  315.         wprintf(L"WM_CHAR %#4x'%lc' %3i\n", wParam, (wchar_t)wParam, (lParam >> 16) & 0xff);
  316.         if (wParam == 8) {
  317.             Current.EraseLeft();
  318.         } else if (wParam >= 32) {
  319.             Current.Insert(wParam);
  320.         }
  321.         InvalidateRect(hwnd, nullptr, false);
  322.         return 0;
  323.     case WM_KEYDOWN:
  324.         wprintf(L"WM_KEYDOWN    %4i %3i\n", wParam, (lParam >> 16) & 0xff);
  325.         if (wParam == VK_LEFT) {
  326.             Current.MoveLeft();
  327.             InvalidateRect(hwnd, nullptr, false);
  328.         } else if (wParam == VK_RIGHT) {
  329.             Current.MoveRight();
  330.             InvalidateRect(hwnd, nullptr, false);
  331.         } else if (wParam == VK_HOME || wParam == VK_PRIOR || wParam == VK_UP) {
  332.             Current.MoveHome();
  333.             InvalidateRect(hwnd, nullptr, false);
  334.         } else if (wParam == VK_END || wParam == VK_NEXT || wParam == VK_DOWN) {
  335.             Current.MoveEnd();
  336.             InvalidateRect(hwnd, nullptr, false);
  337.         } else if (wParam == VK_DELETE) {
  338.             Current.EraseRight();
  339.             InvalidateRect(hwnd, nullptr, false);
  340.         }
  341.         return 0;
  342.     case WM_KEYUP:
  343.         return 0;
  344.     case WM_IME_SETCONTEXT:
  345.         wprintf(L"WM_IME_SETCONTEXT %i\n", wParam);
  346.         return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  347.     case WM_IME_STARTCOMPOSITION:
  348.         wprintf(L"WM_IME_STARTCOMPOSITION\n");
  349.         Current.Insert(CurrentComposition.UpdateAndGetResult(hwnd));
  350.         InvalidateRect(hwnd, nullptr, false);
  351.         return 0;
  352.     case WM_IME_COMPOSITION:
  353.         wprintf(L"WM_IME_COMPOSITION\n");
  354.         Current.Insert(CurrentComposition.UpdateAndGetResult(hwnd));
  355.         InvalidateRect(hwnd, nullptr, false);
  356.         return 0;
  357.     case WM_IME_ENDCOMPOSITION:
  358.         wprintf(L"WM_IME_ENDCOMPOSITION\n");
  359.         CurrentComposition.clauses.clear();
  360.         InvalidateRect(hwnd, nullptr, false);
  361.         return 0;
  362.     case WM_IME_SELECT:
  363.         wprintf(L"WM_IME_SELECT %i\n", wParam);
  364.         return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  365.     case WM_IME_REQUEST:
  366.         switch (wParam) {
  367.         case IMR_CANDIDATEWINDOW:
  368.             wprintf(L"WM_IME_REQUEST IMR_CANDIDATEWINDOW\n");
  369.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  370.         case IMR_COMPOSITIONFONT:
  371.             wprintf(L"WM_IME_REQUEST IMR_COMPOSITIONFONT\n");
  372.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  373.         case IMR_COMPOSITIONWINDOW:
  374.             wprintf(L"WM_IME_REQUEST IMR_COMPOSITIONWINDOW\n");
  375.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  376.         case IMR_CONFIRMRECONVERTSTRING:
  377.             wprintf(L"WM_IME_REQUEST IMR_CONFIRMRECONVERTSTRING\n");
  378.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  379.         case IMR_DOCUMENTFEED:
  380.             wprintf(L"WM_IME_REQUEST IMR_DOCUMENTFEED\n");
  381.             return 0;
  382.         case IMR_QUERYCHARPOSITION:
  383.             ImrQueryCharPosition(hwnd, (IMECHARPOSITION*)lParam);
  384.             return true;
  385.         case IMR_RECONVERTSTRING:
  386.             wprintf(L"WM_IME_REQUEST IMR_RECONVERTSTRING\n");
  387.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  388.         default:
  389.             wprintf(L"WM_IME_REQUEST %i\n", wParam);
  390.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  391.         }
  392.     case WM_IME_NOTIFY:
  393.         switch (wParam) {
  394.         case IMN_CHANGECANDIDATE:
  395.             wprintf(L"WM_IME_NOTIFY IMN_CHANGECANDIDATE\n");
  396.             return 0;
  397.         case IMN_CLOSECANDIDATE:
  398.             wprintf(L"WM_IME_NOTIFY IMN_CLOSECANDIDATE\n");
  399.             return 0;
  400.         case IMN_CLOSESTATUSWINDOW:
  401.             wprintf(L"WM_IME_NOTIFY IMN_CLOSESTATUSWINDOW\n");
  402.             return 0;
  403.         case IMN_GUIDELINE:
  404.             wprintf(L"WM_IME_NOTIFY IMN_GUIDELINE\n");
  405.             return 0;
  406.         case IMN_OPENCANDIDATE:
  407.             wprintf(L"WM_IME_NOTIFY IMN_OPENCANDIDATE\n");
  408.             return 0;
  409.         case IMN_OPENSTATUSWINDOW:
  410.             wprintf(L"WM_IME_NOTIFY IMN_OPENSTATUSWINDOW\n");
  411.             return 0;
  412.         case IMN_SETCANDIDATEPOS:
  413.             wprintf(L"WM_IME_NOTIFY IMN_SETCANDIDATEPOS\n");
  414.             return 0;
  415.         case IMN_SETCOMPOSITIONFONT:
  416.             wprintf(L"WM_IME_NOTIFY IMN_SETCOMPOSITIONFONT\n");
  417.             return 0;
  418.         case IMN_SETCOMPOSITIONWINDOW:
  419.             wprintf(L"WM_IME_NOTIFY IMN_SETCOMPOSITIONWINDOW\n");
  420.             return 0;
  421.         case IMN_SETCONVERSIONMODE:
  422.             wprintf(L"WM_IME_NOTIFY IMN_SETCONVERSIONMODE\n");
  423.             return 0;
  424.         case IMN_SETOPENSTATUS:
  425.             wprintf(L"WM_IME_NOTIFY IMN_SETOPENSTATUS\n");
  426.             return 0;
  427.         case IMN_SETSENTENCEMODE:
  428.             wprintf(L"WM_IME_NOTIFY IMN_SETSENTENCEMODE\n");
  429.             return 0;
  430.         case IMN_SETSTATUSWINDOWPOS:
  431.             wprintf(L"WM_IME_NOTIFY IMN_SETSTATUSWINDOWPOS\n");
  432.             return 0;
  433.         default:
  434.             wprintf(L"WM_IME_NOTIFY %i\n", wParam);
  435.             return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  436.         }
  437.     case WM_PAINT:
  438.         WindowPaint(hwnd);
  439.         return 0;
  440.     default:
  441.         return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  442.     }
  443. }
  444.  
  445. int CALLBACK WinMain(
  446.     HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  447. {
  448.     AllocConsole();
  449.     freopen("CONOUT$", "w", stdout);
  450.     const DWORD WindowStyle = WS_OVERLAPPEDWINDOW;
  451.     WNDCLASSW wndclass;
  452.     wndclass.style = CS_VREDRAW | CS_HREDRAW;
  453.     wndclass.lpfnWndProc = &WindowProc;
  454.     wndclass.cbClsExtra = 8;
  455.     wndclass.cbWndExtra = 0;
  456.     wndclass.hInstance = hInstance;
  457.     wndclass.hIcon = LoadIcon(0, IDI_APPLICATION);
  458.     wndclass.hCursor = LoadCursor(0, IDC_ARROW);
  459.     wndclass.hbrBackground = 0;
  460.     wndclass.lpszMenuName = 0;
  461.     wndclass.lpszClassName = L"MyWindowClass";
  462.     ATOM wndclassatom = RegisterClassW(&wndclass);
  463.     RECT WindowRect = { 0, 0, 800, 600 };
  464.     AdjustWindowRect(
  465.         &WindowRect, WindowStyle, false);
  466.     HWND hwnd = CreateWindowW(
  467.         (LPCWSTR)wndclassatom,
  468.         L"window",
  469.         WindowStyle,
  470.         20,
  471.         20,
  472.         WindowRect.right - WindowRect.left,
  473.         WindowRect.bottom - WindowRect.top,
  474.         0,
  475.         0,
  476.         hInstance,
  477.         0);
  478.     ShowWindow(hwnd, SW_SHOW);
  479.     UpdateWindow(hwnd);
  480.     MSG message = { 0, 0, 0, 0 };
  481.     while (GetMessageW(&message, nullptr, 0, 0)) {
  482.         TranslateMessage(&message);
  483.         DispatchMessageW(&message);
  484.     }
  485.     return 0;
  486. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement