aboutsummaryrefslogtreecommitdiffhomepage
path: root/win32/ScintillaWin.cxx
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2015-02-22 08:57:07 +1100
committerNeil <nyamatongwe@gmail.com>2015-02-22 08:57:07 +1100
commite3dcaa477741dba922e3daf270ff2ecb42b5311c (patch)
treee09f3e1c465e3f63cf1231a3a64e684d6ba2eb79 /win32/ScintillaWin.cxx
parente06bdec7a8e31dbef56c7953083151b888f2f89c (diff)
downloadscintilla-mirror-e3dcaa477741dba922e3daf270ff2ecb42b5311c.tar.gz
Implement VK_HANJA for Korean on Windows.
Diffstat (limited to 'win32/ScintillaWin.cxx')
-rw-r--r--win32/ScintillaWin.cxx135
1 files changed, 133 insertions, 2 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index 100361a1b..f4e43bb54 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -84,6 +84,7 @@
#endif
#include "PlatWin.h"
+#include "HanjaDic.h"
#ifndef SPI_GETWHEELSCROLLLINES
#define SPI_GETWHEELSCROLLLINES 104
@@ -251,6 +252,11 @@ class ScintillaWin :
void MoveImeCarets(int offset);
void DrawImeIndicator(int indicator, int len);
void SetCandidateWindowPos();
+ void BytesToUniChar(const char *bytes, const int bytesLen, wchar_t *character, int &charsLen);
+ void UniCharToBytes(const wchar_t *character, const int charsLen, char *bytes, int &bytesLen);
+ void RangeToHangul(int uniStrLen);
+ void EscapeHanja();
+ void ToggleHanja();
UINT CodePageOfDocument();
virtual bool ValidCodePage(int codePage) const;
@@ -802,6 +808,127 @@ void ScintillaWin::SetCandidateWindowPos() {
}
}
+void ScintillaWin::BytesToUniChar(const char *bytes, const int bytesLen, wchar_t *characters, int &charsLen) {
+ // Return results over characters and charsLen.
+ if (IsUnicodeMode()) {
+ charsLen = ::MultiByteToWideChar(SC_CP_UTF8, 0, bytes, bytesLen, NULL, 0);
+ ::MultiByteToWideChar(SC_CP_UTF8, 0, bytes, bytesLen, characters, charsLen);
+ } else {
+ charsLen = ::MultiByteToWideChar(CodePageOfDocument(), 0, bytes, bytesLen, NULL, 0);
+ ::MultiByteToWideChar(CodePageOfDocument(), 0, bytes, bytesLen, characters, charsLen);
+ }
+}
+
+void ScintillaWin::UniCharToBytes(const wchar_t *characters, const int charsLen, char *bytes, int &bytesLen) {
+ // Return results over bytes and bytesLen.
+ if (IsUnicodeMode()) {
+ bytesLen = UTF8Length(characters, charsLen);
+ UTF8FromUTF16(characters, charsLen, bytes, bytesLen);
+ bytes[bytesLen] = '\0';
+ } else {
+ bytesLen = ::WideCharToMultiByte(CodePageOfDocument(), 0,
+ characters, charsLen, bytes, bytesLen, 0, 0);
+ bytes[bytesLen] = '\0';
+ }
+}
+
+void ScintillaWin::RangeToHangul(int uniStrLen) {
+ // Convert every hanja to hangul from current position to the length uniStrLen.
+ // Even if not coverted, the caret should advance by 1 character.
+ pdoc->BeginUndoAction();
+ for (int i=0; i<uniStrLen; i++) {
+ unsigned int const safeLength = UTF8MaxBytes+1;
+
+ int currentPos = CurrentPosition();
+ int oneCharLen = pdoc->LenChar(currentPos);
+
+ if (oneCharLen > 1) {
+ wchar_t uniChar[safeLength] = { 0 };
+ int uniCharLen = 1;
+ char oneChar[safeLength] = "\0\0\0\0";
+ pdoc->GetCharRange(oneChar, currentPos, oneCharLen);
+
+ BytesToUniChar(oneChar, oneCharLen, uniChar, uniCharLen);
+
+ int hangul = HanjaDict::GetHangulOfHanja(uniChar[0]);
+ if (hangul > 0) {
+ uniChar[0] = static_cast<wchar_t>(hangul);
+
+ UniCharToBytes(uniChar, uniCharLen, oneChar, oneCharLen);
+
+ pdoc->DelChar(currentPos);
+ InsertPaste(oneChar, oneCharLen);
+ } else {
+ MoveImeCarets(oneCharLen);
+ }
+ } else {
+ MoveImeCarets(oneCharLen);
+ }
+ }
+ pdoc->EndUndoAction();
+}
+
+void ScintillaWin::EscapeHanja() {
+ // The candidate box pops up to user to select a hanja.
+ // It comes into WM_IME_COMPOSITION with GCS_RESULTSTR.
+ // The existing hangul or hanja is replaced with it.
+ if (sel.Count() > 1) {
+ return; // Do not allow multi carets.
+ }
+ int currentPos = CurrentPosition();
+ int oneCharLen = pdoc->LenChar(currentPos);
+
+ if (oneCharLen < 2) {
+ return; // No need to handle SBCS.
+ }
+
+ // ImmEscapeW() may overwrite uniChar[] with a null terminated string.
+ // So enlarge it enough to Maximum 4 as in UTF-8.
+ unsigned int const safeLength = UTF8MaxBytes+1;
+ wchar_t uniChar[safeLength] = {0};
+ int uniCharLen = 1;
+ char oneChar[safeLength] = "\0\0\0\0";
+
+ pdoc->GetCharRange(oneChar, currentPos, oneCharLen);
+
+ BytesToUniChar(oneChar, oneCharLen, uniChar, uniCharLen);
+
+ // Set the candidate box position since IME may show it.
+ SetCandidateWindowPos();
+
+ // IME_ESC_HANJA_MODE appears to receive the first character only.
+ HIMC hIMC=ImmGetContext(MainHWND());
+ if (hIMC) {
+ if (ImmEscapeW(GetKeyboardLayout(0), hIMC, IME_ESC_HANJA_MODE, &uniChar)) {
+ SetCandidateWindowPos(); // Force it again for sure.
+ SetSelection (currentPos, currentPos + oneCharLen);
+ }
+ ::ImmReleaseContext(MainHWND(), hIMC);
+ }
+}
+
+void ScintillaWin::ToggleHanja() {
+ // If selection, convert every hanja to hangul within the main range.
+ // If no selection, commit to IME.
+ if (sel.Count() > 1) {
+ return; // Do not allow multi carets.
+ }
+
+ int selStart = sel.RangeMain().Start().Position();
+ int documentStrLen = sel.RangeMain().Length();
+ int selEnd = selStart + documentStrLen;
+ int uniStrLen = pdoc->CountCharacters(selStart, selEnd);
+
+ // Convert one by one from the start of main range.
+ SetSelection(selStart, selStart);
+
+ if (uniStrLen > 0) {
+ RangeToHangul(uniStrLen);
+ } else {
+ EscapeHanja();
+ }
+}
+
sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) {
// Copy & paste by johnsonj with a lot of helps of Neil.
// Great thanks for my foreruners, jiniya and BLUEnLIVE.
@@ -1327,8 +1454,12 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
break;
}
- case WM_IME_KEYDOWN:
- return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
+ case WM_IME_KEYDOWN: {
+ if (wParam == VK_HANJA) {
+ ToggleHanja();
+ }
+ return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
+ }
case WM_KEYUP:
//Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);