Full Unicode patch with RTL Support & BiDi logic.

This commit is well documented, so no need to tell you my life story.

Full Unicode patch with RTL Support & BiDi logic.

Removed the legacy codePage, normalised to UTF8 (65001).

It also comes with:

CTRL + A : select text (highlighted)
CTRL + C : copy
CTRL + V : paste
CTRL + X : cut
CTRL + Y : redo
CTRL + Z : undo
This commit is contained in:
rtw1x1
2025-12-26 12:32:43 +00:00
parent d37607baa1
commit a955c50744
86 changed files with 4076 additions and 3839 deletions

View File

@@ -1,5 +1,6 @@
#include "StdAfx.h"
#include "GrpDIB.h"
#include <utf8.h>
CGraphicDib::CGraphicDib()
{
@@ -74,10 +75,17 @@ void CGraphicDib::SetBkMode(int iBkMode)
::SetBkMode(m_hDC, iBkMode);
}
void CGraphicDib::TextOut(int ix, int iy, const char * c_szText)
void CGraphicDib::TextOut(int ix, int iy, const char* c_szText)
{
::SetBkColor(m_hDC, 0);
::TextOut(m_hDC, ix, iy, c_szText, strlen(c_szText));
::SetBkColor(m_hDC, 0);
if (!c_szText || !*c_szText)
return;
std::wstring wText = Utf8ToWide(c_szText);
if (!wText.empty())
::TextOutW(m_hDC, ix, iy, wText.c_str(), (int)wText.length());
}
void CGraphicDib::Put(HDC hDC, int x, int y)

View File

@@ -2,7 +2,9 @@
#include "GrpDevice.h"
#include "EterBase/Stl.h"
#include "EterBase/Debug.h"
#include <intrin.h>
#include <utf8.h>
bool CPU_HAS_SSE2 = false;
bool GRAPHICS_CAPS_CAN_NOT_DRAW_LINE = false;
@@ -48,9 +50,16 @@ void CGraphicDevice::RegisterWarningString(UINT uiMsg, const char * c_szString)
void CGraphicDevice::__WarningMessage(HWND hWnd, UINT uiMsg)
{
if (m_kMap_strWarningMessage.end() == m_kMap_strWarningMessage.find(uiMsg))
auto it = m_kMap_strWarningMessage.find(uiMsg);
if (it == m_kMap_strWarningMessage.end())
return;
MessageBox(hWnd, m_kMap_strWarningMessage[uiMsg].c_str(), "Warning", MB_OK|MB_TOPMOST);
const std::string& msgUtf8 = it->second;
std::wstring wMsg = Utf8ToWide(msgUtf8);
std::wstring wCaption = L"Warning"; // static wide literal is fine
MessageBoxW(hWnd, wMsg.c_str(), wCaption.c_str(), MB_OK | MB_TOPMOST);
}
void CGraphicDevice::MoveWebBrowserRect(const RECT& c_rcWebPage)
@@ -148,9 +157,9 @@ LPDIRECT3DVERTEXDECLARATION9 CGraphicDevice::CreatePNTStreamVertexShader()
if (ms_lpd3dDevice->CreateVertexDeclaration(pShaderDecl, &dwShader) != D3D_OK)
{
char szError[1024];
sprintf(szError, "Failed to create CreatePNTStreamVertexShader");
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
wchar_t szError[1024];
swprintf(szError, L"Failed to create CreatePNTStreamVertexShader");
MessageBoxW(NULL, szError, L"Vertex Shader Error", MB_ICONSTOP);
}
return dwShader;
@@ -172,9 +181,9 @@ LPDIRECT3DVERTEXDECLARATION9 CGraphicDevice::CreatePNT2StreamVertexShader()
if (ms_lpd3dDevice->CreateVertexDeclaration(pShaderDecl, &dwShader) != D3D_OK)
{
char szError[1024];
sprintf(szError, "Failed to create CreatePNT2StreamVertexShader");
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
wchar_t szError[1024];
swprintf(szError, L"Failed to create CreatePNT2StreamVertexShader");
MessageBoxW(NULL, szError, L"Vertex Shader Error", MB_ICONSTOP);
}
return dwShader;
@@ -194,9 +203,9 @@ LPDIRECT3DVERTEXDECLARATION9 CGraphicDevice::CreatePTStreamVertexShader()
if (ms_lpd3dDevice->CreateVertexDeclaration(pShaderDecl, &dwShader) != D3D_OK)
{
char szError[1024];
sprintf(szError, "Failed to create CreatePTStreamVertexShader");
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
wchar_t szError[1024];
swprintf(szError, L"Failed to create CreatePTStreamVertexShader");
MessageBoxW(NULL, szError, L"Vertex Shader Error", MB_ICONSTOP);
}
return dwShader;
@@ -221,9 +230,9 @@ LPDIRECT3DVERTEXDECLARATION9 CGraphicDevice::CreateDoublePNTStreamVertexShader()
if (ms_lpd3dDevice->CreateVertexDeclaration(pShaderDecl, &dwShader) != D3D_OK)
{
char szError[1024];
sprintf(szError, "Failed to create CreateDoublePNTStreamVertexShader");
MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
wchar_t szError[1024];
swprintf(szError, L"Failed to create CreateDoublePNTStreamVertexShader");
MessageBoxW(NULL, szError, L"Vertex Shader Error", MB_ICONSTOP);
}
return dwShader;

View File

@@ -3,6 +3,7 @@
#include "EterBase/Stl.h"
#include "Util.h"
#include <utf8.h>
CGraphicFontTexture::CGraphicFontTexture()
{
@@ -69,75 +70,74 @@ void CGraphicFontTexture::DestroyDeviceObjects()
bool CGraphicFontTexture::Create(const char* c_szFontName, int fontSize, bool bItalic)
{
Destroy();
strncpy(m_fontName, c_szFontName, sizeof(m_fontName)-1);
m_fontSize = fontSize;
m_bItalic = bItalic;
// UTF-8 -> UTF-16 for font name
std::wstring wFontName = Utf8ToWide(c_szFontName ? c_szFontName : "");
wcsncpy_s(m_fontName, wFontName.c_str(), _TRUNCATE);
m_fontSize = fontSize;
m_bItalic = bItalic;
m_x = 0;
m_y = 0;
m_step = 0;
DWORD width = 256,height = 256;
DWORD width = 256, height = 256;
if (GetMaxTextureWidth() > 512)
width = 512;
if (GetMaxTextureHeight() > 512)
height = 512;
if (!m_dib.Create(ms_hDC, width, height))
return false;
HDC hDC = m_dib.GetDCHandle();
m_hFont = GetFont(GetDefaultCodePage());
m_hFont = GetFont();
m_hFontOld=(HFONT)SelectObject(hDC, m_hFont);
m_hFontOld = (HFONT)SelectObject(hDC, m_hFont);
SetTextColor(hDC, RGB(255, 255, 255));
SetBkColor(hDC, 0);
SetBkColor(hDC, 0);
if (!AppendTexture())
return false;
return true;
}
HFONT CGraphicFontTexture::GetFont(WORD codePage)
HFONT CGraphicFontTexture::GetFont()
{
HFONT hFont = NULL;
TFontMap::iterator i = m_fontMap.find(codePage);
HFONT hFont = nullptr;
if(i != m_fontMap.end())
{
hFont = i->second;
}
else
{
LOGFONT logFont;
// For Unicode, codePage should NOT affect font selection anymore
static const WORD kUnicodeFontKey = 0;
memset(&logFont, 0, sizeof(LOGFONT));
TFontMap::iterator it = m_fontMap.find(kUnicodeFontKey);
if (it != m_fontMap.end())
return it->second;
logFont.lfHeight = m_fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = (BYTE) m_bItalic;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = GetCharsetFromCodePage(codePage);
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
//Tracenf("font: %s", GetFontFaceFromCodePage(codePage));
strcpy(logFont.lfFaceName, m_fontName); //GetFontFaceFromCodePage(codePage));
//strcpy(logFont.lfFaceName, GetFontFaceFromCodePage(codePage));
LOGFONTW logFont{};
hFont = CreateFontIndirect(&logFont);
logFont.lfHeight = m_fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = (BYTE)m_bItalic;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
m_fontMap.insert(TFontMap::value_type(codePage, hFont));
}
// Copy Unicode font face name safely
wcsncpy_s(logFont.lfFaceName, m_fontName, _TRUNCATE);
hFont = CreateFontIndirectW(&logFont);
if (hFont)
m_fontMap.insert(TFontMap::value_type(kUnicodeFontKey, hFont));
return hFont;
}
@@ -189,9 +189,9 @@ bool CGraphicFontTexture::UpdateTexture()
return true;
}
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfomation(WORD codePage, wchar_t keyValue)
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfomation(wchar_t keyValue)
{
TCharacterKey code(codePage, keyValue);
TCharacterKey code = keyValue;
TCharacterInfomationMap::iterator f = m_charInfoMap.find(code);
@@ -201,22 +201,20 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfo
}
else
{
return &f->second;
return &f->second;
}
}
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterInfomation(TCharacterKey code)
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterInfomation(TCharacterKey keyValue)
{
HDC hDC = m_dib.GetDCHandle();
SelectObject(hDC, GetFont(code.first));
wchar_t keyValue = code.second;
SelectObject(hDC, GetFont());
if (keyValue == 0x08)
keyValue = L' '; // 탭은 공백으로 바꾼다 (아랍 출력시 탭 사용: NAME:\tTEXT -> TEXT\t:NAME 로 전환됨 )
keyValue = L' '; // 탭은 공백으로 바꾼다 (아랍 출력시 탭 사용: NAME:\tTEXT -> TEXT\t:NAME 로 전환됨 )
ABCFLOAT stABC;
SIZE size;
ABCFLOAT stABC;
SIZE size;
if (!GetTextExtentPoint32W(hDC, &keyValue, 1, &size) || !GetCharABCWidthsFloatW(hDC, keyValue, keyValue, &stABC))
return NULL;
@@ -254,21 +252,20 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterI
}
TextOutW(hDC, m_x, m_y, &keyValue, 1);
int nChrX;
int nChrY;
int nChrWidth = size.cx;
int nChrHeight = size.cy;
int nDIBWidth = m_dib.GetWidth();
DWORD*pdwDIBData=(DWORD*)m_dib.GetPointer();
DWORD*pdwDIBData=(DWORD*)m_dib.GetPointer();
DWORD*pdwDIBBase=pdwDIBData+nDIBWidth*m_y+m_x;
DWORD*pdwDIBRow;
pdwDIBRow=pdwDIBBase;
for (nChrY=0; nChrY<nChrHeight; ++nChrY, pdwDIBRow+=nDIBWidth)
{
{
for (nChrX=0; nChrX<nChrWidth; ++nChrX)
{
pdwDIBRow[nChrX]=(pdwDIBRow[nChrX]&0xff) ? 0xffff : 0;
@@ -278,7 +275,7 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterI
float rhwidth = 1.0f / float(width);
float rhheight = 1.0f / float(height);
TCharacterInfomation& rNewCharInfo = m_charInfoMap[code];
TCharacterInfomation& rNewCharInfo = m_charInfoMap[keyValue];
rNewCharInfo.index = static_cast<short>(m_pFontTextureVector.size() - 1);
rNewCharInfo.width = size.cx;
@@ -292,7 +289,7 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterI
m_x += size.cx;
if (m_step < size.cy)
m_step = size.cy;
m_step = size.cy;
m_isDirty = true;

View File

@@ -9,73 +9,73 @@
class CGraphicFontTexture : public CGraphicTexture
{
public:
typedef std::pair<WORD,wchar_t> TCharacterKey;
public:
typedef wchar_t TCharacterKey;
typedef struct SCharacterInfomation
{
short index;
short width;
short height;
float left;
float top;
float right;
float bottom;
float advance;
} TCharacterInfomation;
typedef struct SCharacterInfomation
{
short index;
short width;
short height;
float left;
float top;
float right;
float bottom;
float advance;
} TCharacterInfomation;
typedef std::vector<TCharacterInfomation*> TPCharacterInfomationVector;
typedef std::vector<TCharacterInfomation*> TPCharacterInfomationVector;
public:
CGraphicFontTexture();
virtual ~CGraphicFontTexture();
public:
CGraphicFontTexture();
virtual ~CGraphicFontTexture();
void Destroy();
bool Create(const char* c_szFontName, int fontSize, bool bItalic);
void Destroy();
bool Create(const char* c_szFontName, int fontSize, bool bItalic);
bool CreateDeviceObjects();
void DestroyDeviceObjects();
bool CreateDeviceObjects();
void DestroyDeviceObjects();
bool CheckTextureIndex(DWORD dwTexture);
void SelectTexture(DWORD dwTexture);
bool CheckTextureIndex(DWORD dwTexture);
void SelectTexture(DWORD dwTexture);
bool UpdateTexture();
bool UpdateTexture();
TCharacterInfomation* GetCharacterInfomation(WORD codePage, wchar_t keyValue);
TCharacterInfomation* UpdateCharacterInfomation(TCharacterKey code);
TCharacterInfomation* GetCharacterInfomation(wchar_t keyValue);
TCharacterInfomation* UpdateCharacterInfomation(TCharacterKey keyValue);
bool IsEmpty() const;
bool IsEmpty() const;
protected:
void Initialize();
protected:
void Initialize();
bool AppendTexture();
bool AppendTexture();
HFONT GetFont(WORD codePage);
HFONT GetFont();
protected:
typedef std::vector<CGraphicImageTexture*> TGraphicImageTexturePointerVector;
typedef std::map<TCharacterKey, TCharacterInfomation> TCharacterInfomationMap;
typedef std::map<WORD, HFONT> TFontMap;
protected:
typedef std::vector<CGraphicImageTexture*> TGraphicImageTexturePointerVector;
typedef std::map<TCharacterKey, TCharacterInfomation> TCharacterInfomationMap;
typedef std::map<WORD, HFONT> TFontMap;
protected:
CGraphicDib m_dib;
protected:
CGraphicDib m_dib;
HFONT m_hFontOld;
HFONT m_hFont;
HFONT m_hFontOld;
HFONT m_hFont;
TGraphicImageTexturePointerVector m_pFontTextureVector;
TGraphicImageTexturePointerVector m_pFontTextureVector;
TCharacterInfomationMap m_charInfoMap;
TCharacterInfomationMap m_charInfoMap;
TFontMap m_fontMap;
TFontMap m_fontMap;
int m_x;
int m_y;
int m_step;
bool m_isDirty;
int m_x;
int m_y;
int m_step;
bool m_isDirty;
TCHAR m_fontName[LF_FACESIZE];
LONG m_fontSize;
bool m_bItalic;
TCHAR m_fontName[LF_FACESIZE];
LONG m_fontSize;
bool m_bItalic;
};

View File

@@ -3,6 +3,8 @@
#include "GrpD3DXBuffer.h"
#include "StateManager.h"
#include <utf8.h>
CPixelShader::CPixelShader()
{
Initialize();
@@ -29,23 +31,46 @@ void CPixelShader::Destroy()
bool CPixelShader::CreateFromDiskFile(const char* c_szFileName)
{
Destroy();
Destroy();
LPD3DXBUFFER lpd3dxShaderBuffer;
LPD3DXBUFFER lpd3dxErrorBuffer;
if (FAILED(
D3DXAssembleShaderFromFile(c_szFileName, 0, NULL, 0, &lpd3dxShaderBuffer, &lpd3dxErrorBuffer)
))
return false;
if (!c_szFileName || !*c_szFileName)
return false;
CDirect3DXBuffer shaderBuffer(lpd3dxShaderBuffer);
CDirect3DXBuffer errorBuffer(lpd3dxErrorBuffer);
// UTF-8 -> UTF-16 for D3DX
std::wstring wFileName = Utf8ToWide(c_szFileName);
if (FAILED(ms_lpd3dDevice->CreatePixelShader((DWORD*)shaderBuffer.GetPointer(), &m_handle)))
return false;
LPD3DXBUFFER lpd3dxShaderBuffer = nullptr;
LPD3DXBUFFER lpd3dxErrorBuffer = nullptr;
return true;
HRESULT hr = D3DXAssembleShaderFromFileW(
wFileName.c_str(),
nullptr,
nullptr,
0,
&lpd3dxShaderBuffer,
&lpd3dxErrorBuffer
);
if (FAILED(hr))
{
// Log compiler error text (it is ANSI/ASCII)
if (lpd3dxErrorBuffer)
{
const char* err = (const char*)lpd3dxErrorBuffer->GetBufferPointer();
TraceError("Shader compile error: %s", err);
}
return false;
}
CDirect3DXBuffer shaderBuffer(lpd3dxShaderBuffer);
CDirect3DXBuffer errorBuffer(lpd3dxErrorBuffer);
if (FAILED(ms_lpd3dDevice->CreatePixelShader(
(DWORD*)shaderBuffer.GetPointer(),
&m_handle)))
return false;
return true;
}
void CPixelShader::Set()

View File

@@ -4,6 +4,7 @@
#include "StateManager.h"
#include <comdef.h>
#include <utf8.h>
DWORD CScreen::ms_diffuseColor = 0xffffffff;
DWORD CScreen::ms_clearColor = 0L;
@@ -669,8 +670,11 @@ BOOL CScreen::RestoreDevice()
if (FAILED(hrReset))
{
_com_error err(hrReset);
LPCTSTR errMsg = err.ErrorMessage();
TraceError(errMsg);
LPCWSTR errMsgW = err.ErrorMessage(); // wide string
std::string errUtf8 = WideToUtf8(errMsgW);
TraceError("%s", errUtf8.c_str());
return FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ class CGraphicTextInstance
HORIZONTAL_ALIGN_CENTER = 0x02,
HORIZONTAL_ALIGN_RIGHT = 0x03,
};
enum EVerticalAlign
{
VERTICAL_ALIGN_TOP = 0x10,
@@ -23,6 +24,13 @@ class CGraphicTextInstance
VERTICAL_ALIGN_BOTTOM = 0x30
};
enum class ETextDirection : unsigned char
{
Auto = 0,
LTR = 1,
RTL = 2,
};
public:
static void Hyperlink_UpdateMousePos(int x, int y);
static int Hyperlink_GetText(char* buf, int len);
@@ -65,14 +73,24 @@ class CGraphicTextInstance
const std::string& GetValueStringReference();
WORD GetTextLineCount();
void SetTextDirection(ETextDirection dir);
ETextDirection GetTextDirection() const { return m_direction; }
bool IsRTL() const
{
// For AUTO mode, use computed result from BiDi analysis
if (m_direction == ETextDirection::Auto)
return m_computedRTL;
// For explicit direction, derive from m_direction
return (m_direction == ETextDirection::RTL);
}
int PixelPositionToCharacterPosition(int iPixelPosition);
int GetHorizontalAlign();
protected:
void __Initialize();
int __DrawCharacter(CGraphicFontTexture * pFontTexture, WORD codePage, wchar_t text, DWORD dwColor);
int __DrawCharacter(CGraphicFontTexture * pFontTexture, wchar_t text, DWORD dwColor);
void __GetTextPos(DWORD index, float* x, float* y);
int __GetTextTag(const wchar_t * src, int maxLen, int & tagLen, std::wstring & extraInfo);
protected:
struct SHyperlink
@@ -112,11 +130,15 @@ class CGraphicTextInstance
private:
bool m_isUpdate;
bool m_isUpdateFontTexture;
bool m_computedRTL; // Result of BiDi analysis (used when m_direction == Auto)
CGraphicText::TRef m_roText;
CGraphicFontTexture::TPCharacterInfomationVector m_pCharInfoVector;
std::vector<DWORD> m_dwColorInfoVector;
std::vector<SHyperlink> m_hyperlinkVector;
std::vector<int> m_logicalToVisualPos; // Maps logical cursor pos (UTF-16 with tags) to visual pos (rendered chars)
std::vector<int> m_visualToLogicalPos; // Reverse mapping: visual pos -> logical pos
ETextDirection m_direction = ETextDirection::Auto; // Will be overwritten by __Initialize()
public:
static void CreateSystem(UINT uCapacity);
@@ -125,10 +147,8 @@ class CGraphicTextInstance
static CGraphicTextInstance* New();
static void Delete(CGraphicTextInstance* pkInst);
static CDynamicPool<CGraphicTextInstance> ms_kPool;
static CDynamicPool<CGraphicTextInstance> ms_kPool;
};
extern const char* FindToken(const char* begin, const char* end);
extern int ReadToken(const char* token);
#endif

View File

@@ -3,6 +3,8 @@
#include "GrpD3DXBuffer.h"
#include "StateManager.h"
#include <utf8.h>
CVertexShader::CVertexShader()
{
Initialize();
@@ -29,21 +31,44 @@ void CVertexShader::Destroy()
bool CVertexShader::CreateFromDiskFile(const char* c_szFileName, const DWORD* c_pdwVertexDecl)
{
Destroy();
Destroy();
LPD3DXBUFFER lpd3dxShaderBuffer;
LPD3DXBUFFER lpd3dxErrorBuffer;
if (FAILED(
D3DXAssembleShaderFromFile(c_szFileName, 0, NULL, 0, &lpd3dxShaderBuffer, &lpd3dxErrorBuffer)
)) return false;
if (!c_szFileName || !*c_szFileName)
return false;
if (FAILED(
ms_lpd3dDevice->CreateVertexShader((const DWORD*)lpd3dxShaderBuffer->GetBufferPointer(), &m_handle)
))
return false;
// UTF-8 → UTF-16 for D3DX
std::wstring wFileName = Utf8ToWide(c_szFileName);
return true;
LPD3DXBUFFER lpd3dxShaderBuffer = nullptr;
LPD3DXBUFFER lpd3dxErrorBuffer = nullptr;
HRESULT hr = D3DXAssembleShaderFromFileW(
wFileName.c_str(),
nullptr,
nullptr,
0,
&lpd3dxShaderBuffer,
&lpd3dxErrorBuffer
);
if (FAILED(hr))
{
if (lpd3dxErrorBuffer)
{
const char* err = (const char*)lpd3dxErrorBuffer->GetBufferPointer();
TraceError("Vertex shader compile error: %s", err);
}
return false;
}
if (FAILED(
ms_lpd3dDevice->CreateVertexShader(
(const DWORD*)lpd3dxShaderBuffer->GetBufferPointer(),
&m_handle
)))
return false;
return true;
}
void CVertexShader::Set()

File diff suppressed because it is too large Load Diff

View File

@@ -6,203 +6,237 @@
#include "DIMM.h"
#include <vector>
#include <string>
class IIMEEventSink
{
public:
virtual bool OnWM_CHAR( WPARAM wParam, LPARAM lParam ) = 0;
virtual void OnUpdate() = 0;
public:
virtual bool OnWM_CHAR( WPARAM wParam, LPARAM lParam ) = 0;
virtual void OnUpdate() = 0;
virtual void OnChangeCodePage() = 0;
virtual void OnOpenCandidateList() = 0;
virtual void OnCloseCandidateList() = 0;
virtual void OnOpenCandidateList() = 0;
virtual void OnCloseCandidateList() = 0;
virtual void OnOpenReadingWnd() = 0;
virtual void OnCloseReadingWnd() = 0;
virtual void OnOpenReadingWnd() = 0;
virtual void OnCloseReadingWnd() = 0;
};
class CIME
{
public:
enum
{
IMEREADING_MAXLEN = 128,
IMESTR_MAXLEN = 1024,
IMECANDIDATE_MAXLEN = 32768,
MAX_CANDLIST = 10,
MAX_CANDIDATE_LENGTH = 256
};
public:
enum
{
IMEREADING_MAXLEN = 128,
IMESTR_MAXLEN = 1024,
IMECANDIDATE_MAXLEN = 32768,
MAX_CANDLIST = 10,
MAX_CANDIDATE_LENGTH = 256
};
public:
CIME();
virtual ~CIME();
public:
CIME();
virtual ~CIME();
bool Initialize(HWND hWnd);
void Uninitialize(void);
bool Initialize(HWND hWnd);
void Uninitialize(void);
static void Clear();
static void Clear();
void SetMax(int iMax);
void SetUserMax(int iMax);
void SetText(const char* c_szText, int len);
int GetText(std::string & rstrText, bool addCodePage=false);
const char* GetCodePageText();
int GetCodePage();
void SetMax(int iMax);
void SetUserMax(int iMax);
static void SetText(const char* c_szText, int len);
int GetText(std::string & rstrText);
// Candidate List
int GetCandidateCount();
int GetCandidatePageCount();
int GetCandidate(DWORD index, std::string & rstrText);
int GetCandidateSelection();
// Candidate List
int GetCandidateCount();
int GetCandidatePageCount();
int GetCandidate(DWORD index, std::string & rstrText);
int GetCandidateSelection();
// Reading Information
int GetReading(std::string & rstrText);
int GetReadingError();
// Reading Information
int GetReading(std::string & rstrText);
int GetReadingError();
void SetInputMode(DWORD dwMode);
DWORD GetInputMode();
void SetInputMode(DWORD dwMode);
DWORD GetInputMode();
bool IsIMEEnabled();
void EnableIME(bool bEnable=true);
void DisableIME();
bool IsIMEEnabled();
void EnableIME(bool bEnable=true);
void DisableIME();
void EnableCaptureInput();
void DisableCaptureInput();
bool IsCaptureEnabled();
void EnableCaptureInput();
void DisableCaptureInput();
bool IsCaptureEnabled();
void SetNumberMode();
void SetStringMode();
bool __IsWritable(wchar_t key);
void AddExceptKey(wchar_t key);
void ClearExceptKey();
void SetNumberMode();
void SetStringMode();
bool __IsWritable(wchar_t key);
void AddExceptKey(wchar_t key);
void ClearExceptKey();
void PasteTextFromClipBoard();
void EnablePaste(bool bFlag);
void PasteString(const char * str);
static void FinalizeString(bool bSend = false);
void PasteTextFromClipBoard();
void EnablePaste(bool bFlag);
void PasteString(const char * str);
static void FinalizeString(bool bSend = false);
void UseDefaultIME();
void SelectAll();
void DeleteSelection();
void CopySelectionToClipboard(HWND hWnd);
void CutSelectionToClipboard(HWND hWnd);
static int GetCurPos();
static int GetCompLen();
static int GetULBegin();
static int GetULEnd();
void UseDefaultIME();
static void CloseCandidateList();
static void CloseReadingInformation();
static void ChangeInputLanguage();
static void ChangeInputLanguageWorker();
static int GetCurPos();
static int GetCompLen();
static int GetULBegin();
static int GetULEnd();
LRESULT WMInputLanguage(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMStartComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMEndComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMNotify(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMChar(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
static int GetSelBegin();
static int GetSelEnd();
static void ClearSelection();
protected:
void IncCurPos();
void DecCurPos();
void SetCurPos(int offset);
void DelCurPos();
static void CloseCandidateList();
static void CloseReadingInformation();
static void ChangeInputLanguage();
static void ChangeInputLanguageWorker();
protected:
static void CheckInputLocale();
static void CheckToggleState();
static void SetSupportLevel( DWORD dwImeLevel );
LRESULT WMInputLanguage(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMStartComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMEndComposition(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMNotify(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT WMChar(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
void InsertString(wchar_t* szString, int iSize);
public:
struct SUndoState
{
std::wstring text;
int curpos = 0;
int lastpos = 0;
int selbegin = 0;
int selend = 0;
};
void OnChar(wchar_t c);
static void PushUndoState();
static void Undo();
static void Redo();
static void ClearUndoRedo();
UINT GetCodePageFromLang( LANGID langid );
void ResultProcess(HIMC hImc);
void CompositionProcessBuilding(HIMC hImc);
void CompositionProcess(HIMC hImc);
void AttributeProcess(HIMC hImc);
void CandidateProcess(HIMC hImc);
void ReadingProcess(HIMC hImc);
static bool CanUndo();
static bool CanRedo();
bool IsMax(const wchar_t* wInput, int len);
private:
static void RestoreState(const SUndoState& st);
DWORD GetImeId(UINT uIndex = 0);
bool GetReadingWindowOrientation();
static void SetupImeApi();
private:
static std::vector<SUndoState> ms_undo;
static std::vector<SUndoState> ms_redo;
static const size_t MAX_UNDO = 64;
static INPUTCONTEXT* (WINAPI * _ImmLockIMC)( HIMC );
static BOOL (WINAPI * _ImmUnlockIMC)( HIMC );
static LPVOID (WINAPI * _ImmLockIMCC)( HIMCC );
static BOOL (WINAPI * _ImmUnlockIMCC)( HIMCC );
protected:
void IncCurPos();
void DecCurPos();
void SetCurPos(int offset);
void DelCurPos();
static UINT (WINAPI * _GetReadingString)( HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT );
static BOOL (WINAPI * _ShowReadingWindow)( HIMC, BOOL );
protected:
static void CheckInputLocale();
static void CheckToggleState();
static void SetSupportLevel( DWORD dwImeLevel );
protected:
HIMC m_hOrgIMC;
int m_max;
int m_userMax;
void InsertString(wchar_t* szString, int iSize);
BOOL m_bOnlyNumberMode;
void OnChar(wchar_t c);
std::vector<wchar_t> m_exceptKey;
void ResultProcess(HIMC hImc);
void CompositionProcessBuilding(HIMC hImc);
void CompositionProcess(HIMC hImc);
void AttributeProcess(HIMC hImc);
void CandidateProcess(HIMC hImc);
void ReadingProcess(HIMC hImc);
bool m_bEnablePaste;
bool m_bUseDefaultIME;
bool IsMax(const wchar_t* wInput, int len);
DWORD GetImeId(UINT uIndex = 0);
bool GetReadingWindowOrientation();
static void SetupImeApi();
static INPUTCONTEXT* (WINAPI * _ImmLockIMC)( HIMC );
static BOOL (WINAPI * _ImmUnlockIMC)( HIMC );
static LPVOID (WINAPI * _ImmLockIMCC)( HIMCC );
static BOOL (WINAPI * _ImmUnlockIMCC)( HIMCC );
static UINT (WINAPI * _GetReadingString)( HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT );
static BOOL (WINAPI * _ShowReadingWindow)( HIMC, BOOL );
protected:
HIMC m_hOrgIMC;
int m_max;
int m_userMax;
BOOL m_bOnlyNumberMode;
std::vector<wchar_t> m_exceptKey;
bool m_bEnablePaste;
bool m_bUseDefaultIME;
public:
static bool ms_bInitialized;
static bool ms_bDisableIMECompletely;
static bool ms_bUILessMode;
static bool ms_bImeEnabled;
static bool ms_bCaptureInput;
static bool ms_bChineseIME;
static bool ms_bUseIMMCandidate;
public:
static bool ms_bInitialized;
static bool ms_bDisableIMECompletely;
static bool ms_bUILessMode;
static bool ms_bImeEnabled;
static bool ms_bCaptureInput;
static bool ms_bChineseIME;
static bool ms_bUseIMMCandidate;
static HWND ms_hWnd;
static HKL ms_hklCurrent;
static char ms_szKeyboardLayout[KL_NAMELENGTH+1];
static OSVERSIONINFOA ms_stOSVI;
static HWND ms_hWnd;
static HKL ms_hklCurrent;
static wchar_t ms_szKeyboardLayout[KL_NAMELENGTH+1];
static OSVERSIONINFOW ms_stOSVI;
static HINSTANCE ms_hImm32Dll;
static HINSTANCE ms_hCurrentImeDll;
static DWORD ms_dwImeState;
static HINSTANCE ms_hImm32Dll;
static HINSTANCE ms_hCurrentImeDll;
static DWORD ms_dwImeState;
static DWORD ms_adwId[2];
static DWORD ms_adwId[2];
// IME Level
static DWORD ms_dwIMELevel;
static DWORD ms_dwIMELevelSaved;
// IME Level
static DWORD ms_dwIMELevel;
static DWORD ms_dwIMELevelSaved;
// Candidate List
static bool ms_bCandidateList;
static DWORD ms_dwCandidateCount;
static bool ms_bVerticalCandidate;
static int ms_iCandListIndexBase;
static WCHAR ms_wszCandidate[CIME::MAX_CANDLIST][MAX_CANDIDATE_LENGTH];
static DWORD ms_dwCandidateSelection;
static DWORD ms_dwCandidatePageSize;
// Candidate List
static bool ms_bCandidateList;
static DWORD ms_dwCandidateCount;
static bool ms_bVerticalCandidate;
static int ms_iCandListIndexBase;
static WCHAR ms_wszCandidate[CIME::MAX_CANDLIST][MAX_CANDIDATE_LENGTH];
static DWORD ms_dwCandidateSelection;
static DWORD ms_dwCandidatePageSize;
// Reading Information
static bool ms_bReadingInformation;
static int ms_iReadingError;
static bool ms_bHorizontalReading;
static std::vector<wchar_t> ms_wstrReading;
// Reading Information
static bool ms_bReadingInformation;
static int ms_iReadingError;
static bool ms_bHorizontalReading;
static std::vector<wchar_t> ms_wstrReading;
// Indicator
static wchar_t* ms_wszCurrentIndicator;
// Indicator
static wchar_t* ms_wszCurrentIndicator;
static IIMEEventSink* ms_pEvent;
static IIMEEventSink* ms_pEvent;
wchar_t m_wszComposition[IMESTR_MAXLEN];
static wchar_t m_wText[IMESTR_MAXLEN];
wchar_t m_wszComposition[IMESTR_MAXLEN];
static wchar_t m_wText[IMESTR_MAXLEN];
static int ms_compLen;
static int ms_curpos;
static int ms_lastpos;
static int ms_ulbegin;
static int ms_ulend;
static int ms_compLen;
static int ms_curpos;
static int ms_lastpos;
static int ms_ulbegin;
static int ms_ulend;
static UINT ms_uOutputCodePage;
static UINT ms_uInputCodePage;
static int ms_selbegin;
static int ms_selend;
static int ms_compCaret;
};

View File

@@ -2,6 +2,7 @@
#include "MsWindow.h"
#include <windowsx.h>
#include <utf8.h>
CMSWindow::TWindowClassSet CMSWindow::ms_stWCSet;
HINSTANCE CMSWindow::ms_hInstance = NULL;
@@ -61,27 +62,32 @@ void CMSWindow::Destroy()
bool CMSWindow::Create(const char* c_szName, int brush, DWORD cs, DWORD ws, HICON hIcon, int iCursorResource)
{
//assert(ms_hInstance != NULL);
Destroy();
const char* c_szClassName = RegisterWindowClass(cs, brush, MSWindowProcedure, hIcon, iCursorResource);
m_hWnd = CreateWindow(
c_szClassName,
c_szName,
ws,
0, 0, 0, 0,
NULL,
NULL,
ms_hInstance,
NULL);
const wchar_t* wClassName =
RegisterWindowClass(cs, brush, MSWindowProcedure, hIcon, iCursorResource);
if (!wClassName)
return false;
// Window title is UTF-8 → convert
std::wstring wWindowName = Utf8ToWide(c_szName ? c_szName : "");
m_hWnd = CreateWindowW(
wClassName, // already wide
wWindowName.c_str(), // wide
ws,
0, 0, 0, 0,
nullptr,
nullptr,
ms_hInstance,
nullptr
);
if (!m_hWnd)
return false;
SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
//DestroyWindow(ImmGetDefaultIMEWnd(m_hWnd));
SetWindowLongPtrW(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
return true;
}
@@ -197,7 +203,11 @@ void CMSWindow::AdjustSize(int width, int height)
void CMSWindow::SetText(const char* c_szText)
{
SetWindowText(m_hWnd, c_szText);
if (!m_hWnd)
return;
std::wstring wText = Utf8ToWide(c_szText ? c_szText : "");
SetWindowTextW(m_hWnd, wText.c_str());
}
void CMSWindow::SetSize(int width, int height)
@@ -205,37 +215,41 @@ void CMSWindow::SetSize(int width, int height)
SetWindowPos(m_hWnd, NULL, 0, 0, width, height, SWP_NOZORDER|SWP_NOMOVE);
}
const char * CMSWindow::RegisterWindowClass(DWORD style, int brush, WNDPROC pfnWndProc, HICON hIcon, int iCursorResource)
const wchar_t* CMSWindow::RegisterWindowClass(DWORD style, int brush, WNDPROC pfnWndProc, HICON hIcon, int iCursorResource)
{
char szClassName[1024];
sprintf(szClassName, "eter - s%x:b%x:p:%x", style, brush, (DWORD) pfnWndProc);
wchar_t szClassName[1024];
swprintf_s(
szClassName,
L"eter - s%x:b%x:p:%p",
style,
brush,
pfnWndProc
);
TWindowClassSet::iterator f = ms_stWCSet.find((char*) szClassName);
// Use a set of std::wstring (NOT char*)
TWindowClassSet::iterator it = ms_stWCSet.find(szClassName);
if (it != ms_stWCSet.end())
return it->c_str();
if (f != ms_stWCSet.end())
return *f;
// Persist the string
std::wstring staticClassName = szClassName;
ms_stWCSet.insert(staticClassName);
const char* c_szStaticClassName = stl_static_string(szClassName).c_str();
WNDCLASSW wc{};
wc.style = style;
wc.lpfnWndProc = pfnWndProc;
wc.hCursor = LoadCursor(ms_hInstance, MAKEINTRESOURCE(iCursorResource));
wc.hIcon = hIcon ? hIcon : LoadIcon(ms_hInstance, IDI_APPLICATION);
wc.hbrBackground = (HBRUSH)GetStockObject(brush);
wc.hInstance = ms_hInstance;
wc.lpszClassName = staticClassName.c_str();
wc.lpszMenuName = nullptr;
ms_stWCSet.insert((char * const) c_szStaticClassName);
WNDCLASS wc;
if (!RegisterClassW(&wc))
return nullptr;
wc.style = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpfnWndProc = pfnWndProc;
wc.hCursor = LoadCursor(ms_hInstance, MAKEINTRESOURCE(iCursorResource));
wc.hIcon = hIcon ? hIcon : LoadIcon(ms_hInstance, IDI_APPLICATION);
wc.hbrBackground = (HBRUSH) GetStockObject(brush);
wc.hInstance = ms_hInstance;
wc.lpszClassName = c_szStaticClassName;
wc.lpszMenuName = "";
if (!RegisterClass(&wc))
return "";
return c_szStaticClassName;
// Return pointer stable inside the set
return ms_stWCSet.find(staticClassName)->c_str();
}
CMSWindow::CMSWindow()

View File

@@ -42,10 +42,10 @@ class CMSWindow
virtual void OnSize(WPARAM wParam, LPARAM lParam);
protected:
const char* RegisterWindowClass(DWORD style, int brush, WNDPROC pfnWndProc, HICON hIcon=NULL, int iCursorResource=32512);
const wchar_t* RegisterWindowClass(DWORD style, int brush, WNDPROC pfnWndProc, HICON hIcon=NULL, int iCursorResource=32512);
protected:
typedef std::set<char*, stl_sz_less> TWindowClassSet;
typedef std::set<std::wstring> TWindowClassSet;
protected:
HWND m_hWnd;

View File

@@ -2,38 +2,30 @@
#include "TextBar.h"
#include "EterLib/Util.h"
#include <utf8.h>
void CTextBar::__SetFont(int fontSize, bool isBold)
{
int iCodePage = GetDefaultCodePage();
LOGFONTW logFont{};
LOGFONT logFont;
logFont.lfHeight = fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = isBold ? FW_BOLD : FW_NORMAL;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
wcscpy_s(logFont.lfFaceName, LF_FACESIZE, L"Tahoma");
memset(&logFont, 0, sizeof(LOGFONT));
logFont.lfHeight = fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
if (isBold)
logFont.lfWeight = FW_BOLD;
else
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = GetCharsetFromCodePage(iCodePage);
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
strcpy(logFont.lfFaceName, GetFontFaceFromCodePage(iCodePage));
m_hFont = CreateFontIndirect(&logFont);
HDC hdc = m_dib.GetDCHandle();
m_hOldFont = (HFONT)SelectObject(hdc, m_hFont);
}
void CTextBar::SetTextColor(int r, int g, int b)
@@ -41,11 +33,24 @@ void CTextBar::SetTextColor(int r, int g, int b)
HDC hDC = m_dib.GetDCHandle();
::SetTextColor(hDC, RGB(r, g, b));
}
void CTextBar::GetTextExtent(const char * c_szText, SIZE* p_size)
void CTextBar::GetTextExtent(const char* c_szText, SIZE* p_size)
{
if (!c_szText || !p_size)
{
if (p_size)
{
p_size->cx = 0;
p_size->cy = 0;
}
return;
}
HDC hDC = m_dib.GetDCHandle();
GetTextExtentPoint32(hDC, c_szText, strlen(c_szText), p_size);
// UTF-8 → UTF-16
std::wstring wText = Utf8ToWide(c_szText);
GetTextExtentPoint32W(hDC, wText.c_str(), static_cast<int>(wText.length()), p_size);
}
void CTextBar::TextOut(int ix, int iy, const char * c_szText)
@@ -63,10 +68,9 @@ void CTextBar::OnCreate()
CTextBar::CTextBar(int fontSize, bool isBold)
{
m_hOldFont = NULL;
m_hOldFont = NULL;
m_fontSize = fontSize;
m_isBold = isBold;
}
CTextBar::~CTextBar()

View File

@@ -57,16 +57,24 @@ std::wstring GetTextTagOutputString(const wchar_t * src, int src_len)
if (tag == TEXT_TAG_PLAIN || tag == TEXT_TAG_TAG)
{
if (hyperlinkStep == 0)
// Show normal text (step 0) AND hyperlink visible text (step 2)
if (hyperlinkStep == 0 || hyperlinkStep == 2)
{
++output_len;
dst += src[i];
}
}
else if (tag == TEXT_TAG_HYPERLINK_START)
hyperlinkStep = 1;
hyperlinkStep = 1; // Start metadata (hidden)
else if (tag == TEXT_TAG_HYPERLINK_END)
hyperlinkStep = 0;
{
// First |h: end metadata, start visible (1 -> 2)
// Second |h: end visible (2 -> 0)
if (hyperlinkStep == 1)
hyperlinkStep = 2;
else if (hyperlinkStep == 2)
hyperlinkStep = 0;
}
i += len;
}
@@ -98,7 +106,8 @@ int GetTextTagInternalPosFromRenderPos(const wchar_t * src, int src_len, int off
}
else if (tag == TEXT_TAG_PLAIN || tag == TEXT_TAG_TAG)
{
if (hyperlinkStep == 0)
// Show normal text (step 0) AND hyperlink visible text (step 2)
if (hyperlinkStep == 0 || hyperlinkStep == 2)
{
if (!color_tag)
internal_offset = i;
@@ -111,9 +120,16 @@ int GetTextTagInternalPosFromRenderPos(const wchar_t * src, int src_len, int off
}
}
else if (tag == TEXT_TAG_HYPERLINK_START)
hyperlinkStep = 1;
hyperlinkStep = 1; // Start metadata (hidden)
else if (tag == TEXT_TAG_HYPERLINK_END)
hyperlinkStep = 0;
{
// First |h: end metadata, start visible (1 -> 2)
// Second |h: end visible (2 -> 0)
if (hyperlinkStep == 1)
hyperlinkStep = 2;
else if (hyperlinkStep == 2)
hyperlinkStep = 0;
}
i += len;
}

View File

@@ -133,252 +133,3 @@ D3DXCOLOR TokenToColor(CTokenVector & rVector)
atof(rVector[2].c_str()),
atof(rVector[3].c_str()));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static std::string gs_fontFace="";
static DWORD gs_codePage=0;
int CALLBACK EnumFontFamExProc(CONST LOGFONT* plogFont, CONST TEXTMETRIC* /*textMetric*/, DWORD /*dwWord*/, LPARAM lParam)
{
return stricmp((const char*)lParam, plogFont->lfFaceName);
}
int GetCharsetFromCodePage(WORD codePage)
{
switch( codePage )
{
case CP_932:
return SHIFTJIS_CHARSET;
case CP_949:
return HANGUL_CHARSET;
case CP_936:
return GB2312_CHARSET;
case CP_950:
return CHINESEBIG5_CHARSET;
case CP_1253:
return GREEK_CHARSET;
case CP_1254:
return TURKISH_CHARSET;
case CP_1255:
return HEBREW_CHARSET;
case CP_1256:
return ARABIC_CHARSET;
case CP_1257:
return BALTIC_CHARSET;
case CP_1258:
return VIETNAMESE_CHARSET;
case CP_874:
return THAI_CHARSET;
case CP_1250:
return EASTEUROPE_CHARSET;
case CP_1251:
return RUSSIAN_CHARSET;
default:
return DEFAULT_CHARSET;
}
}
const char* GetFontFaceFromCodePageNT(WORD codePage)
{
switch( codePage )
{
case CP_932:
return "MS PGothic";
case CP_949:
return "GulimChe";
case CP_936:
return "SimSun";
case CP_950:
return "MingLiU";
case CP_874:
return "Tahoma";
case CP_1252:
return "Arial";
case CP_1256:
return "Tahoma";
case CP_1258:
return "Tahoma";
case CP_65001:
return "Arial";
default:
return "Arial";
}
}
const char* GetFontFaceFromCodePage9x(WORD codePage)
{
switch( codePage )
{
case CP_932:
return "굃굍 굊긕긘긞긏";
case CP_949:
return "굴림체";
case CP_936:
return "芥竟";
case CP_950:
return "꾄ⁿ톱";
case CP_874:
return "Tahoma";
case CP_1252:
return "Arial";
case CP_1256:
return "Tahoma";
case CP_1258:
return "Tahoma";
case CP_65001:
return "Arial";
default:
return "Arial";
}
}
DWORD GetDefaultCodePage()
{
return gs_codePage;
}
const char * GetDefaultFontFace()
{
return gs_fontFace.c_str();
}
const char* GetFontFaceFromCodePage(WORD codePage)
{
LOGFONTA logFont = {};
logFont.lfCharSet = GetCharsetFromCodePage(codePage);
const char* fontFace = GetFontFaceFromCodePage9x(codePage);
HDC hDC = GetDC(NULL);
if(EnumFontFamiliesEx(hDC, &logFont, EnumFontFamExProc, (LPARAM)fontFace, 0) == 0)
{
ReleaseDC(NULL, hDC);
return fontFace;
}
fontFace = GetFontFaceFromCodePageNT(codePage);
if(EnumFontFamiliesEx(hDC, &logFont, EnumFontFamExProc, (LPARAM)fontFace, 0) == 0)
{
ReleaseDC(NULL, hDC);
return fontFace;
}
ReleaseDC(NULL, hDC);
return GetDefaultFontFace();
}
void SetDefaultFontFace(const char* fontFace)
{
gs_fontFace=fontFace;
}
bool SetDefaultCodePage(DWORD codePage)
{
gs_codePage=codePage;
std::string fontFace=GetFontFaceFromCodePage(codePage);
if (fontFace.empty())
return false;
SetDefaultFontFace(fontFace.c_str());
return true;
}
int __base64_get( const int c )
{
if( 'A' <= c && c <= 'Z' )
return c-'A';
if( 'a' <= c && c <= 'z' )
return c - 'a' + 26;
if( '0' <= c && c <= '9' )
return c - '0' + 52;
if( c == '+' )
return 62;
if( c == '/' )
return 63;
if( c == '=' ) // end of line
return -1;
return -2; // non value;
}
void __strcat1(char * str,int i)
{
char result[2];
result[0] = i;
result[1] = NULL;
strcat(str,result);
}
void base64_decode(const char * str,char * resultStr)
{
int nCount=0, i=0, r, result;
int length = strlen(str);
char szDest[5]="";
strcpy(resultStr,"");
while(nCount < length)
{
i=0;
strcpy(szDest, "");
while(nCount<length && i<4) // 4개의 바이트를 얻는다.
{
r = str[nCount++];
result = __base64_get(r);
if(result!=-2)
{
if(result!=-1)
szDest[i++] = result;
else szDest[i++] = '@'; // It's end (64번은 디코딩시 사용되지 않기 때문)
}
}
if(i==4) // 4개의 소스를 모두 얻어냈다. 디코드 시작
{
if( nCount+3 >= length ) // 데이터의 끝에 도달했다.
{
if( szDest[1] == '@' )
{
__strcat1(resultStr,(szDest[0]<<2));
break;
}// exit while loop
else
__strcat1(resultStr,(szDest[0]<<2 | szDest[1]>>4)); // 1 Byte
if( szDest[2] == '@' )
{
__strcat1(resultStr,(szDest[1]<<4));
break;
}
else
__strcat1(resultStr,(szDest[1]<<4 | szDest[2]>>2)); // 2 Byte
if( szDest[3] == '@' )
{
__strcat1(resultStr,(szDest[2]<<6));
break;
}
else
__strcat1(resultStr,(szDest[2]<<6 | szDest[3])); // 3 Byte
}
else
{
__strcat1(resultStr,(szDest[0]<<2 | szDest[1]>>4)); // 1 Byte
__strcat1(resultStr,(szDest[1]<<4 | szDest[2]>>2)); // 2 Byte
__strcat1(resultStr,(szDest[2]<<6 | szDest[3])); // 3 Byte
}
}
}// end of while
for (i = 0; i < strlen(resultStr); i++)
{
char c = resultStr[i];
int xx = i + 5;
resultStr[i] = char(c ^ xx);
}
// E
}

View File

@@ -96,18 +96,5 @@ extern D3DXCOLOR TokenToColor(CTokenVector & rVector);
#define GOTO_CHILD_NODE(TextFileLoader, Index) CTextFileLoader::CGotoChild Child(TextFileLoader, Index);
///////////////////////////////////////////////////////////////////////////////////////////////////
extern int CALLBACK EnumFontFamExProc(CONST LOGFONT* plogFont, CONST TEXTMETRIC* textMetric, DWORD dwWord, LPARAM lParam);
extern int GetCharsetFromCodePage(WORD codePage);
extern const char* GetFontFaceFromCodePageNT(WORD codePage);
extern const char* GetFontFaceFromCodePage9x(WORD codePage);
extern DWORD GetDefaultCodePage();
extern const char * GetDefaultFontFace();
extern const char* GetFontFaceFromCodePage(WORD codePage);
extern void SetDefaultFontFace(const char* fontFace);
extern bool SetDefaultCodePage(DWORD codePage);
extern void base64_decode(const char * str,char * resultStr);
extern DWORD GetMaxTextureWidth();
extern DWORD GetMaxTextureHeight();

View File

@@ -3,34 +3,48 @@
using namespace script;
#define ishan(ch) (((ch) & 0xE0) > 0x90)
#define isnhspace(ch) (!ishan(ch) && isspace(ch))
static const char* Utf8Next(const char* p, const char* end)
{
if (!p || p >= end) return end;
unsigned char c = (unsigned char)*p;
if (c < 0x80) return p + 1;
if ((c >> 5) == 0x6) return (p + 2 <= end) ? p + 2 : end;
if ((c >> 4) == 0xE) return (p + 3 <= end) ? p + 3 : end;
if ((c >> 3) == 0x1E) return (p + 4 <= end) ? p + 4 : end;
// invalid lead byte -> move 1 to avoid infinite loops
return p + 1;
}
extern DWORD GetDefaultCodePage();
static const char* Utf8Prev(const char* base, const char* p)
{
if (!base || !p || p <= base) return base;
const char* q = p - 1;
// move back over continuation bytes 10xxxxxx
while (q > base && (((unsigned char)*q & 0xC0) == 0x80))
--q;
return q;
}
const char* LocaleString_FindChar(const char* base, int len, char test)
{
if (!base)
return NULL;
return nullptr;
DWORD codePage = GetDefaultCodePage();
int pos = 0;
while (pos < len)
{
const char* cur = base + pos;
const char* next = CharNextExA(codePage, cur, 0);
int cur_len = next - cur;
const char* next = Utf8Next(cur, base + len);
int cur_len = int(next - cur);
if (cur_len > 1)
{
pos += cur_len;
}
else if (1 == cur_len)
else if (cur_len == 1)
{
if (*cur == test)
return cur;
++pos;
}
else
@@ -38,36 +52,31 @@ const char* LocaleString_FindChar(const char* base, int len, char test)
break;
}
}
return NULL;
return nullptr;
}
int LocaleString_RightTrim(char* base, int len)
{
DWORD codePage = GetDefaultCodePage();
int pos = len;
while (pos > 0)
{
char* cur = base + pos;
char* prev = CharPrevExA(codePage, base, cur , 0);
int prev_len = cur - prev;
char* prev = (char*)Utf8Prev(base, cur);
int prev_len = int(cur - prev);
if (prev_len != 1)
break;
if (!isspace((unsigned char) *prev) && *prev != '\n' && *prev != '\r')
break;
if (!isspace((unsigned char)*prev) && *prev != '\n' && *prev != '\r')
break;
*prev = '\0';
pos -= prev_len;
}
if (pos > 0)
return pos;
return 0;
return (pos > 0) ? pos : 0;
}
void LocaleString_RightTrim(char* base)
@@ -75,52 +84,10 @@ void LocaleString_RightTrim(char* base)
LocaleString_RightTrim(base, strlen(base));
}
void OLD_rtrim(char* base)
{
if (!base)
return;
DWORD codePage = GetDefaultCodePage();
if (949 == codePage || 936 == codePage)
{
char* end = base + strlen(base) - 1;
while (end != base)
{
if (!isnhspace((unsigned char) *end) && *end != '\n' && *end != '\r' || (end!=base && *((unsigned char*)end-1)>0xa0))
break;
*end = '\0';
end = CharPrevExA(codePage, base, end, 0);
}
}
else
{
char* end = base + strlen(base);
while (end != base)
{
char* prev = CharPrevExA(codePage, base, end, 0);
int prev_len = end - prev;
if (prev_len != 1)
break;
if (!isspace((unsigned char) *prev) && *prev != '\n' && *prev != '\r')
break;
*prev = '\0';
end = prev;
}
}
}
const char* LocaleString_Skip(DWORD codePage, const char* cur)
const char* LocaleString_Skip(const char* cur)
{
int loopCount = 0;
const char* end = cur + strlen(cur);
while (*cur)
{
@@ -130,44 +97,42 @@ const char* LocaleString_Skip(DWORD codePage, const char* cur)
break;
}
const char* next = CharNextExA(codePage, cur, 0);
int cur_len = next - cur;
const char* next = Utf8Next(cur, end);
int cur_len = int(next - cur);
if (cur_len > 1)
{
cur = next;
}
else if (1 == cur_len)
else if (cur_len == 1)
{
if (!isspace((unsigned char) *cur) && *cur != '\n' && *cur != '\r')
if (!isspace((unsigned char)*cur) && *cur != '\n' && *cur != '\r')
return cur;
++cur;
}
else
{
break;
}
}
return cur;
}
bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
{
char szName[32 + 1];
char szValue[64 + 1];
char szName[32 + 1];
char szValue[64 + 1];
int iNameLen = 0;
int iValueLen = 0;
int iNameLen = 0;
int iValueLen = 0;
int iCharLen = 0;
int pos = 0;
bool isValue = false;
bool isValue = false;
DWORD codePage = GetDefaultCodePage();
while (pos < arg_len)
{
while (pos < arg_len)
{
const char* end = c_arg_base + arg_len;
const char* cur = c_arg_base + pos;
const char* next = CharNextExA(codePage, cur, 0);
const char* next = Utf8Next(cur, end);
iCharLen = next - cur;
if (iCharLen > 1)
@@ -180,7 +145,7 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
return false;
}
memcpy(szValue+iValueLen, cur, iCharLen);
memcpy(szValue+iValueLen, cur, iCharLen);
iValueLen += iCharLen;
szValue[iValueLen] = '\0';
}
@@ -191,7 +156,7 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
TraceError("argument name overflow: must be shorter than 32 letters");
return false;
}
memcpy(szName+iNameLen, cur, iCharLen);
memcpy(szName+iNameLen, cur, iCharLen);
iNameLen += iCharLen;
szName[iNameLen] = '\0';
}
@@ -220,11 +185,9 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
{
isValue = true;
}
// 값이 아니고, 이름이 시작되지 않았을 경우 빈칸은 건너 뛴다.
else if (!isValue && iNameLen == 0 && isspace((unsigned char) c))
{
}
// 엔터는 건너 뛴다
else if (c == '\r' || c == '\n')
{
}
@@ -238,9 +201,9 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
return false;
}
memcpy(szValue+iValueLen, cur, iCharLen);
memcpy(szValue+iValueLen, cur, iCharLen);
iValueLen += iCharLen;
szValue[iValueLen] = '\0';
szValue[iValueLen] = '\0';
}
else
{
@@ -249,10 +212,10 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
TraceError("argument name overflow: must be shorter than 32 letters");
return false;
}
memcpy(szName+iNameLen, cur, iCharLen);
memcpy(szName+iNameLen, cur, iCharLen);
iNameLen += iCharLen;
szName[iNameLen] = '\0';
}
szName[iNameLen] = '\0';
}
}
}
else
@@ -261,122 +224,128 @@ bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
}
pos += iCharLen;
}
}
if (iNameLen != 0 && iValueLen != 0)
{
if (iNameLen != 0 && iValueLen != 0)
{
iNameLen = LocaleString_RightTrim(szName, iNameLen);
iValueLen = LocaleString_RightTrim(szValue, iValueLen);
argList.push_back(TArg(szName, szValue));
}
argList.push_back(TArg(szName, szValue));
}
return true;
return true;
}
bool Group::Create(const std::string & stSource)
bool Group::Create(const std::string& stSource)
{
m_cmdList.clear();
if (stSource.empty())
return false;
const char *str_base = stSource.c_str();
if (!str_base || !*str_base)
{
TraceError("Source file has no content");
return false;
}
int str_len = stSource.length();
int str_pos = 0;
DWORD codePage = GetDefaultCodePage();
const char* str_base = stSource.c_str();
if (!str_base || !*str_base)
{
TraceError("Source file has no content");
return false;
}
char box_data[1024 + 1];
const int str_len = (int)stSource.size();
int str_pos = 0;
char box_data[1024 + 1];
static std::string stLetter;
while (str_pos < str_len)
{
TCmd cmd;
while (str_pos < str_len)
{
TCmd cmd;
const char* word = str_base + str_pos;
const char* word_next = CharNextExA(codePage, word, 0);
int word_len = word_next - word;
const char* end = str_base + str_len;
const char* word_next = Utf8Next(word, end);
if (!word_next || word_next <= word)
{
// Invalid UTF-8 sequence or broken helper -> advance 1 byte to avoid infinite loop
word_next = word + 1;
}
const int word_len = (int)(word_next - word);
if (word_len > 1)
{
str_pos += word_len;
{
stLetter.assign(word, word_next);
cmd.name.assign("LETTER");
cmd.argList.push_back(TArg("value", stLetter));
m_cmdList.push_back(cmd);
}
stLetter.assign(word, word_next);
cmd.name.assign("LETTER");
cmd.argList.push_back(TArg("value", stLetter));
m_cmdList.push_back(cmd);
}
else if (word_len == 1)
{
const char cur = *word;
if ('[' == cur)
if (cur == '[')
{
++str_pos;
const char* box_begin = str_base + str_pos;
const char* box_end = LocaleString_FindChar(box_begin, str_len - str_pos, ']');
const char* box_end = LocaleString_FindChar(box_begin, str_len - str_pos, ']');
if (!box_end)
{
TraceError(" !! PARSING ERROR - Syntax Error : %s\n", box_begin);
return false;
}
str_pos += box_end - box_begin + 1;
str_pos += (int)(box_end - box_begin) + 1;
int data_len = 0;
{
const char* data_begin = LocaleString_Skip(codePage, box_begin);
const char* data_begin = LocaleString_Skip(box_begin);
const char* data_end = box_end;
data_len = data_end - data_begin;
data_len = (int)(data_end - data_begin);
if (data_len >= 1024)
{
TraceError(" !! PARSING ERROR - Buffer Overflow : %d, %s\n", data_len, str_base);
return false;
}
memcpy(box_data, data_begin, data_len);
memcpy(box_data, data_begin, (size_t)data_len);
box_data[data_len] = '\0';
data_len = LocaleString_RightTrim(box_data, data_len); // 오른쪽 빈칸 자르기
data_len = LocaleString_RightTrim(box_data, data_len);
}
{
const char* space = LocaleString_FindChar(box_data, data_len, ' ');
if (space) // 인자가 있음
if (space)
{
int name_len = space - box_data;
const int name_len = (int)(space - box_data);
cmd.name.assign(box_data, name_len);
const char* space_next = CharNextExA(codePage, space, 0);
const char* arg = LocaleString_Skip(codePage, space_next);
int arg_len = data_len - (arg - box_data);
const char* data_end = box_data + data_len;
const char* space_next = Utf8Next(space, data_end);
if (!space_next || space_next <= space)
space_next = space + 1;
const char* arg = LocaleString_Skip(space_next);
const int arg_len = (int)(data_len - (arg - box_data));
if (!GetArg(arg, arg_len, cmd.argList))
{
TraceError(" !! PARSING ERROR - Unknown Arguments : %d, %s\n", arg_len, arg);
return false;
}
}
else // 인자가 없으므로 모든 스트링이 명령어다.
else
{
cmd.name.assign(box_data);
cmd.argList.clear();
}
m_cmdList.push_back(cmd);
}
}
@@ -387,51 +356,49 @@ bool Group::Create(const std::string & stSource)
else
{
++str_pos;
{
stLetter.assign(1, cur);
cmd.name.assign("LETTER");
cmd.argList.push_back(TArg("value", stLetter));
m_cmdList.push_back(cmd);
}
stLetter.assign(1, cur);
cmd.name.assign("LETTER");
cmd.argList.push_back(TArg("value", stLetter));
m_cmdList.push_back(cmd);
}
}
else
{
break;
}
}
}
return true;
return true;
}
bool Group::GetCmd(TCmd & cmd)
{
if (m_cmdList.empty())
return false;
if (m_cmdList.empty())
return false;
cmd = m_cmdList.front();
m_cmdList.pop_front();
return true;
cmd = m_cmdList.front();
m_cmdList.pop_front();
return true;
}
bool Group::ReadCmd(TCmd & cmd)
{
if (m_cmdList.empty())
return false;
if (m_cmdList.empty())
return false;
cmd = m_cmdList.front();
return true;
cmd = m_cmdList.front();
return true;
}
std::string & Group::GetError()
{
return m_stError;
return m_stError;
}
void Group::SetError(const char * c_pszError)
{
m_stError.assign(c_pszError);
m_stError.assign(c_pszError);
}
Group::Group()

View File

@@ -6,89 +6,69 @@
namespace script
{
typedef struct SArgumet
{
SArgumet(const std::string& c_stName, const std::string& c_stValue)
{
strName = c_stName;
strValue = c_stValue;
}
typedef struct SArgumet
{
SArgumet(const std::string& c_stName, const std::string& c_stValue)
{
strName = c_stName;
strValue = c_stValue;
}
SArgumet(const SArgumet& c_arg)
{
strName = c_arg.strName;
strValue = c_arg.strValue;
}
}
void operator=(const SArgumet& c_arg)
{
strName = c_arg.strName;
strValue = c_arg.strValue;
}
std::string strName;
std::string strValue;
} TArg;
typedef std::list<TArg> TArgList;
typedef struct SCmd
{
std::string name;
TArgList argList;
}
SCmd()
{}
std::string strName;
std::string strValue;
} TArg;
typedef std::list<TArg> TArgList;
typedef struct SCmd
{
std::string name;
TArgList argList;
SCmd() {}
SCmd(const SCmd& c_cmd)
{
name = c_cmd.name;
argList = c_cmd.argList;
}
void operator=(const SCmd& c_cmd)
{
name = c_cmd.name;
argList = c_cmd.argList;
}
} TCmd;
class Group
{
} TCmd;
class Group
{
public:
Group();
~Group();
public:
/** 스트링으로 부터 스크립트 그룹을 만든다.
*
* 실패하면 GetError 메소드로 확인할 수 있다.
*
* @param stSource 이 스트링으로 부터 그룹이 만들어 진다.
* @return 성공시 true, 실패하면 false
*/
bool Create(const std::string & stSource);
/** 명령어를 받는 메소드
*
* @param cmd 성공시에 이 구조체로 명령어가 복사 된다.
* @return 명령어가 남아 있다면 true, 없다면 false
*/
bool GetCmd(TCmd & cmd);
bool Create(const std::string & stSource);
bool GetCmd(TCmd & cmd);
bool ReadCmd(TCmd & cmd);
std::string & GetError();
/*
명령어를 가져오되 꺼내지는 않는다.
*/
bool ReadCmd(TCmd & cmd);
/** 에러를 출력 받는 메소드
*
* @return stError 이 곳으로 에러가 출력 된다.
*/
std::string & GetError();
private:
void SetError(const char *str);
bool GetArg(const char * c_atr_base, int arg_len, TArgList & argList);
std::string m_stError;
std::list<TCmd> m_cmdList;
};
}
void SetError(const char *str);
bool GetArg(const char * c_atr_base, int arg_len, TArgList & argList);
std::string m_stError;
std::list<TCmd> m_cmdList;
};
}
#endif