How to stop receiving repeated OnKeyPress events on a TForm?












-1















I have a main Form and when I select an item and press Enter a second modal Form is shown. This has some TEdit controls to change the item parameters. When the user has finished, he can press Esc to cancel or Enter to update the item, and close the edit Form.



The problem is that if the user presses and holds Enter, a loop is occurs. The Form is closed and opened again and then closed... and so on.



I changed the WndProc of the modal Form and cancel if the previous key state was pressed. But this works only if I don't have any controls on the Form. If I drop a TEdit (which is needed), the Form re-enters the loop. The modal Form has KeyPreview set to true, because I want to be able to validate the data from anywhere.



This is the minimal code to reproduce the problem:



After you test this, you can drop a TEdit on Form2 and you will notice that a loop occurs.



Form1:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
procedure FormKeyPress(Sender: TObject; var Key: Char);
end;

var
Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then Form2.ShowModal;
end;

end.


Form2:



unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
protected
procedure WndProc(var Msg: TMessage); override;
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
KeyPreview:= True;
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin Key:= #0; ModalResult:= mrOK; end;
end;

procedure TForm2.WndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_CHAR) and ((Msg.LParam and $40000000) <> 0) then Exit;
inherited;
end;

end.









share|improve this question

























  • How about unselecting the item in the main form, on return from the modal form?

    – Tom Brunberg
    Nov 20 '18 at 19:04











  • If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

    – A Lombardo
    Nov 20 '18 at 19:04













  • @TomBrunberg the item must remain selected.

    – Marus Nebunu
    Nov 20 '18 at 19:07











  • @ALombardo, I check it, but if it's valid the loop will occur.

    – Marus Nebunu
    Nov 20 '18 at 19:09






  • 1





    Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

    – Jerry Dodge
    Nov 20 '18 at 20:50


















-1















I have a main Form and when I select an item and press Enter a second modal Form is shown. This has some TEdit controls to change the item parameters. When the user has finished, he can press Esc to cancel or Enter to update the item, and close the edit Form.



The problem is that if the user presses and holds Enter, a loop is occurs. The Form is closed and opened again and then closed... and so on.



I changed the WndProc of the modal Form and cancel if the previous key state was pressed. But this works only if I don't have any controls on the Form. If I drop a TEdit (which is needed), the Form re-enters the loop. The modal Form has KeyPreview set to true, because I want to be able to validate the data from anywhere.



This is the minimal code to reproduce the problem:



After you test this, you can drop a TEdit on Form2 and you will notice that a loop occurs.



Form1:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
procedure FormKeyPress(Sender: TObject; var Key: Char);
end;

var
Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then Form2.ShowModal;
end;

end.


Form2:



unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
protected
procedure WndProc(var Msg: TMessage); override;
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
KeyPreview:= True;
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin Key:= #0; ModalResult:= mrOK; end;
end;

procedure TForm2.WndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_CHAR) and ((Msg.LParam and $40000000) <> 0) then Exit;
inherited;
end;

end.









share|improve this question

























  • How about unselecting the item in the main form, on return from the modal form?

    – Tom Brunberg
    Nov 20 '18 at 19:04











  • If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

    – A Lombardo
    Nov 20 '18 at 19:04













  • @TomBrunberg the item must remain selected.

    – Marus Nebunu
    Nov 20 '18 at 19:07











  • @ALombardo, I check it, but if it's valid the loop will occur.

    – Marus Nebunu
    Nov 20 '18 at 19:09






  • 1





    Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

    – Jerry Dodge
    Nov 20 '18 at 20:50
















-1












-1








-1








I have a main Form and when I select an item and press Enter a second modal Form is shown. This has some TEdit controls to change the item parameters. When the user has finished, he can press Esc to cancel or Enter to update the item, and close the edit Form.



The problem is that if the user presses and holds Enter, a loop is occurs. The Form is closed and opened again and then closed... and so on.



I changed the WndProc of the modal Form and cancel if the previous key state was pressed. But this works only if I don't have any controls on the Form. If I drop a TEdit (which is needed), the Form re-enters the loop. The modal Form has KeyPreview set to true, because I want to be able to validate the data from anywhere.



This is the minimal code to reproduce the problem:



After you test this, you can drop a TEdit on Form2 and you will notice that a loop occurs.



Form1:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
procedure FormKeyPress(Sender: TObject; var Key: Char);
end;

var
Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then Form2.ShowModal;
end;

end.


Form2:



unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
protected
procedure WndProc(var Msg: TMessage); override;
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
KeyPreview:= True;
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin Key:= #0; ModalResult:= mrOK; end;
end;

procedure TForm2.WndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_CHAR) and ((Msg.LParam and $40000000) <> 0) then Exit;
inherited;
end;

end.









share|improve this question
















I have a main Form and when I select an item and press Enter a second modal Form is shown. This has some TEdit controls to change the item parameters. When the user has finished, he can press Esc to cancel or Enter to update the item, and close the edit Form.



The problem is that if the user presses and holds Enter, a loop is occurs. The Form is closed and opened again and then closed... and so on.



I changed the WndProc of the modal Form and cancel if the previous key state was pressed. But this works only if I don't have any controls on the Form. If I drop a TEdit (which is needed), the Form re-enters the loop. The modal Form has KeyPreview set to true, because I want to be able to validate the data from anywhere.



This is the minimal code to reproduce the problem:



After you test this, you can drop a TEdit on Form2 and you will notice that a loop occurs.



Form1:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
procedure FormKeyPress(Sender: TObject; var Key: Char);
end;

var
Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then Form2.ShowModal;
end;

end.


Form2:



unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
protected
procedure WndProc(var Msg: TMessage); override;
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
KeyPreview:= True;
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin Key:= #0; ModalResult:= mrOK; end;
end;

procedure TForm2.WndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_CHAR) and ((Msg.LParam and $40000000) <> 0) then Exit;
inherited;
end;

end.






forms delphi delphi-2009






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 '18 at 18:07









Remy Lebeau

339k19262456




339k19262456










asked Nov 20 '18 at 17:48









Marus NebunuMarus Nebunu

1,226931




1,226931













  • How about unselecting the item in the main form, on return from the modal form?

    – Tom Brunberg
    Nov 20 '18 at 19:04











  • If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

    – A Lombardo
    Nov 20 '18 at 19:04













  • @TomBrunberg the item must remain selected.

    – Marus Nebunu
    Nov 20 '18 at 19:07











  • @ALombardo, I check it, but if it's valid the loop will occur.

    – Marus Nebunu
    Nov 20 '18 at 19:09






  • 1





    Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

    – Jerry Dodge
    Nov 20 '18 at 20:50





















  • How about unselecting the item in the main form, on return from the modal form?

    – Tom Brunberg
    Nov 20 '18 at 19:04











  • If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

    – A Lombardo
    Nov 20 '18 at 19:04













  • @TomBrunberg the item must remain selected.

    – Marus Nebunu
    Nov 20 '18 at 19:07











  • @ALombardo, I check it, but if it's valid the loop will occur.

    – Marus Nebunu
    Nov 20 '18 at 19:09






  • 1





    Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

    – Jerry Dodge
    Nov 20 '18 at 20:50



















How about unselecting the item in the main form, on return from the modal form?

– Tom Brunberg
Nov 20 '18 at 19:04





How about unselecting the item in the main form, on return from the modal form?

– Tom Brunberg
Nov 20 '18 at 19:04













If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

– A Lombardo
Nov 20 '18 at 19:04







If it's only valid to press ENTER if Edit1 has a value, why not check that also: if (key = #13) then if (trim(Edit1.Text) <> '') then begin Key := #0; ModalResult := mrOK; end else Key := #0;

– A Lombardo
Nov 20 '18 at 19:04















@TomBrunberg the item must remain selected.

– Marus Nebunu
Nov 20 '18 at 19:07





@TomBrunberg the item must remain selected.

– Marus Nebunu
Nov 20 '18 at 19:07













@ALombardo, I check it, but if it's valid the loop will occur.

– Marus Nebunu
Nov 20 '18 at 19:09





@ALombardo, I check it, but if it's valid the loop will occur.

– Marus Nebunu
Nov 20 '18 at 19:09




1




1





Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

– Jerry Dodge
Nov 20 '18 at 20:50







Or you can use OnKeyDown / OnKeyUp instead of OnKeyPress. Those one's won't repeat when held down.

– Jerry Dodge
Nov 20 '18 at 20:50














1 Answer
1






active

oldest

votes


















0














Because it's impossible to hook TWinControl.DoKeyPress to solve this issue as it should, I came up with this workaround:



Form1:



procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnActivate:= AppActivate;
end;

procedure TForm1.AppActivate(Sender: TObject);
begin
EnterReleased:= (GetAsyncKeyState(VK_RETURN) and $8000) = 0;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin
Key:= #0;
if EnterReleased then begin
EnterReleased:= False;
Form2.ShowModal;
end;
end;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_RETURN then EnterReleased:= True;
end;


Form2:



procedure TForm2.FormCreate(Sender: TObject);
begin
KeyPreview:= True;
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then begin
Key:= #0;
if EnterReleased then begin
EnterReleased:= False;
ModalResult:= mrOK;
end;
end;
end;

procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_RETURN then EnterReleased:= True;
end;





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53398701%2fhow-to-stop-receiving-repeated-onkeypress-events-on-a-tform%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Because it's impossible to hook TWinControl.DoKeyPress to solve this issue as it should, I came up with this workaround:



    Form1:



    procedure TForm1.FormCreate(Sender: TObject);
    begin
    Application.OnActivate:= AppActivate;
    end;

    procedure TForm1.AppActivate(Sender: TObject);
    begin
    EnterReleased:= (GetAsyncKeyState(VK_RETURN) and $8000) = 0;
    end;

    procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
    begin
    if Key = #13 then begin
    Key:= #0;
    if EnterReleased then begin
    EnterReleased:= False;
    Form2.ShowModal;
    end;
    end;
    end;

    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
    if Key = VK_RETURN then EnterReleased:= True;
    end;


    Form2:



    procedure TForm2.FormCreate(Sender: TObject);
    begin
    KeyPreview:= True;
    end;

    procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
    begin
    if Key = #13 then begin
    Key:= #0;
    if EnterReleased then begin
    EnterReleased:= False;
    ModalResult:= mrOK;
    end;
    end;
    end;

    procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
    if Key = VK_RETURN then EnterReleased:= True;
    end;





    share|improve this answer






























      0














      Because it's impossible to hook TWinControl.DoKeyPress to solve this issue as it should, I came up with this workaround:



      Form1:



      procedure TForm1.FormCreate(Sender: TObject);
      begin
      Application.OnActivate:= AppActivate;
      end;

      procedure TForm1.AppActivate(Sender: TObject);
      begin
      EnterReleased:= (GetAsyncKeyState(VK_RETURN) and $8000) = 0;
      end;

      procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
      begin
      if Key = #13 then begin
      Key:= #0;
      if EnterReleased then begin
      EnterReleased:= False;
      Form2.ShowModal;
      end;
      end;
      end;

      procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
      begin
      if Key = VK_RETURN then EnterReleased:= True;
      end;


      Form2:



      procedure TForm2.FormCreate(Sender: TObject);
      begin
      KeyPreview:= True;
      end;

      procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
      begin
      if Key = #13 then begin
      Key:= #0;
      if EnterReleased then begin
      EnterReleased:= False;
      ModalResult:= mrOK;
      end;
      end;
      end;

      procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
      begin
      if Key = VK_RETURN then EnterReleased:= True;
      end;





      share|improve this answer




























        0












        0








        0







        Because it's impossible to hook TWinControl.DoKeyPress to solve this issue as it should, I came up with this workaround:



        Form1:



        procedure TForm1.FormCreate(Sender: TObject);
        begin
        Application.OnActivate:= AppActivate;
        end;

        procedure TForm1.AppActivate(Sender: TObject);
        begin
        EnterReleased:= (GetAsyncKeyState(VK_RETURN) and $8000) = 0;
        end;

        procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
        begin
        if Key = #13 then begin
        Key:= #0;
        if EnterReleased then begin
        EnterReleased:= False;
        Form2.ShowModal;
        end;
        end;
        end;

        procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        begin
        if Key = VK_RETURN then EnterReleased:= True;
        end;


        Form2:



        procedure TForm2.FormCreate(Sender: TObject);
        begin
        KeyPreview:= True;
        end;

        procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
        begin
        if Key = #13 then begin
        Key:= #0;
        if EnterReleased then begin
        EnterReleased:= False;
        ModalResult:= mrOK;
        end;
        end;
        end;

        procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        begin
        if Key = VK_RETURN then EnterReleased:= True;
        end;





        share|improve this answer















        Because it's impossible to hook TWinControl.DoKeyPress to solve this issue as it should, I came up with this workaround:



        Form1:



        procedure TForm1.FormCreate(Sender: TObject);
        begin
        Application.OnActivate:= AppActivate;
        end;

        procedure TForm1.AppActivate(Sender: TObject);
        begin
        EnterReleased:= (GetAsyncKeyState(VK_RETURN) and $8000) = 0;
        end;

        procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
        begin
        if Key = #13 then begin
        Key:= #0;
        if EnterReleased then begin
        EnterReleased:= False;
        Form2.ShowModal;
        end;
        end;
        end;

        procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        begin
        if Key = VK_RETURN then EnterReleased:= True;
        end;


        Form2:



        procedure TForm2.FormCreate(Sender: TObject);
        begin
        KeyPreview:= True;
        end;

        procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
        begin
        if Key = #13 then begin
        Key:= #0;
        if EnterReleased then begin
        EnterReleased:= False;
        ModalResult:= mrOK;
        end;
        end;
        end;

        procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        begin
        if Key = VK_RETURN then EnterReleased:= True;
        end;






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 22 '18 at 20:27

























        answered Nov 21 '18 at 14:57









        Marus NebunuMarus Nebunu

        1,226931




        1,226931
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53398701%2fhow-to-stop-receiving-repeated-onkeypress-events-on-a-tform%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Guess what letter conforming each word

            Port of Spain

            Run scheduled task as local user group (not BUILTIN)