Difference between revisions of "The Zandalar project"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
(Use Cases)
m (Semantics Table)
 
(14 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
= Input Aggregator & events =
 
= Input Aggregator & events =
 
== Use Cases ==
 
== Use Cases ==
 
 
The use cases are described by steps. For each step there might be some actions done at different levels:
 
The use cases are described by steps. For each step there might be some actions done at different levels:
 
* Raw input = the data that comes directly from the input system the application is using (OIS, glfw, etc.).
 
* Raw input = the data that comes directly from the input system the application is using (OIS, glfw, etc.).
Line 15: Line 14:
 
! Step description !! Raw input !! Input Injection !! InputEvent fed to CEGUI
 
! Step description !! Raw input !! Input Injection !! InputEvent fed to CEGUI
 
|-
 
|-
| Move the mouse over the button || Mouse movement || injectMouseMove/injectMousePosition || MovementInputEvent
+
| Move the mouse over the button || Mouse movement || injectMouseMove/injectMousePosition || PointerMovementInputEvent
 
|-
 
|-
| Press the LMB || Mouse button press || injectMouseButtonDown(LMB) || PressedButtonInputEvent(Mouse_LMB)
+
| Press the LMB || Mouse button press || injectMouseButtonDown(LMB) || PointerActivationInputEvent
 
|-
 
|-
| Release the LMB|| Mouse button release || injectMouseButtonUp(LMB) || ReleasedButtonInputEvent(Mouse_LMB)
+
| Release the LMB|| Mouse button release || injectMouseButtonUp(LMB) || PointerDeactivationInputEvent
 
|-
 
|-
 
| The button is clicked (Click event is triggered)|| N/A || N/A || N/A
 
| The button is clicked (Click event is triggered)|| N/A || N/A || N/A
Line 31: Line 30:
 
| Focus the button || colspan = 3 | Uses the use case "''Focus a button using the keyboard/gamepad''"
 
| Focus the button || colspan = 3 | Uses the use case "''Focus a button using the keyboard/gamepad''"
 
|-
 
|-
| Press the ENTER key (1) || Key Button press || injectKeyDown(Enter) || PressedButtonInputEvent(Keyb_Enter)
+
| Press the ENTER key (1) || Key Button press || injectKeyDown(Enter) || SemanticInputEvent(Confirm)
 
|-
 
|-
| Release the ENTER key || Key Button release || injectKeyUp(Enter) || ReleasedButtonInputEvent(Keyb_Enter)
+
| Release the ENTER key *** || Key Button release || injectKeyUp(Enter) || ReleasedButtonInputEvent(Confirm) **** (check the semantics table)
 
|-
 
|-
 
| The button is clicked (Click event is triggered)|| N/A || N/A || N/A
 
| The button is clicked (Click event is triggered)|| N/A || N/A || N/A
Line 52: Line 51:
 
| Press a character key || Char press || injectChar(chr) || TextInputEvent(chr)
 
| Press a character key || Char press || injectChar(chr) || TextInputEvent(chr)
 
|-
 
|-
| Press a non-character key || Key Button press || injectKeyDown(key) || PressedButtonInputEvent(Keyb_key)
+
| Press backspace (delete last char) || Key Button press || injectKeyDown(key) || SemanticInputEvent(DeleteLastCharacter)
|-
+
| Release a non-character key || Key Button release || injectKeyUp(key) || ReleasedButtonInputEvent(Keyb_key
+
 
|}
 
|}
  
=== Focus a button using the keyboard/gamepad ===
+
=== Scroll horizontally with the mouse wheel ===
TODO - This should go into the GUI Navigation part.
+
{| class="wikitable"
 +
|-
 +
! Step description !! Raw input !! Input Injection !! InputEvent fed to CEGUI
 +
|-
 +
| Rotate the wheel || Wheel rotation delta || injectMouseWheelChange(delta) || ScrollInputEvent(direction, delta)
 +
|}
  
 
== Proposed design ==
 
== Proposed design ==
Line 64: Line 66:
 
For start, the following events will cover all existing functions in the 'InjectedInputReceiver' interface:
 
For start, the following events will cover all existing functions in the 'InjectedInputReceiver' interface:
  
MovementInputEvent
+
{| class="wikitable"
* '''Data''':
+
|-
** Position : Vector2
+
! Input Event name !! Data !! Functions covered
** Delta : Vector2
+
|-
* '''Functions''':
+
| SemanticInputEvent ||
** injectMouseMove
+
* Value: Enum/int (see below table)
** injectMousePosition
+
* Payload:
 
+
** float[2]
PressedButtonInputEvent
+
** PointerSource enum member
* '''Data''':
+
*** PS_Left
** Button : Buttons Enum/integer or long for maximum flexibility
+
*** PS_Middle
* '''Functions''':
+
*** PS_Right
** injectMouseButtonDown
+
||
** injectKeyDown
+
* injectMouseButtonDown
 
+
* injectKeyDown
ReleasedButtonInputEvent
+
* injectMouseButtonUp
* '''Data''':
+
* injectKeyUp
** Button : Buttons Enum/integer or long for maximum flexibility
+
* injectMouseButtonClick
* '''Functions''':
+
* injectMouseButtonDoubleClick
** injectMouseButtonUp
+
* injectMouseButtonTripleClick
** injectKeyUp
+
* injectMouseWheelChange
 
+
|-
ActivatedInputEvent
+
| TextInputEvent ||
* '''Data''':
+
* Text : string/char
** Count (1+) : int
+
||
* '''Functions''':
+
* injectChar
** injectMouseButtonClick
+
|-
** injectMouseButtonDoubleClick
+
|}
** injectMouseButtonTripleClick
+
 
+
TextInputEvent
+
* '''Data''':
+
** Text : string/char
+
* '''Functions''':
+
** injectChar
+
  
 
Unmapped (yet) functions:
 
Unmapped (yet) functions:
 
* injectMouseLeaves
 
* injectMouseLeaves
* injectMouseWheelChange
 
  
== Original proposition ==
+
=== Semantics Table ===
I propose an input abstraction so we can use the (if not all) of the existing input architecture.
+
The following table represents the semantic values (members of an ENUM) and the raw event(s) from which they are generated.
  
(e.g.: injectMouseDown, injectMouseUp), but rather `Input Events`. An `InputEvent` is the basic input unit CEGUI will use, and that is generated from raw input. The input event is a basic POD class (just like the current EventArgs) that contains different information based on where it came from and from what raw input it was generated.
+
injectMouseMove + injectMousePosition
 +
* PointerMove
 +
injectMouseButtonDown
 +
* PointerHold (PointerSource)
 +
* SelectMultipleItems (SHIFT + click)
 +
* SelectCumulative (CTRL + CLICK)
 +
injectMouseButtonUp
 +
* PointerActivate (PointerSource)
 +
injectMouseButtonClick
 +
* PointerActivate (PointerSource)
 +
injectMouseButtonDoubleClick
 +
* SelectWord (double click)
 +
injectMouseButtonTripleClick
 +
* SelectAll (triple click)
 +
<strike>'''Question:''' Maybe we should create a standalone event type for pointer activation which also 'records' the number of activations? (for example in the case of double/triple click). The editbox uses double/triple click to select all text. Maybe let semantic action 'select all?'</strike>: YES
  
Some examples of input events are:
+
<strike>'''Question2:''' What we do with the right/middle/extra mouse buttons (TabControl uses middle and nobutton buttons)?:
* MovementInputEvent
+
* Introduce the idea of 'PointerSource' which can be left/right/middle
**  Generated from mouse x/y
+
* Add separate values: LeftPointerActivation, RightPointerActivation, etc? (I'd go for this)</strike>: We go for 'PointerSource' enum in the Semantic Event payload.
**  Generated from joystick/thumbstick x/y
+
* PressedInputEvent
+
**  Generated from mouse button
+
**  Generated from keyboard button
+
**  Generated from a gamepad button
+
the previous event
+
  
One can see that this solution leads us to allow a variety of input to be mapped to certain input events. Of course, each different input event will have some specific payload (the button pressed, the x/y coordinates of the movement, etc.).
+
injectKeyDown + injectKeyUp
 +
* DeleteLastCharacter (backspace)
 +
* DeletePreviousCharacter (del)
 +
* Confirm/Submit (Enter/tab/numpad enter -> This should go into the GUI navigation module)
 +
* SelectLeftCharacter (SHIFT + left arrow)
 +
* SelectRightCharacter (SHIFT + right arrow)
 +
* GoToPreviousCharacter (left arrow)
 +
* GoToPreviousWord (CTRL + left arrow)
 +
* GoToNextCharacter (right arrow)
 +
* GoToNextWord (CTRL + right arrow)
 +
* GoToStartOfLine (home)
 +
* GoToEndOfLine (end)
 +
* SelectAll (CTRL+A)
 +
* Back (escape)
 +
* Undo (CTRL+Z)
 +
* Redo (CTRL+Y)
 +
* Cut (CTRL+X)
 +
* Copy (CTRL+C)
 +
* Paste (CTRL+V)
  
+
injectMouseWheelChange
 +
* VerticalScroll
 +
* HorizontalScroll
  
Then, thishave the so-called `Input Aggregator` which will be able to aggregate raw inputs from multiple input devices into input events. In order to define the way we get those inputs, we will have an interface for each type of input device supported, and attach it to the aggregator dynamically as required by the user. This the support for those input devices, but rather just defining the interface we require to be implemented so we can use those input directly, without having the user emulate it (e.g.: emulate the mouse movement from the input of a joystick maneuver).
+
== Decisions ==
 +
=== Combining keyboard, gamepad and mouse button pressed actions ===
 +
We have three ways of handling this.
 +
* Using two types of events (Pressed/ReleasedButtonInputEvent) AND SemanticInputEvent
 +
** We have a "big" enum which contains all possible values for a keyboard, mouse and the gamepad
 +
** The 'raw' events (Pressed/ReleasedButtonInputEvent are triggered every time
 +
** The semantic events are generated only based on a mapping configuration: (button_id) -> (semantic_value). If a specific (button_id) present in the mapping is pressed then a semantic event will be generated with the specified (semantic_value).
 +
*** (button_id) is a member of the "big" enum
 +
*** (semantic_value) is a user-defined value. Inside CEGUI's system we'll have an enum which is used instead of magic numbers. Users could define their own enum which has indices starting from the last CEGUI's enum member number.
 +
* Using just the raw types of event (Pressed/ReleasedInputEvent) WITHOUT SemanticInputEvent
 +
** This would involve '''ignoring the explicit click calls''', and rather generate them inside the system.
 +
* Using just SemanticInputEvent WITHOUT raw events.
 +
 
 +
= GUI navigation =
 +
== Use cases ==
 +
 
 +
=== Focus a button using the keyboard/gamepad ===
 +
Just calling focus()
  
In order for the library to work with some basic input events out of the box I will create a default `Input Aggregator` implementation for mouse and keyboard (and if time allows it for gamepad). Basically what is required to be done is: take the current methods used in the `InjectedInputReceiver` and move them in device-specific files (e.g.: `GUIContext` .
+
=== Navigate a form ===
 +
Prerequisite: first control in the current window is focused; navigation is configured.
 +
* Pressed("Tab") = focus next ("next")
 +
* Pressed("CTRL + Tab") = focus previous ("previous")
 +
Steps:
 +
* Press `Tab`
 +
* The next control is focused.
  
At the end of the day, the samples that exist now should work (from the functionality point of view) the same way after the input system is replaced.
+
=== Navigate a 2D Menu ===
 +
Prerequisite: first control in the current window is focused; navigation is configured:
 +
* Pressed("left") = go left ("left")
 +
* Pressed("right") = go left ("right")
 +
* Pressed("top") = go left ("top")
 +
* Pressed("up") = go left ("up")
 +
* ^The same items but with the gamepad's D-Pad configuration instead of the keys
 +
Steps
 +
* Press a configured key/gamepad button.
 +
* The control in the specified direction is focused.

Latest revision as of 21:02, 19 July 2013

The Zandalar Project is a codename for the new Input archtecture and GUI navigation features.

Input Aggregator & events

Use Cases

The use cases are described by steps. For each step there might be some actions done at different levels:

  • Raw input = the data that comes directly from the input system the application is using (OIS, glfw, etc.).
  • Input Injection = the `InjectedInputReceiver`-ish function called with the right parameters
    • For backwards compatibility-ish, we can persist the same interface(InjectedInputReceiver), but provide in it a default implementation that generates the input events for the current interface's functions.
  • InputEvent = the `InputEvent` type generated from the injected input. This is the final step, and this is fed to the CEGUI library.

Clicking a button using a mouse

Step description Raw input Input Injection InputEvent fed to CEGUI
Move the mouse over the button Mouse movement injectMouseMove/injectMousePosition PointerMovementInputEvent
Press the LMB Mouse button press injectMouseButtonDown(LMB) PointerActivationInputEvent
Release the LMB Mouse button release injectMouseButtonUp(LMB) PointerDeactivationInputEvent
The button is clicked (Click event is triggered) N/A N/A N/A

Clicking/activating a button using the keyboard (new feature)

Step description Raw input Input Injection InputEvent fed to CEGUI
Focus the button Uses the use case "Focus a button using the keyboard/gamepad"
Press the ENTER key (1) Key Button press injectKeyDown(Enter) SemanticInputEvent(Confirm)
Release the ENTER key *** Key Button release injectKeyUp(Enter) ReleasedButtonInputEvent(Confirm) **** (check the semantics table)
The button is clicked (Click event is triggered) N/A N/A N/A

(1) the key will be defined as per the NavigationStrategy (GUINavigation project part). If there is no such key defined, the event will be ignored.

Clicking/activating a button using a gamepad

The same as previous Clicking/activating a button using the keyboard, but with the difference that it uses a Gamepad button instead of a Keyboard one.

Type text into a textbox

Step description Raw input Input Injection InputEvent fed to CEGUI
Focus the textbox Uses the use case "Focus a textbox using the keyboard/gamepad"
Press a character key Char press injectChar(chr) TextInputEvent(chr)
Press backspace (delete last char) Key Button press injectKeyDown(key) SemanticInputEvent(DeleteLastCharacter)

Scroll horizontally with the mouse wheel

Step description Raw input Input Injection InputEvent fed to CEGUI
Rotate the wheel Wheel rotation delta injectMouseWheelChange(delta) ScrollInputEvent(direction, delta)

Proposed design

Events

For start, the following events will cover all existing functions in the 'InjectedInputReceiver' interface:

Input Event name Data Functions covered
SemanticInputEvent
  • Value: Enum/int (see below table)
  • Payload:
    • float[2]
    • PointerSource enum member
      • PS_Left
      • PS_Middle
      • PS_Right
  • injectMouseButtonDown
  • injectKeyDown
  • injectMouseButtonUp
  • injectKeyUp
  • injectMouseButtonClick
  • injectMouseButtonDoubleClick
  • injectMouseButtonTripleClick
  • injectMouseWheelChange
TextInputEvent
  • Text : string/char
  • injectChar

Unmapped (yet) functions:

  • injectMouseLeaves

Semantics Table

The following table represents the semantic values (members of an ENUM) and the raw event(s) from which they are generated.

injectMouseMove + injectMousePosition

  • PointerMove

injectMouseButtonDown

  • PointerHold (PointerSource)
  • SelectMultipleItems (SHIFT + click)
  • SelectCumulative (CTRL + CLICK)

injectMouseButtonUp

  • PointerActivate (PointerSource)

injectMouseButtonClick

  • PointerActivate (PointerSource)

injectMouseButtonDoubleClick

  • SelectWord (double click)

injectMouseButtonTripleClick

  • SelectAll (triple click)

Question: Maybe we should create a standalone event type for pointer activation which also 'records' the number of activations? (for example in the case of double/triple click). The editbox uses double/triple click to select all text. Maybe let semantic action 'select all?': YES

Question2: What we do with the right/middle/extra mouse buttons (TabControl uses middle and nobutton buttons)?:

  • Introduce the idea of 'PointerSource' which can be left/right/middle
  • Add separate values: LeftPointerActivation, RightPointerActivation, etc? (I'd go for this): We go for 'PointerSource' enum in the Semantic Event payload.

injectKeyDown + injectKeyUp

  • DeleteLastCharacter (backspace)
  • DeletePreviousCharacter (del)
  • Confirm/Submit (Enter/tab/numpad enter -> This should go into the GUI navigation module)
  • SelectLeftCharacter (SHIFT + left arrow)
  • SelectRightCharacter (SHIFT + right arrow)
  • GoToPreviousCharacter (left arrow)
  • GoToPreviousWord (CTRL + left arrow)
  • GoToNextCharacter (right arrow)
  • GoToNextWord (CTRL + right arrow)
  • GoToStartOfLine (home)
  • GoToEndOfLine (end)
  • SelectAll (CTRL+A)
  • Back (escape)
  • Undo (CTRL+Z)
  • Redo (CTRL+Y)
  • Cut (CTRL+X)
  • Copy (CTRL+C)
  • Paste (CTRL+V)

injectMouseWheelChange

  • VerticalScroll
  • HorizontalScroll

Decisions

Combining keyboard, gamepad and mouse button pressed actions

We have three ways of handling this.

  • Using two types of events (Pressed/ReleasedButtonInputEvent) AND SemanticInputEvent
    • We have a "big" enum which contains all possible values for a keyboard, mouse and the gamepad
    • The 'raw' events (Pressed/ReleasedButtonInputEvent are triggered every time
    • The semantic events are generated only based on a mapping configuration: (button_id) -> (semantic_value). If a specific (button_id) present in the mapping is pressed then a semantic event will be generated with the specified (semantic_value).
      • (button_id) is a member of the "big" enum
      • (semantic_value) is a user-defined value. Inside CEGUI's system we'll have an enum which is used instead of magic numbers. Users could define their own enum which has indices starting from the last CEGUI's enum member number.
  • Using just the raw types of event (Pressed/ReleasedInputEvent) WITHOUT SemanticInputEvent
    • This would involve ignoring the explicit click calls, and rather generate them inside the system.
  • Using just SemanticInputEvent WITHOUT raw events.

GUI navigation

Use cases

Focus a button using the keyboard/gamepad

Just calling focus()

Navigate a form

Prerequisite: first control in the current window is focused; navigation is configured.

  • Pressed("Tab") = focus next ("next")
  • Pressed("CTRL + Tab") = focus previous ("previous")

Steps:

  • Press `Tab`
  • The next control is focused.

Navigate a 2D Menu

Prerequisite: first control in the current window is focused; navigation is configured:

  • Pressed("left") = go left ("left")
  • Pressed("right") = go left ("right")
  • Pressed("top") = go left ("top")
  • Pressed("up") = go left ("up")
  • ^The same items but with the gamepad's D-Pad configuration instead of the keys

Steps

  • Press a configured key/gamepad button.
  • The control in the specified direction is focused.