//实现中文输入框的类
#include "CImeEditBox.h"
//////////////////////////////////////////////////////////////////////////
//计算光标左边是否为DBCS字符(如汉字)
//相关函数:IsDBCSLeadByte
BOOL DBCSTestLeft(const char *str, int cursor)
{
if(cursor > 0)
{
if(cursor > 1)
{
if(str[cursor - 2] < 0 && str[cursor - 1] < 0)
return TRUE;
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//计算光标右边是否为DBCS字符(如汉字)
BOOL DBCSTestRight(const char *str, int cursor)
{
int slen = strlen(str);
if(cursor < slen)
{
if(cursor < slen - 1)
{
if(str[cursor + 1] < 0 && str[cursor] < 0)
return TRUE;
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//测试中英文混合字串
bool DBCSTestString(const char *str, int slen)
{
bool flag = false;
for(int i = 0; i < slen; i++)
if(str[i] < 0) flag = !flag;
return flag;
}
//////////////////////////////////////////////////////////////////////////
//基于第一个字符的,以字符为单位,获得当前光标位置
void CImeEditBox::GetCursorPos(int *posX, int *posY)
{
*posX = m_cursor - m_lineID[m_curLine].startPos;
*posY = m_curLine;
}
//////////////////////////////////////////////////////////////////////////
//内部模拟设置光标的位置
void CImeEditBox::SetCursorPos(int posX, int posY)
{
if(posY < 0) m_curLine = 0;
else if(posY >= m_numLines) m_curLine = m_numLines - 1;
else m_curLine = posY;
int curLen = m_lineID[m_curLine].endPos - m_lineID[m_curLine].startPos + 1;//当前的串长
if(posX > curLen - 1)
{
m_cursor = m_lineID[m_curLine].endPos;
if(m_curLine == m_numLines - 1) m_cursor++;//在最后要后移
if(curLen > 1) CalcReturn(strlen(m_Text));
}
else if(posX >= curLen - 1) m_cursor = m_lineID[m_curLine].endPos;
else if(posX <= 0) m_cursor = m_lineID[m_curLine].startPos;
else m_cursor = m_lineID[m_curLine].startPos + posX;
if(DBCSTestString(m_Text + m_lineID[m_curLine].startPos, m_cursor - m_lineID[m_curLine].startPos))
m_cursor--;//如果分开了汉字那么左移
if(m_cursor < 0) m_cursor = 0;
}
//////////////////////////////////////////////////////////////////////////
//遇到回车字符时前移1格(根据多次测试经验总结的,确实需要)
void CImeEditBox::CalcReturn(int slen)
{
if(m_cursor > 1 && m_cursor < slen)
{
if((m_Text[m_cursor - 1] == '\r') && (m_Text[m_cursor - 2] != '\r') && (m_Text[m_cursor] != '\r'))
m_cursor--;
}
}
//////////////////////////////////////////////////////////////////////////
//计算正确的光标位置和每行起始字符的位置、遇到回车字符换行
//这个算是本程序的核心吧
void CImeEditBox::CalcLineInfo()
{
int slen = strlen(m_Text);
int dbcs = 0, py = 1, chCnt = 0;
// ZeroMemory(m_lineID, TEXT_LEN);
m_lineID[0].startPos = 0; //第一行从0开始
for(int i = 0; i <= slen; i++)
{
if(m_cursor == i) m_curLine = py - 1;
if(i == slen) break;
if(m_Text[i] < 0)//小于0为汉字的半个字符
{
if(dbcs == 0)dbcs = 1;
else if(dbcs == 1)dbcs = 2;
else dbcs = 1;
}
else dbcs = 0;
if(m_Text[i] == 13)//回车字符
{
chCnt = 0;
m_lineID[py].startPos = i + 1;
m_lineID[py - 1].endPos = i;
py++;
}
else
{
chCnt++;
if(chCnt == m_numX)
{
chCnt = 0;
if(dbcs == 1)
{
m_lineID[py].startPos = i;
m_lineID[py - 1].endPos = i - 1;
chCnt++;
}
else
{
m_lineID[py].startPos = i + 1;
m_lineID[py - 1].endPos = i;
}
py++;
}
}
}
m_lineID[py - 1].endPos = slen - 1;
if(m_curLine < 0)m_curLine = 0;
m_numLines = py;
CalcStartLine();
}
//////////////////////////////////////////////////////////////////////////
//计算起始行数
void CImeEditBox::CalcStartLine()
{
int ln = m_curLine - m_startLine;
if(ln >= m_numY) m_startLine = m_curLine - m_numY + 1;
else if(ln < 0) m_startLine = m_curLine;
}
//////////////////////////////////////////////////////////////////////////
//重设选择位置
void CImeEditBox::ResetSelCur()
{
m_selcur = m_cursor;
m_selLine = m_curLine;
}
//////////////////////////////////////////////////////////////////////////
//内部使用,删除一个ASCII字符或DBCS字符,拦截等操作放在OnBackspace
void CImeEditBox::DelOne()
{
char tmp[TEXT_LEN], tmp2[TEXT_LEN];
sprintf(tmp2, "%s", m_Text + m_cursor);
if(DBCSTestLeft(m_Text, m_cursor))//如果左边是汉字那么删除2个字符
{
m_cursor -= 2;
}
else if(m_cursor > 0)m_cursor -= 1;
sprintf(tmp, "%s", m_Text);
tmp[m_cursor] = '\0';
sprintf(m_Text, "%s%s", tmp, tmp2);//重组
}
//////////////////////////////////////////////////////////////////////////
//内部使用,删除选择的字符
void CImeEditBox::DelSel()
{
char tmp[TEXT_LEN], tmp2[TEXT_LEN];
if(m_cursor > m_selcur)
{
sprintf(tmp2, "%s", m_Text + m_cursor);//选择的右边
sprintf(tmp, "%s", m_Text);
tmp[m_selcur] = '\0';//选择的左边
m_cursor = m_selcur;
}
else if(m_cursor < m_selcur)
{
sprintf(tmp2, "%s", m_Text + m_selcur);//选择的右边
sprintf(tmp, "%s", m_Text);
tmp[m_cursor] = '\0';//选择的左边
}
else return;//对于没有选择的不操作
sprintf(m_Text, "%s%s", tmp, tmp2);//重组
}
//////////////////////////////////////////////////////////////////////////
//内部使用,添加一个字符
void CImeEditBox::AddOne(char ch)
{
//把字符串拆成两部分
char tmp[TEXT_LEN], tmp2[TEXT_LEN];
sprintf(tmp, "%s", m_Text);
//tmp[m_cursor] = '\0';
sprintf(tmp2, "%s", m_Text + m_cursor);
//重新组合
sprintf(m_Text, "%s%c%s", tmp, ch, tmp2);
m_cursor++;//光标往后移动1格
}
//////////////////////////////////////////////////////////////////////////
//处理删除的消息
void CImeEditBox::OnDel()
{
if(!m_CanEdit)return;
m_DrawCurWait = DRAW_CUR_WAIT;//让光标显示出来
if(m_cursor == m_selcur)
DelOne();
else DelSel();
ResetSelCur();
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//处理输入的消息
void CImeEditBox::OnChar(char ch)
{
if(!m_CanEdit)return;
m_DrawCurWait = DRAW_CUR_WAIT;//让光标显示出来
if(ch == 8) //删除键值为8
{
OnDel();
return;
}
if(ch == 13 && m_NoRet) //回车键值为13('\r')
return;
if(m_cursor != m_selcur)
DelSel();
AddOne(ch);
ResetSelCur();
//重新计算格式
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//计时器,用于光标的闪烁
void CImeEditBox::OnTimer()
{
m_DrawCurWait--;
if(m_DrawCurWait < -DRAW_CUR_WAIT)
m_DrawCurWait = DRAW_CUR_WAIT;
}
//////////////////////////////////////////////////////////////////////////
//光标左移
void CImeEditBox::OnMoveLeft()
{
m_DrawCurWait = DRAW_CUR_WAIT;
if(DBCSTestLeft(m_Text, m_cursor))
{
m_cursor -= 2;
}
else if(m_cursor > 0) m_cursor -= 1;
ResetSelCur();
//重新计算格式
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//光标右移
void CImeEditBox::OnMoveRight()
{
m_DrawCurWait = DRAW_CUR_WAIT;
if(DBCSTestRight(m_Text, m_cursor))
{
m_cursor += 2;
}
else if(m_Text[m_cursor] != '\0') m_cursor += 1;
ResetSelCur();
//重新计算格式
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//光标上移
void CImeEditBox::OnMoveUp()
{
m_DrawCurWait = DRAW_CUR_WAIT;
int pX, pY;
GetCursorPos(&pX, &pY);
SetCursorPos(pX, pY - 1);
ResetSelCur();
//重新计算格式
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//光标下移
void CImeEditBox::OnMoveDown()
{
m_DrawCurWait = DRAW_CUR_WAIT;
int pX, pY;
GetCursorPos(&pX, &pY);
SetCursorPos(pX, pY + 1);
ResetSelCur();
//重新计算格式
CalcLineInfo();
}
//////////////////////////////////////////////////////////////////////////
//内部的测试鼠标点击的函数
void CImeEditBox::MouseClick(int mx, int my)
{
m_
评论13