aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/ScintillaHistory.html4
-rw-r--r--scripts/HeaderOrder.txt1
-rw-r--r--win32/HanjaDic.cxx122
-rw-r--r--win32/HanjaDic.h26
-rw-r--r--win32/SciLexer.vcxproj1
-rw-r--r--win32/ScintillaWin.cxx135
-rw-r--r--win32/makefile3
-rw-r--r--win32/scintilla.mak14
8 files changed, 299 insertions, 7 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 777ccc7d1..cf9a11104 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -498,6 +498,10 @@
Minimum version of Qt supported is now 4.8 due to the use of QElapsedTimer::nsecsElapsed.
</li>
<li>
+ On Windows, for Korean, the VK_HANJA key is implemented to choose Hanja for Hangul and
+ to convert from Hanja to Hangul.
+ </li>
+ <li>
C++ lexer adds lexer.cpp.verbatim.strings.allow.escapes option that allows verbatim (@") strings
to contain escape sequences. This should remain off (0) for C# and be turned on (1) for Objective C.
</li>
diff --git a/scripts/HeaderOrder.txt b/scripts/HeaderOrder.txt
index 2496a34a3..67854c5c1 100644
--- a/scripts/HeaderOrder.txt
+++ b/scripts/HeaderOrder.txt
@@ -124,6 +124,7 @@
// win32
#include "PlatWin.h"
+#include "HanjaDic.h"
// gtk
#include "Converter.h"
diff --git a/win32/HanjaDic.cxx b/win32/HanjaDic.cxx
new file mode 100644
index 000000000..25105ee6d
--- /dev/null
+++ b/win32/HanjaDic.cxx
@@ -0,0 +1,122 @@
+// Scintilla source code edit control
+/** @file HanjaDic.cxx
+ ** Korean Hanja Dictionary
+ ** Convert between Korean Hanja and Hangul by COM interface.
+ **/
+// Copyright 2015 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <windows.h>
+
+#include "UniConversion.h"
+#include "HanjaDic.h"
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+namespace HanjaDict {
+
+interface IRadical;
+interface IHanja;
+interface IStrokes;
+
+typedef enum { HANJA_UNKNOWN = 0, HANJA_K0 = 1, HANJA_K1 = 2, HANJA_OTHER = 3 } HANJA_TYPE;
+
+interface IHanjaDic : IUnknown {
+ STDMETHOD(OpenMainDic)();
+ STDMETHOD(CloseMainDic)();
+ STDMETHOD(GetHanjaWords)(BSTR bstrHangul, SAFEARRAY* ppsaHanja, VARIANT_BOOL* pfFound);
+ STDMETHOD(GetHanjaChars)(unsigned short wchHangul, BSTR* pbstrHanjaChars, VARIANT_BOOL* pfFound);
+ STDMETHOD(HanjaToHangul)(BSTR bstrHanja, BSTR* pbstrHangul);
+ STDMETHOD(GetHanjaType)(unsigned short wchHanja, HANJA_TYPE* pHanjaType);
+ STDMETHOD(GetHanjaSense)(unsigned short wchHanja, BSTR* pbstrSense);
+ STDMETHOD(GetRadicalID)(short SeqNumOfRadical, short* pRadicalID, unsigned short* pwchRadical);
+ STDMETHOD(GetRadical)(short nRadicalID, IRadical** ppIRadical);
+ STDMETHOD(RadicalIDToHanja)(short nRadicalID, unsigned short* pwchRadical);
+ STDMETHOD(GetHanja)(unsigned short wchHanja, IHanja** ppIHanja);
+ STDMETHOD(GetStrokes)(short nStrokes, IStrokes** ppIStrokes);
+ STDMETHOD(OpenDefaultCustomDic)();
+ STDMETHOD(OpenCustomDic)(BSTR bstrPath, long* plUdr);
+ STDMETHOD(CloseDefaultCustomDic)();
+ STDMETHOD(CloseCustomDic)(long lUdr);
+ STDMETHOD(CloseAllCustomDics)();
+ STDMETHOD(GetDefaultCustomHanjaWords)(BSTR bstrHangul, SAFEARRAY** ppsaHanja, VARIANT_BOOL* pfFound);
+ STDMETHOD(GetCustomHanjaWords)(long lUdr, BSTR bstrHangul, SAFEARRAY** ppsaHanja, VARIANT_BOOL* pfFound);
+ STDMETHOD(PutDefaultCustomHanjaWord)(BSTR bstrHangul, BSTR bstrHanja);
+ STDMETHOD(PutCustomHanjaWord)(long lUdr, BSTR bstrHangul, BSTR bstrHanja);
+ STDMETHOD(MaxNumOfRadicals)(short* pVal);
+ STDMETHOD(MaxNumOfStrokes)(short* pVal);
+ STDMETHOD(DefaultCustomDic)(long* pVal);
+ STDMETHOD(DefaultCustomDic)(long pVal);
+ STDMETHOD(MaxHanjaType)(HANJA_TYPE* pHanjaType);
+ STDMETHOD(MaxHanjaType)(HANJA_TYPE pHanjaType);
+};
+
+extern "C" const GUID __declspec(selectany) IID_IHanjaDic =
+{ 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } };
+
+class HanjaDic {
+private:
+ HRESULT hr;
+ CLSID CLSID_HanjaDic;
+
+public:
+ IHanjaDic *HJinterface;
+
+ HanjaDic() {
+ hr = CLSIDFromProgID(OLESTR("mshjdic.hanjadic"), &CLSID_HanjaDic);
+ if (SUCCEEDED(hr)) {
+ hr = CoCreateInstance(CLSID_HanjaDic, NULL,
+ CLSCTX_INPROC_SERVER, IID_IHanjaDic,
+ (LPVOID *)& HJinterface);
+ if (SUCCEEDED(hr)) {
+ hr = HJinterface->OpenMainDic();
+ }
+ }
+ }
+
+ ~HanjaDic() {
+ if (SUCCEEDED(hr)) {
+ hr = HJinterface->CloseMainDic();
+ HJinterface->Release();
+ }
+ }
+
+ bool HJdictAvailable() {
+ return SUCCEEDED(hr);
+ }
+
+ bool IsHanja(int hanja) {
+ HANJA_TYPE hanjaType;
+ hr = HJinterface->GetHanjaType(static_cast<unsigned short>(hanja), &hanjaType);
+ if (SUCCEEDED(hr)) {
+ return (hanjaType > 0);
+ }
+ return false;
+ }
+};
+
+int GetHangulOfHanja(int hanjaChar) {
+ // Convert hanja character to hangul one.
+ int hangulChar = -1; // If fails, return -1.
+ HanjaDic dict;
+ if (!dict.HJdictAvailable() || !dict.IsHanja(hanjaChar)) {
+ return hangulChar;
+ }
+ wchar_t convHnja[UTF8MaxBytes] = {0};
+ convHnja[0] = static_cast<wchar_t>(hanjaChar);
+
+ BSTR bstrHangul = SysAllocString(NULL);
+ BSTR bstrHanja = SysAllocString(convHnja);
+ HRESULT hr = dict.HJinterface->HanjaToHangul(bstrHanja, &bstrHangul);
+ if (SUCCEEDED(hr)) {
+ wchar_t wHangul = static_cast<wchar_t *>(bstrHangul)[0];
+ hangulChar = static_cast<int>(wHangul);
+ }
+ SysFreeString(bstrHangul);
+ SysFreeString(bstrHanja);
+ return hangulChar;
+}
+
+}
diff --git a/win32/HanjaDic.h b/win32/HanjaDic.h
new file mode 100644
index 000000000..5ba61f661
--- /dev/null
+++ b/win32/HanjaDic.h
@@ -0,0 +1,26 @@
+// Scintilla source code edit control
+/** @file HanjaDic.h
+ ** Korean Hanja Dictionary
+ ** Convert between Korean Hanja and Hangul by COM interface.
+ **/
+// Copyright 2015 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#ifndef HANJADIC_H
+#define HANJADIC_H
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+namespace HanjaDict {
+
+int GetHangulOfHanja(int character);
+
+}
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif
diff --git a/win32/SciLexer.vcxproj b/win32/SciLexer.vcxproj
index 50b2e5f7f..2e821b39a 100644
--- a/win32/SciLexer.vcxproj
+++ b/win32/SciLexer.vcxproj
@@ -111,6 +111,7 @@
<ClCompile Include="..\lexers\*.cxx" />
<ClCompile Include="..\lexlib\*.cxx" />
<ClCompile Include="..\src\*.cxx" />
+ <ClCompile Include="..\win32\HanjaDic.cxx" />
<ClCompile Include="..\win32\PlatWin.cxx" />
<ClCompile Include="..\win32\ScintillaWin.cxx" />
</ItemGroup>
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);
diff --git a/win32/makefile b/win32/makefile
index 6012905b4..6aa0d6139 100644
--- a/win32/makefile
+++ b/win32/makefile
@@ -91,7 +91,8 @@ BASEOBJS = \
Style.o \
UniConversion.o \
ViewStyle.o \
- XPM.o
+ XPM.o \
+ HanjaDic.o
SOBJS = ScintillaWin.o ScintillaBase.o $(BASEOBJS)
diff --git a/win32/scintilla.mak b/win32/scintilla.mak
index 17fb3e2df..d200597e5 100644
--- a/win32/scintilla.mak
+++ b/win32/scintilla.mak
@@ -88,7 +88,8 @@ SHAREDOBJS=\
$(DIR_O)\Style.obj \
$(DIR_O)\UniConversion.obj \
$(DIR_O)\ViewStyle.obj \
- $(DIR_O)\XPM.obj
+ $(DIR_O)\XPM.obj \
+ $(DIR_O)\HanjaDic.obj \
SOBJS=\
$(SHAREDOBJS) \
@@ -877,7 +878,8 @@ $(DIR_O)\ScintillaWin.obj: \
../src/Editor.h \
../src/AutoComplete.h \
../src/ScintillaBase.h \
- PlatWin.h
+ PlatWin.h \
+ HanjaDic.h
$(DIR_O)\ScintillaWinL.obj: \
ScintillaWin.cxx \
../include/Platform.h \
@@ -910,7 +912,8 @@ $(DIR_O)\ScintillaWinL.obj: \
../src/Editor.h \
../src/AutoComplete.h \
../src/ScintillaBase.h \
- PlatWin.h
+ PlatWin.h \
+ HanjaDic.h
$(DIR_O)\ScintillaWinS.obj: \
ScintillaWin.cxx \
../include/Platform.h \
@@ -943,7 +946,8 @@ $(DIR_O)\ScintillaWinS.obj: \
../src/Editor.h \
../src/AutoComplete.h \
../src/ScintillaBase.h \
- PlatWin.h
+ PlatWin.h \
+ HanjaDic.h
$(DIR_O)\Selection.obj: \
../src/Selection.cxx \
../include/Platform.h \
@@ -983,3 +987,5 @@ $(DIR_O)\XPM.obj: \
../src/XPM.cxx \
../include/Platform.h \
../src/XPM.h
+$(DIR_O)\HanjaDic: \
+ ./HanjaDic.h