diff options
| author | Neil <nyamatongwe@gmail.com> | 2015-02-22 08:57:07 +1100 | 
|---|---|---|
| committer | Neil <nyamatongwe@gmail.com> | 2015-02-22 08:57:07 +1100 | 
| commit | e3dcaa477741dba922e3daf270ff2ecb42b5311c (patch) | |
| tree | e09f3e1c465e3f63cf1231a3a64e684d6ba2eb79 /win32 | |
| parent | e06bdec7a8e31dbef56c7953083151b888f2f89c (diff) | |
| download | scintilla-mirror-e3dcaa477741dba922e3daf270ff2ecb42b5311c.tar.gz | |
Implement VK_HANJA for Korean on Windows.
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 | 
