在非UNICODE的Delphi 7中使用TNT控件来实现WideString/UNICODE的Delphi VirtualKey。

时间:2020-12-19 08:18:14

I am using this code to convert a virtual key to WideString:

我正在使用这段代码将一个虚拟密钥转换为WideString:

function VKeytoWideString (Key : Word) : WideString; var  WBuff         : array [0..255] of WideChar;  KeyboardState : TKeyboardState;  UResult       : Integer;begin  Result := ''; GetKeyBoardState (KeyboardState);  ZeroMemory(@WBuff[0], SizeOf(WBuff)); UResult := ToUnicode(key, MapVirtualKey(key, 0), KeyboardState, WBuff, Length(WBuff), 0);  if UResult > 0 then  SetString(Result, WBuff, UResult) else if UResult = -1 then  Result := WBuff;end; 

It works fine on my PC, but on a Chinese PC I get this:

它在我的电脑上工作得很好,但是在中国的电脑上我得到了这个:

foo http://img341.imageshack.us/img341/9506/clipboard01l.png

foo http://img341.imageshack.us/img341/9506/clipboard01l.png

It converts the Chinese chars to Hanyu Pinyin. I think the function actually returns the raw input of the keyboard and not what the user actually wants to type in.

它把中国的字符转换成汉语拼音。我认为这个函数实际上返回的是键盘的原始输入,而不是用户真正想要输入的内容。

How should I handle this?

我该如何处理?

2 个解决方案

#1


2  

As per the comments, here is an example of how you can avoid the problem by handling KeyPress events instead of manually converting KeyDown events. The TNT controls don't provide a WideChar KeyPress event, but it's fairly easy to add. Ideally, you should not put the extensions to TTntMemo and TTntForm in derived classes as I've done here, but instead modify the TNT source code.

根据评论,这里有一个示例,说明如何通过处理KeyPress事件而不是手动转换KeyDown事件来避免问题。TNT控件不提供WideChar KeyPress事件,但是很容易添加。

The form contains two TTntMemo controls. Pressing keys in the first will log the events in the second.

该表单包含两个TTntMemo控件。按第一个键将记录第二个事件。

unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, TntForms, StdCtrls, TntStdCtrls;type  TKeyPressWEvent = procedure(Sender: TObject; var Key: WideChar) of object;  TTntMemo = class(TntStdCtrls.TTntMemo)  private    FOnKeyPressW: TKeyPressWEvent;    procedure WMChar(var Msg: TWMChar); message WM_CHAR;  protected    function DoKeyPressW(var Message: TWMKey): Boolean;    procedure KeyPressW(var Key: WideChar);  published    property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;  end;  TTntForm = class(TntForms.TTntForm)  private    FOnKeyPressW: TKeyPressWEvent;    procedure WMChar(var Msg: TWMChar); message WM_CHAR;  protected    function DoKeyPressW(var Message: TWMKey): Boolean;    procedure KeyPressW(var Key: WideChar);  published    property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;  end;  TForm1 = class(TTntForm)    TntMemo1: TTntMemo;    TntMemo2: TTntMemo;    procedure FormCreate(Sender: TObject);    procedure FormKeyPressW(Sender: TObject; var Key: WideChar);    procedure TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);  end;var  Form1: TForm1;implementationuses  TntControls;{$R *.dfm}type  TWinControlAccess = class(TWinControl);  TTntFormAccess = class(TTntForm);function TntControl_DoKeyPressW(Self: TWinControl; var Message: TWMKey;  KeyPressW: Pointer): Boolean;type  TKeyPressWProc = procedure(Self: TWinControl; var Key: WideChar);var  Form: TCustomForm;  Ch: WideChar;begin  Result := True;  Form := GetParentForm(Self);  if (Form <> nil) and (Form <> Self) and Form.KeyPreview then  begin    if (Form is TTntForm) and TTntFormAccess(Form).DoKeyPressW(Message) then Exit;    if TWinControlAccess(Form).DoKeyPress(Message) then Exit;  end;  if not (csNoStdEvents in Self.ControlStyle) then  begin    Ch := GetWideCharFromWMCharMsg(Message);    TKeyPressWProc(KeyPressW)(Self, Ch);    SetWideCharForWMCharMsg(Message, Ch);    if Ch = #0 then Exit;  end;  Result := False;end;{ TTntMemo }function TTntMemo.DoKeyPressW(var Message: TWMKey): Boolean;begin  Result := TntControl_DoKeyPressW(Self, Message, @TTntMemo.KeyPressW);end;procedure TTntMemo.KeyPressW(var Key: WideChar);begin  if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);end;procedure TTntMemo.WMChar(var Msg: TWMChar);begin  if not DoKeyPressW(Msg) then inherited;end;{ TTntForm }function TTntForm.DoKeyPressW(var Message: TWMKey): Boolean;begin  Result := TntControl_DoKeyPressW(Self, Message, @TTntForm.KeyPressW);end;procedure TTntForm.KeyPressW(var Key: WideChar);begin  if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);end;procedure TTntForm.WMChar(var Msg: TWMChar);begin  if not DoKeyPressW(Msg) then inherited;end;{ TForm1 }procedure TForm1.FormCreate(Sender: TObject);begin  Self.OnKeyPressW := FormKeyPressW;  TntMemo1.OnKeyPressW := TntMemo1KeyPressW;end;procedure TForm1.FormKeyPressW(Sender: TObject; var Key: WideChar);begin  TntMemo2.Lines.Add(WideString('FormKeyPress: ') + Key);end;procedure TForm1.TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);begin  TntMemo2.Lines.Add(WideString('TntMemo1KeyPress: ') + Key);end;end.

#2


1  

I haven’t got much experience with typing Chinese either, but I suspect this is the IME (Input Method Editor) kicking in. That’s what allows Chinese users to type in pinyin, which will then be translated into ideographic characters (otherwise, you’d need a keyboard with some 1000+ keys...)

我也没有多少输入中文的经验,但我怀疑这是输入方法编辑器。这就是让中国用户输入拼音的原因,拼音将被翻译成表意文字(否则的话,你需要一个有1000多个按键的键盘……)

The Virtual Keycodes are directly related to the keyboard, and so will, of necessity, only correspond to the entered keys. So your function works fine: it converts a VKEY code to a WideChar. To do what you want, you’ll have to write a second function, which would convert pinyin to characters.

虚拟密钥代码与键盘直接相关,因此必然只与输入的密钥对应。所以您的函数工作得很好:它将VKEY代码转换为WideChar。要做你想做的,你必须写第二个函数,它将拼音转换成字符。

If you want to do this specifically for Chinese, I’ll bet there’s functions for doing this out there. If you want to make it more generic, and independent of locale and language, then perhaps it’s possible to interface with the IME for the relevant TMemo, but if so, I haven’t got a clue. My best guess would be to search MSDN for IME.

如果你想专门为中文做这个,我敢打赌有函数可以做这个。如果您想使它更通用,并且独立于语言环境和语言,那么可能可以为相关的TMemo与IME进行交互,但如果是这样,我就不知道了。我的最佳猜测是为IME搜索MSDN。

But, to echo hvd’s comment: what do you want to accomplish here?

但是,为了回应hvd的评论:你想在这里完成什么?

Wouldn’t it be easier to just copy the text of the TMemo?

复制TMemo的文本不是更简单吗?

#1


2  

As per the comments, here is an example of how you can avoid the problem by handling KeyPress events instead of manually converting KeyDown events. The TNT controls don't provide a WideChar KeyPress event, but it's fairly easy to add. Ideally, you should not put the extensions to TTntMemo and TTntForm in derived classes as I've done here, but instead modify the TNT source code.

根据评论,这里有一个示例,说明如何通过处理KeyPress事件而不是手动转换KeyDown事件来避免问题。TNT控件不提供WideChar KeyPress事件,但是很容易添加。

The form contains two TTntMemo controls. Pressing keys in the first will log the events in the second.

该表单包含两个TTntMemo控件。按第一个键将记录第二个事件。

unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, TntForms, StdCtrls, TntStdCtrls;type  TKeyPressWEvent = procedure(Sender: TObject; var Key: WideChar) of object;  TTntMemo = class(TntStdCtrls.TTntMemo)  private    FOnKeyPressW: TKeyPressWEvent;    procedure WMChar(var Msg: TWMChar); message WM_CHAR;  protected    function DoKeyPressW(var Message: TWMKey): Boolean;    procedure KeyPressW(var Key: WideChar);  published    property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;  end;  TTntForm = class(TntForms.TTntForm)  private    FOnKeyPressW: TKeyPressWEvent;    procedure WMChar(var Msg: TWMChar); message WM_CHAR;  protected    function DoKeyPressW(var Message: TWMKey): Boolean;    procedure KeyPressW(var Key: WideChar);  published    property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;  end;  TForm1 = class(TTntForm)    TntMemo1: TTntMemo;    TntMemo2: TTntMemo;    procedure FormCreate(Sender: TObject);    procedure FormKeyPressW(Sender: TObject; var Key: WideChar);    procedure TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);  end;var  Form1: TForm1;implementationuses  TntControls;{$R *.dfm}type  TWinControlAccess = class(TWinControl);  TTntFormAccess = class(TTntForm);function TntControl_DoKeyPressW(Self: TWinControl; var Message: TWMKey;  KeyPressW: Pointer): Boolean;type  TKeyPressWProc = procedure(Self: TWinControl; var Key: WideChar);var  Form: TCustomForm;  Ch: WideChar;begin  Result := True;  Form := GetParentForm(Self);  if (Form <> nil) and (Form <> Self) and Form.KeyPreview then  begin    if (Form is TTntForm) and TTntFormAccess(Form).DoKeyPressW(Message) then Exit;    if TWinControlAccess(Form).DoKeyPress(Message) then Exit;  end;  if not (csNoStdEvents in Self.ControlStyle) then  begin    Ch := GetWideCharFromWMCharMsg(Message);    TKeyPressWProc(KeyPressW)(Self, Ch);    SetWideCharForWMCharMsg(Message, Ch);    if Ch = #0 then Exit;  end;  Result := False;end;{ TTntMemo }function TTntMemo.DoKeyPressW(var Message: TWMKey): Boolean;begin  Result := TntControl_DoKeyPressW(Self, Message, @TTntMemo.KeyPressW);end;procedure TTntMemo.KeyPressW(var Key: WideChar);begin  if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);end;procedure TTntMemo.WMChar(var Msg: TWMChar);begin  if not DoKeyPressW(Msg) then inherited;end;{ TTntForm }function TTntForm.DoKeyPressW(var Message: TWMKey): Boolean;begin  Result := TntControl_DoKeyPressW(Self, Message, @TTntForm.KeyPressW);end;procedure TTntForm.KeyPressW(var Key: WideChar);begin  if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);end;procedure TTntForm.WMChar(var Msg: TWMChar);begin  if not DoKeyPressW(Msg) then inherited;end;{ TForm1 }procedure TForm1.FormCreate(Sender: TObject);begin  Self.OnKeyPressW := FormKeyPressW;  TntMemo1.OnKeyPressW := TntMemo1KeyPressW;end;procedure TForm1.FormKeyPressW(Sender: TObject; var Key: WideChar);begin  TntMemo2.Lines.Add(WideString('FormKeyPress: ') + Key);end;procedure TForm1.TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);begin  TntMemo2.Lines.Add(WideString('TntMemo1KeyPress: ') + Key);end;end.

#2


1  

I haven’t got much experience with typing Chinese either, but I suspect this is the IME (Input Method Editor) kicking in. That’s what allows Chinese users to type in pinyin, which will then be translated into ideographic characters (otherwise, you’d need a keyboard with some 1000+ keys...)

我也没有多少输入中文的经验,但我怀疑这是输入方法编辑器。这就是让中国用户输入拼音的原因,拼音将被翻译成表意文字(否则的话,你需要一个有1000多个按键的键盘……)

The Virtual Keycodes are directly related to the keyboard, and so will, of necessity, only correspond to the entered keys. So your function works fine: it converts a VKEY code to a WideChar. To do what you want, you’ll have to write a second function, which would convert pinyin to characters.

虚拟密钥代码与键盘直接相关,因此必然只与输入的密钥对应。所以您的函数工作得很好:它将VKEY代码转换为WideChar。要做你想做的,你必须写第二个函数,它将拼音转换成字符。

If you want to do this specifically for Chinese, I’ll bet there’s functions for doing this out there. If you want to make it more generic, and independent of locale and language, then perhaps it’s possible to interface with the IME for the relevant TMemo, but if so, I haven’t got a clue. My best guess would be to search MSDN for IME.

如果你想专门为中文做这个,我敢打赌有函数可以做这个。如果您想使它更通用,并且独立于语言环境和语言,那么可能可以为相关的TMemo与IME进行交互,但如果是这样,我就不知道了。我的最佳猜测是为IME搜索MSDN。

But, to echo hvd’s comment: what do you want to accomplish here?

但是,为了回应hvd的评论:你想在这里完成什么?

Wouldn’t it be easier to just copy the text of the TMemo?

复制TMemo的文本不是更简单吗?