Board logo

Subject: 实现Delphi输入法,帮助懒人 [Print This Page]

Author: internetzs    Time: 2004-10-2 11:46     Subject: 实现Delphi输入法,帮助懒人

前段时间看到有个叫Delphi输入法的程序,很有创意,但使用不方便。
所以我想实现类似的在IDE实现代码输入助手。 下面为前期无IDE的测试程序:
http://www.internetoa.com/uploadfiles/DelphiPut_Test.rar  (需要D7运行包)
效果: http://www.internetoa.com/uploadfiles/DelphiPut.png


问题:怎样捕捉EditWindow的OnKeyDown事件?


我尝试用下面方式:
找到EditWindow,然后挂接OnKeydown或WindowProc,但WM_KEYDOWN都不发生。挂接在EditControl上情况也一样。

但如果挂接事件WM_KEYUP是正常发生的,因为我在发送IDE前要修改按下的键,所以才要捕获KeyDown。


下面是挂接KeyUp代码,正常的:

   for i := 0 to Screen.CustomFormCount - 1 do
    if IsIdeEditorForm(Screen.CustomForms) then
    begin
      EditorForm := Screen.CustomForms;
      EditControl := EditorForm.FindComponent(EditControlName) as TWinControl;
      Assert(Assigned(EditControl));
      Assert(EditControl.ClassNameIs(EditControlClassName));

      EditorForm.KeyPreview:= True;

      OldKeyUpEvent:= EditorForm.OnKeyUp;
      EditorForm.OnKeyUp:= EditWindowKeyUp;

//           OldEditControlWndProc:= EditorForm.WindowProc;
//      EditorForm.WindowProc:= EditControlWndProc;

。。。

procedure TfrmMain.EditWindowKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
    MessageBeep(MB_ICONSTOP);
    if Assigned(OldKeyUpEvent) then
        OldKeyUpEvent(Sender, Key, Shift);
end;

完成后,我会将把源代码公开到此,我对IDE缺少经验,那位高手指点条明路?

[ 本贴由 internetzs 于 2004-10-2 11:52 最后编辑 ]
Author: internetzs    Time: 2004-10-4 17:21

差不多完成了,下面是测试版

本人只是在WinXP + SP1 + Delphi7测试通过

效果:http://www.internetoa.com/uploadfiles/DelphPut.gif
下载:http://www.internetoa.com/uploadfiles/DelphiPut.rar
Author: zjy    Time: 2004-10-7 20:43

效果看起来还不错:)

不知输入法里的词汇是否支持从即时编译中获得?在 GExperts 中提供了一个代码纠错功能,里面有个方法可以从 IDE 中取得当前项目即时语法分析后的有效符号表,可以参考一下。

CnPack 最近开发工作不少,如果你这个工具完善后愿意加到 CnWizards 中来,无限欢迎!!
Author: internetzs    Time: 2004-10-21 16:10

源代码: http://www.internetoa.com/uploadfiles/DelphiPut.rar
知道的问题:在Delphi编辑时,在某些特殊区别会报Code completion错误,
我暂时找不到解决的办法。只能重启IDE.
Author: leeon    Time: 2004-10-26 09:47

我想Hook会帮你解决这个问题。如果你的汇编能看懂一些,

可以从看雪这里下载ApiList:

http://www.pediy.com/tools/Compilers.htm

ApiList这个软件,运行之后不管在哪个编辑框都可以。
Author: internetzs    Time: 2004-10-26 11:37

* 修正了list out of index bonus(1)的错误
* 修正了AV非法访问内存错误

http://www.internetoa.com/uploadfiles/DelphiPut.rar
Author: zjy    Time: 2004-10-26 22:58

试用了一下,感觉不错,做得很细致!

分析其源码,建议以下地方可以再改进一下:
1、键盘事件挂接可以改用 SetWindowsHookEx 建一个键盘钩子,当前的挂接方式有时候不起作用。
2、Delphi自己的自动完成窗口弹出时,键盘焦点还在 EditWindow 上,而输入助手窗口弹出时自己获得了焦点。
Author: felixsun    Time: 2004-11-5 10:29

如果支持D6就好了
Author: zjy    Time: 2004-11-6 09:07

我已经把这个工具移植到 CnWizards 中了,改动部分如下:
1、移植到 CnWizards 专家框架中。
2、EditWindow 的 OnKeyUp 替换改成用 SetWindowsHookEx 注册一个全局的键盘钩子来实现(实现于公共的 CnWizNotifier 单元。
3、通过在 InvokeCodeCompletion 前用 TCnMethodHook 替换掉 MessageDlgPosHelp 函数,来避免失败时 IDE 弹出错误对话框的问题。
4、对程序结构的一些调整及代码整理。
5、把图片资源直接加到 ImageList 中。

单元列表:
cnpackSourceWizardIdeEnhancementsCnInputHelper.pas
cnpackSourceWizardUtilsCnWizSymbolList.pas

后续工作:
1、改进提示窗口显示,使焦点保持在代码编辑器中,象 Code Insignt 窗口一样。
2、使用 GExpoerts 提供的方法,移植到不支持 IOTACodeInsightManager 的 D5/D6 中。
3、增加设置窗口。
4、完善对列表按类型排序功能,增加类型过滤功能。

相关任务单:
http://www.cnvcl.org:8008/cnpack/tktview?tn=115,0

非常感谢 internetzs 的工作及移植授权!您的名字已经作为该专家的第一作者出现,现在使用的是 Johnson Zhong,如果觉得不合适,请与我联系。
Author: internetzs    Time: 2004-11-7 11:49

移植到cnpack是个令人振奋的好消息。我现在每天都离不开这个东东了。

关于提示焦点问题:
我发现以前的旧版的delphi输入法(DelphiInput)的焦点是保持在delphi中的,我问过原作者是怎么实现的,他回答:

是用栏截Delphi中键盘的消息,而不是用SetWindowsHookEx
在Delphi7的Demo中用一个“Editor Keybinding”例子,可以参考一下!
目录是“Delphi7DemosToolsAPIEditor Keybinding”

我对Keybinding不太了解,移植的时候或许可参考。
毕竟用SetWindowsHookEx方法要外加dll不太好。
Author: iceman    Time: 2004-11-10 10:26

请问新版本的CnPack什么时候发布???带DelphiInput的
Author: zjy    Time: 2004-11-10 11:45

呵呵,新版本还要一段时间才发完善发布,不过您现在可以先下载一个刚刚发布的内部测试版:
http://ftp.cnvcl.org/temp/CnWizards_0.7.0.alpha.exe

这个版本对 DelphiPut 进行了大量的改进和增强,已经可以支持 D567 了。
希望大家喜欢,有什么问题欢迎给我们反馈。
Author: zjy    Time: 2004-11-10 11:54

移植后的输入助手增强了如下功能:
1、全面支持 D567,功能一致。
2、可以显示在标识符中间匹配的项。
3、在 uses 中使用时自动列出所有可用的单元名。
4、根据不同的代码位置,自动过滤列表内容。
5、支持多种排序方式,调整了一些优先级算法。
6、大量的结构改进和性能优化,更多智能判断。
7、支持延时弹出,默认为250ms。

目前设置界面还没有完成,请关注新版本的发布。
Author: zjy    Time: 2004-11-10 12:05

正在开发中的功能及未解决的问题:
1、如果IDE的AutoComplete显示时,不弹出列表,当前会替换。
2、列表弹出时,光标保留在编辑区,象AutoComplete窗口一样。
3、增加设置界面。
4、支持代码模板功能,可以用缩写输入代码块,如用 be 输入 begin end 对。

大家有什么好的建议,欢迎与我们联系!
Author: internetzs    Time: 2004-11-10 18:12

呵,动作真快,下面一些建议提供参考:

1. 行号和Symbol的字体可以设置,还有颜色。默认的“宋体”不好看
2. 行号的代码的TCnEditorGutter.Width可根据行号宽度进行动态调整
3. 单击TCnEditorGutter可以设置或取消书签
4. SymbolList过滤还是只过滤以输入的单词打头好些,太多眼花

以下是我的前段时间写的的一些代码片段:


// 画行号
procedure TGutterPanel.DrawLineNumber;
var
    i: Integer;
    Number: string;
    R: TRect;
    EditView: IOTAEditView;
    TopRow: Integer;
    BottomRow: Integer;
    CurrentRow: Integer;
begin
    EditView := CnOtaGetTopMostEditView;
    if not Assigned(EditView) then Exit;

    TopRow:= EditView.TopRow;
    BottomRow:= EditView.BottomRow;
    CurrentRow:= EditView.CursorPos.Line;

    with FLineControl do
    begin
        Refresh;
        Canvas.Brush.Style:= bsClear;
        Canvas.Font:= Self.Font;
        
        // 根据字串的宽度动态调整Gutter的宽度
        Self.Width:= FLineControl.Canvas.TextWidth(IntToStr(BottomRow))+3;

        for i:= TopRow to BottomRow do
        begin
            if (i=CurrentRow) and Assigned(FEditCursor) then
            begin
                // 画一个当前行的图标代替
                Canvas.Draw((Width - FEditCursor.Width) div 2 ,
                    (i-TopRow)* FLineHeight, FEditCursor);
            end
            else
            begin
                Number:= IntToStr(i);
                R:= Rect(0, (i-TopRow)* FLineHeight, Width-3, (i-TopRow)* FLineHeight+FLineHeight);
                DrawText(Canvas.Handle, PChar(Number), Length(Number), R, DT_RIGHT);
            end;
        end;

        // 画一条垂直线
        Canvas.Pen.Color:= VLineColor;
        Canvas.MoveTo(Width-1, 0);
        Canvas.LineTo(Width-1, Height);
    end;
end;

// 单击Gutter Panel设置或取消书签
procedure TGutterPanel.LineControltMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
    Row: Integer;
    EditView: IOTAEditView;
    ID: Integer;
    EditPos, SavePos: TOTAEditPos;

    function GetBlankBookmarkID: Integer;
    var
      i: Integer;
    begin
        Result:= 0;
        for i:=0 to 9 do
        if EditView.BookmarkPos[i ].Line = 0  then
        begin
            Result:= i;
            Exit;
        end;
    end;
    function FindBookmark(Row: Integer): Integer;
    var
      i: Integer;
    begin
        Result:= -1;
        for i:=0 to 9 do
        if EditView.BookmarkPos[i ].Line=Row then
        begin
            Result:= i;
            Exit;
        end;
    end;
begin
   
    if Button = mbLeft then
    begin
        EditView := CnOtaGetTopMostEditView;
        if Assigned(EditView) then
        begin
            Row:= EditView.TopRow + Y div FLineHeight;
            SavePos:= EditView.CursorPos;
            EditPos:= EditView.CursorPos;
            EditPos.Line:= Row;
            EditView.CursorPos:= EditPos;
            ID:= FindBookmark(Row);
            if ID=-1 then ID:= GetBlankBookmarkID;
            EditView.BookmarkToggle(ID);
            EditView.CursorPos:= SavePos;
            EditView.Paint;
        end;
    end;
end;
Author: zjy    Time: 2004-11-10 18:29

呵呵,internetzs 做的东西不少嘛!

行号是 Passion 移植 Dragon PC 的专家,我让他过来这里看看。

符号过滤支持中间匹配是考虑到有时候我们只记得一些标识符中间的部分,或者不知道用什么函数合适,用一些关键词来尝试的功能,比如输入 Process 可以显示所有与进程相关的函数。默认的排序方法会将匹配开头的放到最前面,而且只有回车可以选择,应该没什么影响。
这个功能可以关掉,只是设置界面还没有做,注册表项:
HKEY_CURRENT_USERSoftwareCnPackCnWizardsCnInputHelper
Author: internetzs    Time: 2004-11-10 18:52

你的那个问题:
1、如果IDE的AutoComplete显示时,不弹出列表,当前会替换。

可以用下面方法解决(未验证):

Delphi的Code completion窗口的信息,

WindowText: KibitzWindow
WindowClass: TCodeCompleteListView

如果你用FindWindow函数能找到此窗口,则证明Code completion窗口已经存在。
否则此时SymbolList的窗口才可以弹出。

还有个问题就是中文输入法存在时不要弹出
Author: zjy    Time: 2004-11-10 19:10

多谢提供,省去不少功能,否则我得自己去找了。

输入法问题是因为我平时都开着输入法,只是用shift把它禁用,如果开输入法就关自动完成的话,来回切换输入法太麻烦,所以把这个功能禁用了。我加个选项由用户决定吧。
Author: Passion    Time: 2004-11-10 19:56     Subject: 行号显示功能还没完善……

……就被匆忙地拿出来见世面,不好意思,我赶紧接着完善它。
Author: iceman    Time: 2004-11-13 13:49

输入法总体感觉比vs.net2005好,但如下图(我在输入点的时候){图1}

[ Last edited by iceman on 2004-11-13 at 15:25 ]

Image Attachment: 输入点的时候.JPG (2004-11-13 13:49, 110.39 K) / Download count 1054
http://bbs.cnpack.org/attachment.php?aid=12


Author: iceman    Time: 2004-11-13 13:50

但跟着输入c的时候.,为什么会出现这么多的选项(图二)

[ Last edited by iceman on 2004-11-13 at 15:25 ]

Image Attachment: 输入C的时候.JPG (2004-11-13 13:50, 133.69 K) / Download count 363
http://bbs.cnpack.org/attachment.php?aid=13


Author: zjy    Time: 2004-11-13 17:15

多谢报告这个错误,这确实是一个问题,在D7下暂时还没有找到解决办法,在D5下已经正常了。

这几天又做了不少改进工作,下周会发布一个新的内测版,请关注!
Author: lann    Time: 2004-11-13 21:24



QUOTE:
yygw  在 2004-11-13 05:15 PM 发表:

多谢报告这个错误,这确实是一个问题,在D7下暂时还没有找到解决办法,在D5下已经正常了。

这几天又做了不少改进工作,下周会发布一个新的内测版,请关注!

非常感谢各位的无私奉献~
可否考虑将这部份的功能移植到BCB6呢?
前不久试用CnWizard 7.0 alpha似乎没见到BCB版本有新增此功能
Author: zjy    Time: 2004-11-13 21:36

多谢支持!

这个工具最核心的技术是从实时编译器中获得当前标识符列表,当前只有 Delphi7 的 ToolsAPI 提供了官方的支持,而在 Delphi5/6 都是使用了修改自 GExperts 的未公开技术,直接调用内核 bpl 导出函数来实现的。

由于 BCB 和 Delphi 的编译器不同,GExperts 的自动改错工具也没有提供对 BCB 的基于编辑器的纠错支持,故实现起来会有一定难度,可惜 BCB 没有到 7.0 版:(

目前考虑在 BCB 中先增加一个根据自定义标识符列表提示的工具。
Author: zjy    Time: 2004-11-14 09:36     Subject: 新版本已经发布

专家包发布 0.7.0.a1内部测试版

    http://ftp.cnvcl.org/temp/CnWizards_0.7.0.a1.exe

    在前两天发布的 alpha基础上,对输入助手和行号做了大量的改进:
    1、IDE的自动完成显示时,不再弹出助手。
    2、助手弹出时,光标仍在代码编辑器中。
    3、增加了列表右键菜单和设置窗口,允许用热键 F2 关闭/启用 自动弹出(Action可放在工具栏上),用 Alt+Down 手工弹出。
    4、行号显示自动调整宽度,优化了重绘性能。
    5、点击行号可以 设置/取消书签。
    6、右键点击行号,可以书签跳转、打开书签浏览等。

    欢迎测试和反馈意见!
Author: iceman    Time: 2004-11-15 11:53

动作真快,下载ing
Author: shadowstar    Time: 2004-11-21 19:57

CnWizards IDE专家包最可爱的就是这个功能了,很亲切^-^
Author: shadowstar    Time: 2004-11-26 23:07

Delphi自带的Code Insight在选择一个函数后敲‘;’可以自动添加(),如果没有参数就不会添加,希望可以把输入法也增强一下。
Author: shadowstar    Time: 2004-11-26 23:08

test;
Author: zjy    Time: 2004-11-27 09:18



QUOTE:
shadowstar  在 2004-11-26 23:07 发表:

Delphi自带的Code Insight在选择一个函数后敲‘;’可以自动添加(),如果没有参数就不会添加,希望可以把输入法也增强一下。

这个功能可能不太好做,有空我想想办法。
Author: shadowstar    Time: 2004-11-27 13:25

大家一起想办法。
Author: internetzs    Time: 2004-11-28 20:37

小功能难实现,就不发花太多时间去钻牛角尖了,得不偿失。
还是花时间移植到D2005才好。
D2005的OpenToolsApi好象没找这方面的帮助,都不知Borland在想什么。
Borland好象都不太重视帮助系统,每次都急于推出新版本,帮助都不全,
要隔一段时间打补丁。D7/D8都是这样。
Author: zjy    Time: 2004-11-28 20:46

Borland也是要为生计考虑啊。D2005同时支持 Delphi/Delphi.NET/C# 三种语言和应用程序框架,专家要全部兼容得花不少力气。这几天我在忙其它的,还没时间在 D2005 下测试,internetzs 有空先研究下吧:)




Welcome to CnPack Forum (http://bbs.cnpack.org/) Powered by Discuz! 5.0.0