RichViewEdit.RTFReaderProperties属性UnicodeMode设置为rvruOnlyUnicode,再把RVStyle.TextStyle的所有字体设定的Unicode设为True,即OK。
在WinXP下用全拼输入法进行了测试,确实出现标点符号(","等)无法正确输入显示的问题,但用智能ABC输入法、紫光拼音输入法、微软拼音输入法等测试,却发现是正常的,五笔输入法没有安装,未进行测试。经过仔细研究分析和用SPY截获RichViewEdit消息的结果,发现问题出现在全拼输入法输入中文标点符号时,系统发送给的消息与其他输入法不同,见下面:
【全拼输入法】
<00005> 007B02EC P WM_KEYDOWN nVirtKey:VK_PROCESSKEY cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 007B02EC P WM_CHAR chCharCode:'.' (172) (lead) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00007> 007B02EC P WM_CHAR chCharCode:'' (163) (trail) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00008> 007B02EC P WM_KEYUP nVirtKey:00BC cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
【智能ABC输入法】
<00017> 007B02EC P WM_KEYDOWN nVirtKey:VK_PROCESSKEY cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00018> 007B02EC P WM_IME_COMPOSITION chDBCS:0000 fFlags:1FBF
<00019> 007B02EC P WM_IME_ENDCOMPOSITION
<00020> 007B02EC P WM_KEYUP nVirtKey:00BC cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
全拼输入法的中文汉字发送的消息与智能ABC输入法的中文汉字、中文标点发送的消息相同,但中文标点是将低字节与高字节作为两个WM_CHAR消息发送的,而RichView在对WM_CHAR消息的处理时存在一定的问题,就导致了不能正确输入显示中文标点。下面是处理WM_CHAR消息之后调用的代码(RVERVData.pas):
procedure TRVEditRVData.KeyPress(var Key: Char);
var Text: String;
begin
if (GetRVStyle=nil) or (PartialSelectedItem<>nil) or not CanDelete then begin
Beep;
exit;
end;
{$IFNDEF RVDONOTUSEUNICODE}
if GetRVStyle.TextStyles[GetActualCurStyleNo].Unicode then begin
Text := RVU_KeyToUnicode(Key); // ****
if Length(Text)=0 then exit;
end
else
{$ENDIF}
Text := Key;
InsertTextTyping(Text);
end;
问题就出在标记为"****"的行,由于一个标点如","(0xACA3)被当作两个字符发送,这里的Key在第一次是0xA3,而第二次是0xAC,RVU_KeyToUnicode实际上就是调用MultiByteToWideChar进行Unicode转换的,它对0xA3、0xAC这样一个中文标点被分割成的两个字符的分别单独转换结果和实际的输入就不符了,在转换之后都成了0x0000(WideChar),插入之后就不能正常显示的。因此,要解决这个问题,关键就在于不能把中文标点的低字节、高字节作为两个字符分别转换,而是应该加在一起一次转换,这样插入的结果才正确。为了验证上述的分析结果,我将这里的代码作了如下更改:
{ ================================== }
{ 2004-11-17 Added by LiChengbin }
var FirstChar: Char;
{ ================================== }
procedure TRVEditRVData.KeyPress(var Key: Char);
var Text: String;
begin
if (GetRVStyle=nil) or (PartialSelectedItem<>nil) or not CanDelete then begin
Beep;
exit;
end;
{$IFNDEF RVDONOTUSEUNICODE}
if GetRVStyle.TextStyles[GetActualCurStyleNo].Unicode then begin
{ ================================== }
{ 2004-11-17 Modified by LiChengbin }
//Text := RVU_KeyToUnicode(Key);
if (FirstChar = #0) and IsDBCSLeadByte(Byte(Key)) then
begin
FirstChar := Key;
Exit;
end;
if FirstChar <> #0 then
Text := RVU_KeyToUnicode(FirstChar + Key)
else
Text := RVU_KeyToUnicode(Key);
FirstChar := #0;
{ ================================== }
if Length(Text)=0 then exit;
end
else
{$ENDIF}
Text := Key;
InsertTextTyping(Text);
end;
再次进行了测试,OK! 中文标点可以正确输入并显示了。
【全拼输入法】
<00005> 007B02EC P WM_KEYDOWN nVirtKey:VK_PROCESSKEY cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 007B02EC P WM_CHAR chCharCode:'.' (172) (lead) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00007> 007B02EC P WM_CHAR chCharCode:'' (163) (trail) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00008> 007B02EC P WM_KEYUP nVirtKey:00BC cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
【智能ABC输入法】
<00017> 007B02EC P WM_KEYDOWN nVirtKey:VK_PROCESSKEY cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00018> 007B02EC P WM_IME_COMPOSITION chDBCS:0000 fFlags:1FBF
<00019> 007B02EC P WM_IME_ENDCOMPOSITION
<00020> 007B02EC P WM_KEYUP nVirtKey:00BC cRepeat:1 ScanCode:33 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
全拼输入法的中文汉字发送的消息与智能ABC输入法的中文汉字、中文标点发送的消息相同,但中文标点是将低字节与高字节作为两个WM_CHAR消息发送的,而RichView在对WM_CHAR消息的处理时存在一定的问题,就导致了不能正确输入显示中文标点。下面是处理WM_CHAR消息之后调用的代码(RVERVData.pas):
procedure TRVEditRVData.KeyPress(var Key: Char);
var Text: String;
begin
if (GetRVStyle=nil) or (PartialSelectedItem<>nil) or not CanDelete then begin
Beep;
exit;
end;
{$IFNDEF RVDONOTUSEUNICODE}
if GetRVStyle.TextStyles[GetActualCurStyleNo].Unicode then begin
Text := RVU_KeyToUnicode(Key); // ****
if Length(Text)=0 then exit;
end
else
{$ENDIF}
Text := Key;
InsertTextTyping(Text);
end;
问题就出在标记为"****"的行,由于一个标点如","(0xACA3)被当作两个字符发送,这里的Key在第一次是0xA3,而第二次是0xAC,RVU_KeyToUnicode实际上就是调用MultiByteToWideChar进行Unicode转换的,它对0xA3、0xAC这样一个中文标点被分割成的两个字符的分别单独转换结果和实际的输入就不符了,在转换之后都成了0x0000(WideChar),插入之后就不能正常显示的。因此,要解决这个问题,关键就在于不能把中文标点的低字节、高字节作为两个字符分别转换,而是应该加在一起一次转换,这样插入的结果才正确。为了验证上述的分析结果,我将这里的代码作了如下更改:
{ ================================== }
{ 2004-11-17 Added by LiChengbin }
var FirstChar: Char;
{ ================================== }
procedure TRVEditRVData.KeyPress(var Key: Char);
var Text: String;
begin
if (GetRVStyle=nil) or (PartialSelectedItem<>nil) or not CanDelete then begin
Beep;
exit;
end;
{$IFNDEF RVDONOTUSEUNICODE}
if GetRVStyle.TextStyles[GetActualCurStyleNo].Unicode then begin
{ ================================== }
{ 2004-11-17 Modified by LiChengbin }
//Text := RVU_KeyToUnicode(Key);
if (FirstChar = #0) and IsDBCSLeadByte(Byte(Key)) then
begin
FirstChar := Key;
Exit;
end;
if FirstChar <> #0 then
Text := RVU_KeyToUnicode(FirstChar + Key)
else
Text := RVU_KeyToUnicode(Key);
FirstChar := #0;
{ ================================== }
if Length(Text)=0 then exit;
end
else
{$ENDIF}
Text := Key;
InsertTextTyping(Text);
end;
再次进行了测试,OK! 中文标点可以正确输入并显示了。