Class TInputListener

Unit

Declaration

type TInputListener = class(TComponent)

Description

Base class for things that listen to user input.

Hierarchy

  • TComponent
  • TInputListener

Overview

Methods

Protected function ContainerWidth: Cardinal;
Protected function ContainerHeight: Cardinal;
Protected function ContainerRect: TRectangle;
Protected function ContainerSizeKnown: boolean;
Protected procedure SetContainer(const Value: TUIContainer); virtual;
Protected procedure DoCursorChange; virtual; deprecated 'better override VisibleChange and watch for chCursor in Changes';
Public constructor Create(AOwner: TComponent); override;
Public function Press(const Event: TInputPressRelease): boolean; virtual;
Public function Release(const Event: TInputPressRelease): boolean; virtual;
Public function PreviewPress(const Event: TInputPressRelease): boolean; virtual;
Public function PreviewRelease(const Event: TInputPressRelease): boolean; virtual;
Public function Motion(const Event: TInputMotion): boolean; virtual;
Public function SensorRotation(const X, Y, Z, Angle: Double; const SecondsPassed: Single): boolean; virtual;
Public function SensorTranslation(const X, Y, Z, Length: Double; const SecondsPassed: Single): boolean; virtual;
Public function JoyAxisMove(const JoyID, Axis: Byte): boolean; virtual;
Public function JoyButtonPress(const JoyID, Button: Byte): boolean; virtual;
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); virtual;
Public procedure VisibleChange(const Changes: TCastleUserInterfaceChanges; const ChangeInitiatedByChildren: boolean = false); overload; virtual;
Public procedure VisibleChange(const RectOrCursorChanged: boolean = false); overload; virtual; deprecated 'use VisibleChange overload with (TCastleUserInterfaceChanges,boolean) parameters';
Public function AllowSuspendForInput: boolean; virtual;
Public procedure Resize; virtual;
Public procedure ContainerResize(const AContainerWidth, AContainerHeight: Cardinal); virtual; deprecated 'use Resize';

Properties

Public property OnVisibleChange: TCastleUserInterfaceChangeEvent read FOnVisibleChange write FOnVisibleChange;
Public property Container: TUIContainer read FContainer write SetContainer;
Public property OnCursorChange: TNotifyEvent read FOnCursorChange write FOnCursorChange; deprecated 'use OnVisibleChange (or override VisibleChange) and watch for Changes that include chCursor';
Public property ExclusiveEvents: boolean read FExclusiveEvents write FExclusiveEvents default true;
Published property Cursor: TMouseCursor read FCursor write SetCursor default mcDefault;
Published property OnUpdate: TUiUpdateEvent read FOnUpdate write FOnUpdate;
Published property OnPress: TUiPressReleaseEvent read FOnPress write FOnPress;
Published property OnRelease: TUiPressReleaseEvent read FOnRelease write FOnRelease;
Published property OnMotion: TUiMotionEvent read FOnMotion write FOnMotion;

Description

Methods

Protected function ContainerWidth: Cardinal;

Container sizes.

Protected function ContainerHeight: Cardinal;
 
Protected function ContainerRect: TRectangle;
 
Protected function ContainerSizeKnown: boolean;
 
Protected procedure SetContainer(const Value: TUIContainer); virtual;
 
Protected procedure DoCursorChange; virtual; deprecated 'better override VisibleChange and watch for chCursor in Changes';

Warning: this symbol is deprecated: better override VisibleChange and watch for chCursor in Changes

Called when Cursor changed. In TCastleUserInterface class, just calls OnCursorChange.

Public constructor Create(AOwner: TComponent); override;
 
Public function Press(const Event: TInputPressRelease): boolean; virtual;

Handle press or release of a key, mouse button or mouse wheel. Return True if the event was somehow handled, which prevents from passing this event to other UI controls.

When implementing in descendants it is best to override it like this:

function TMyControl.Press(const Event: TInputPressRelease): boolean;
begin
  Result := inherited;
  if Result then Exit; // exit if ancestor already handled event

  if Event.IsKey(keyEnter) then
  begin
    // do something in reaction on Enter
    Exit(ExclusiveEvents); // ExclusiveEvents is true by default
  end;

  if Event.IsMouseButton(mbLeft) then
  begin
    // do something in reaction on Enter
    Exit(ExclusiveEvents); // ExclusiveEvents is true by default
  end;
end;

Note that releasing of the mouse wheel is not implemented for now, neither by CastleWindow or Lazarus CastleControl.

The events PreviewPress and PreviewRelease are passed first to the parent control, before children have a chance to process this event. Overriding them makes sense if you draw something in RenderOverChildren.

The events Press and Release are passed to the parent only after the children had a chance to process this event. Overriding them makes sense if you draw something in Render. This is usually more natural, and adviced.

Public function Release(const Event: TInputPressRelease): boolean; virtual;
 
Public function PreviewPress(const Event: TInputPressRelease): boolean; virtual;
 
Public function PreviewRelease(const Event: TInputPressRelease): boolean; virtual;
 
Public function Motion(const Event: TInputMotion): boolean; virtual;

Motion of mouse or touch.

Public function SensorRotation(const X, Y, Z, Angle: Double; const SecondsPassed: Single): boolean; virtual;

Rotation detected by sensor. Used for example by 3Dconnexion devices or touch controls.

Parameters
X
X axis (tilt forward/backwards)
Y
Y axis (rotate)
Z
Z axis (tilt sidewards)
Angle
Angle of rotation
SecondsPassed
The time passed since last SensorRotation call. This is necessary because some sensors, e.g. 3Dconnexion, may *not* reported as often as normal Update calls.
Public function SensorTranslation(const X, Y, Z, Length: Double; const SecondsPassed: Single): boolean; virtual;

Translation detected by sensor. Used for example by 3Dconnexion devices or touch controls.

Parameters
X
X axis (move left/right)
Y
Y axis (move up/down)
Z
Z axis (move forward/backwards)
Length
Length of the vector consisting of the above
SecondsPassed
The time passed since last SensorRotation call. This is necessary because some sensors, e.g. 3Dconnexion, may *not* reported as often as normal Update calls.
Public function JoyAxisMove(const JoyID, Axis: Byte): boolean; virtual;

Axis movement detected by joystick

Parameters
JoyID
ID of joystick with pressed button
Axis
Number of moved axis
Public function JoyButtonPress(const JoyID, Button: Byte): boolean; virtual;

Joystick button pressed.

Parameters
JoyID
ID of joystick with pressed button
Button
Number of pressed button
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); virtual;

Control may do here anything that must be continously repeated. E.g. camera handles here falling down due to gravity, rotating model in Examine mode, and many more.

This method may be used, among many other things, to continously react to the fact that user pressed some key (or mouse button). For example, if holding some key should move some 3D object, you should do something like:

if HandleInput then
begin
  if Container.Pressed[K_Right] then
    Transform.Position := Transform.Position + Vector3(SecondsPassed * 10, 0, 0);
  HandleInput := not ExclusiveEvents;
end;

Instead of directly using a key code, consider also using TInputShortcut that makes the input key nicely configurable. See engine tutorial about handling inputs.

Multiplying movement by SecondsPassed makes your operation frame-rate independent. Object will move by 10 units in a second, regardless of how many FPS your game has.

The code related to HandleInput is important if you write a generally-useful control that should nicely cooperate with all other controls, even when placed on top of them or under them. The correct approach is to only look at pressed keys/mouse buttons if HandleInput is True. Moreover, if you did check that HandleInput is True, and you did actually handle some keys, then you have to set HandleInput := not ExclusiveEvents. As ExclusiveEvents is True in normal circumstances, this will prevent the other controls (behind the current control) from handling the keys (they will get HandleInput = False). And this is important to avoid doubly-processing the same key press, e.g. if two controls react to the same key, only the one on top should process it.

Note that to handle a single press / release (like "switch light on when pressing a key") you should rather use Press and Release methods. Use this method only for continous handling (like "holding this key makes the light brighter and brighter").

To understand why such HandleInput approach is needed, realize that the "Update" events are called differently than simple mouse and key events like "Press" and "Release". "Press" and "Release" events return whether the event was somehow "handled", and the container passes them only to the controls under the mouse (decided by TCastleUserInterface.CapturesEventsAtPosition). And as soon as some control says it "handled" the event, other controls (even if under the mouse) will not receive the event.

This approach is not suitable for Update events. Some controls need to do the Update job all the time, regardless of whether the control is under the mouse and regardless of what other controls already did. So all controls (well, all controls that exist, in case of TCastleUserInterface, see TCastleUserInterface.GetExists) receive Update calls.

So the "handled" status is passed through HandleInput. If a control is not under the mouse, it will receive HandleInput = False. If a control is under the mouse, it will receive HandleInput = True as long as no other control on top of it didn't already change it to False.

Parameters
SecondsPassed
Should be calculated like TFramesPerSecond.SecondsPassed, and usually it's in fact just taken from TCastleWindowCustom.Fps.SecondsPassed.
Public procedure VisibleChange(const Changes: TCastleUserInterfaceChanges; const ChangeInitiatedByChildren: boolean = false); overload; virtual;

Called always when something important inside this control (or it's children) changed. To be more precise, this is called when something mentioned among the TCastleUserInterfaceChange enumerated items changed.

This is always called with Changes <> [] (non-empty set).

Public procedure VisibleChange(const RectOrCursorChanged: boolean = false); overload; virtual; deprecated 'use VisibleChange overload with (TCastleUserInterfaceChanges,boolean) parameters';

Warning: this symbol is deprecated: use VisibleChange overload with (TCastleUserInterfaceChanges,boolean) parameters

 
Public function AllowSuspendForInput: boolean; virtual;

Allow window containing this control to suspend waiting for user input. Typically you want to override this to return False when you do something in the overridden Update method.

In this class, this simply returns always True.

See also
TCastleWindowCustom.AllowSuspendForInput
Is it allowed to suspend (for an indefinite amount of time) waiting for user input.
Public procedure Resize; virtual;

You can resize/reposition your component here, for example set TCastleUserInterface.Left or TCastleUserInterface.Bottom, to react to parent size changes. Called always when the container (component or window with OpenGL context) size changes. Called only when the OpenGL context of the container is initialized, so you can be sure that this is called only between GLContextOpen and GLContextClose.

We also make sure to call this once when inserting into the controls list (like TCastleWindowCustom.Controls or TCastleControlCustom.Controls or inside parent TCastleUserInterface), if inserting into the container/parent with already initialized OpenGL context. If inserting into the container/parent without OpenGL context initialized, it will be called later, when OpenGL context will get initialized, right after GLContextOpen.

In other words, this is always called to let the control know the size of the container, if and only if the OpenGL context is initialized.

Public procedure ContainerResize(const AContainerWidth, AContainerHeight: Cardinal); virtual; deprecated 'use Resize';

Warning: this symbol is deprecated: use Resize

 

Properties

Public property OnVisibleChange: TCastleUserInterfaceChangeEvent read FOnVisibleChange write FOnVisibleChange;

Called always when something important inside this control (or it's children) changed. See VisibleChange for details about when and how this is called.

Be careful when handling this event. Various changes may cause this, so be prepared to handle it at any moment, even in the middle when UI control is changing. It may also occur very often. It's usually safest to only set a boolean flag like "something should be recalculated" when this event happens, and do the actual recalculation later.

Public property Container: TUIContainer read FContainer write SetContainer;

Container of this control. When adding control to container's Controls list (like TCastleWindowCustom.Controls) container will automatically set itself here, and when removing from container this will be changed back to Nil.

May be Nil if this control is not yet inserted into any container.

Public property OnCursorChange: TNotifyEvent read FOnCursorChange write FOnCursorChange; deprecated 'use OnVisibleChange (or override VisibleChange) and watch for Changes that include chCursor';

Warning: this symbol is deprecated: use OnVisibleChange (or override VisibleChange) and watch for Changes that include chCursor

Event called when the Cursor property changes. This event is, in normal circumstances, used by the Container, so you should not use it in your own programs.

Public property ExclusiveEvents: boolean read FExclusiveEvents write FExclusiveEvents default true;

Should we disable further mouse / keys handling for events that we already handled in this control. If True, then our events will return True for mouse and key events handled.

This means that events will not be simultaneously handled by both this control and some other (or camera or normal window callbacks), which is usually more sensible, but sometimes somewhat limiting.

Published property Cursor: TMouseCursor read FCursor write SetCursor default mcDefault;

Mouse cursor over this control. When user moves mouse over the Container, the currently focused (topmost under the cursor) control determines the mouse cursor look.

Published property OnUpdate: TUiUpdateEvent read FOnUpdate write FOnUpdate;

Event that occurs continously on each control. See Update for details.

Published property OnPress: TUiPressReleaseEvent read FOnPress write FOnPress;

An input (key, mouse button, mouse wheel) was pressed. See Press for details.

Published property OnRelease: TUiPressReleaseEvent read FOnRelease write FOnRelease;

An input (key, mouse button, mouse wheel) was released. See Release for details.

Published property OnMotion: TUiMotionEvent read FOnMotion write FOnMotion;

Pointer (mouse or finger) moved. See Motion for details.


Generated by PasDoc 0.15.0.