diff options
Diffstat (limited to 'win32')
-rw-r--r-- | win32/HanjaDic.cxx | 122 | ||||
-rw-r--r-- | win32/HanjaDic.h | 26 | ||||
-rw-r--r-- | win32/SciLexer.vcxproj | 1 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 135 | ||||
-rw-r--r-- | win32/makefile | 3 | ||||
-rw-r--r-- | win32/scintilla.mak | 14 |
6 files changed, 294 insertions, 7 deletions
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 |