Get user input string from label

Hi,

How can I use a label to get an input string from user (from keyboard typing) on runtime so that I can use this input for handling events?

See example at examples\user_interface\edit_test

In short you use TCastleEdit for that and read it’s Edit1.Text e.g. in TCastleEdit.OnChange event.

As Eugene says, the user interface to read text input is TCastleEdit. The TCastleLabel is, by design, just for displaying text.

Do you maybe just want to read keys that user pressed? In this case you can do it by overriding TUIState.Press (use the CGE editor, create “New Project” from any template – it will show how to handle keys by overriding Press method). Or you can assign event to Window.OnPress.

To add to above, you could of course handle keys and append them to TCastleLabel.Caption, thus effectively implementing your own text input. Whether this makes sense (whether TCastleEdit is more suitable) depends on what exactly you want to make.

Thanks.
I used part of the example Eugene mentioned; it is a start. :slight_smile:
What I want to make is a simple verb-noun parser that takes input from this edit string.
I would be nice if this edit string would be part of a label list where standard commands are shown and this as an additional one. Just like the old Sierra adventure games (the first Leisure suit Larry games for instance) where you could select “talk” “look” but fill in additional ones from an edit input line also.

For now I just have the TCastleEdit and it looks like this on my background picture.
I have 3 questions about this:

  1. Can I (and how) replace the standard flashing | with the > sign?
  2. How can I store the line input and close the editor by hitting the “enter” button?
  3. How can I enter text / focus without moving and activating the mouse cursor over the edit line?
    (I used edit1.focused := true but I still have to move mouse over the edit line to be able to enter text).

Btw I said “Label list” but I mean OnScreenMenuList.

image

This CaretChar is set as const in castlecontrols_edit.inc. I.e. you can’t change it in current version of the Engine. I don’t really see any implications of making it a variable. The flashing speed CaretSpeed can also be easily made into a variable if it’s needed.

You should observe some event to. In this case you can do it with TCastleEdit.OnPress. Inside just check if Event.Key = keyEnter and set TCastleEdit.Exists = false and get TCastleEdit.Text.

I think that’s what TCastleEdit.CaptureAllInput := true should do.

Do you have an example of this EditOnpress procedure? I don’t understand it how to implement this.

And TCastleEdit.CaptureAllInput := true does not work, I still have to move the mouse cursor over the editor before I can enter some text.

Interesting, indeed it works only if the mouse cursor is over some specific types of Castle User Interface (TCastleButton and TCastleLabel pass the events correctly, but TCastleRectangleControl doesn’t). I might be missing something here (I don’t feel good today) but at the first glance it looks like a bug.

Note, that this is a general way of handling “callbacks” or “events”. You might want to check how they work in general Modern Object Pascal Introduction for Programmers | Castle Game Engine because an “example” won’t likely to do you much good, as it should be adapted to specific conditions (i.e. if you call it in a class or outside of it).

In the example examples\user_interface\edit_test you can “extend” TEventHandler class by adding 2 callback procedures:

type
  TEventHandler = class
    procedure ButtonCopyTextClick(Sender: TObject);
    procedure Edit1Changed(Sender: TObject);
    procedure Edit1Press(const Sender: TInputListener;
    const Event: TInputPressRelease; var Handled: Boolean);
  end;

procedure TEventHandler.Edit1Changed(Sender: TObject);
begin
  //do something here
end;

procedure TEventHandler.Edit1Press(const Sender: TInputListener;
const Event: TInputPressRelease; var Handled: Boolean);
begin
  if Event.Key = keyEnter then
  begin
    //do something here
  end;
end;  

And then in the code when Edit1 is created - “assign” those procedures to the corresponding events:

  Edit1.OnChange := @TEventHandler(nil).Edit1Changed;
  Edit1.OnPress := @TEventHandler(nil).Edit1Press;

Note that you’ll need to add CastleKeysMouse to Uses section.

If you think that’s a bug maybe Michalis can take a look at it. :wink:

Many thanks for the example. The Edit1Press does what I had in mind; the edit1.text is remembered and I now can close the editor with TCastleEdit.Exists = false pressing keyEnter. Great.
But I am confused about the Edit1Changed procedure; is this an alternate way of storing the edited text?

Yes. You should use either one or another.

Edit1Press happens on every press event and checks if this event was keyEnter. If you want to run a command when the player presses Enter and don’t care what happens inbetween (like in DOS-era point-and-click games) then this is the one you need.

Eidt1Change happens every time the content of the TCastleEdit has been changed - e.g. a new letter has been typed in or deleted. This event is useful if you want to do something with user input while the player types in, e.g. if the player types in a magic keyword iddqd then do something immediately. I don’t think you can capture “Enter” key in here (still you can try looking at Container.Pressed[keyEnter]).

The CaptureAllInput is not really 100% reliable and I should probably just remove it. It will fail in case TCastleEdit is child of another non-fullscreen control.

The reliable way to do this is to set Window.Container.ForceCaptureInput := MyEdit. This will make MyEdit receive input always, regardless of mouse position.

1 Like

Thanks, that did the job. I would never figured out this myself.

Ok, Edit1Press is indeed what I need for this point-and-click stuff.
But Edit1Change could be useful also; for instance interrupting the player with a message while typing certain words or if the sentence becomes too long.
:slight_smile: