Skip to content

Commit

Permalink
[doc] Keymapping update and continue doc.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlyr committed Oct 4, 2022
1 parent 8230570 commit 83209e0
Showing 1 changed file with 67 additions and 8 deletions.
75 changes: 67 additions & 8 deletions doc/developer/keymapping.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
\page develkeymapping KeyMapping
[TOC]

# Usage
## Intoduction

KeyMapping is defined around two concepts, context (KeyMappingManager::Context) and action (KeyMappingManager::KeyMappingAction).
An action is associated to an event binding (KeyMappingManager::EventBinding), this binding represents the input (mouse, keys, modifiers) that are associated with the action.
The context allows to use same binding for different actions depending of the considered context.
The first widget that receive input event needs to manage context and determine which context to use to request corresponding action.
Typically the viewer is this first widget, and can decide which context to use depending on what is under mouse, if gizmo edit is enable, or if an active camera manipulator is active.

Context and action are simply indices stored in the key mapping manager, they are associated with std::string name, to ease key mapping management.
Typical usage is to have one context per class that may have its specifiv key mapping actions.

On the user side, one can test which action corresponds to a given binding (the one that triggers the event for instance), or use KeyMappingCallback manager to trigger registered callback.

## Usage

You first need to add into every configuration file (located in the `install_dir/Configs/` folder) an entry which will bind your action to a key.
This file as an only `keymaps` node, with `keymap` per binding.
Expand All @@ -16,9 +29,9 @@ This file as an only `keymaps` node, with `keymap` per binding.
Default values are in \[ \]

* `ACTION` *mandatory* represents the KeyMappingAction enum's value you want to trigger.
* `CONTEXT` \[AppContext\] epresents the context, for instance the class that will try to catch this keymapping
* `KEY` \[no def\] represents the key that need to be pressed to trigger the event (ie `Key_Z`, for example), "" or "-1" or absent correspond to no key needed.
* `MODIFIERS` \[NoModifiers\]represents the modifier used along with key or mouse button (needs to be a `Qt::Modifier` enum value) to trigger the action.
* `CONTEXT` \[AppContext\] represents the context, for instance the class that will try to catch this keymapping
* `KEY` \[-1\] represents the key that need to be pressed to trigger the event (ie `Key_Z`, for example), "" or "-1" or absent correspond to no key needed.
* `MODIFIERS` \[NoModifiers\] represents the modifier used along with key or mouse button (needs to be a `Qt::Modifier` enum value) to trigger the action.
Multiples modifiers can be specified, separated by commas as in `"ControlModifier,ShiftModifier"`.
* `BUTTONS` \[NoButtons\] represents the button to trigger the event (i.e. `LeftButton`, for example).
* `WHEEL` \[false\] if true, it's a wheel event ! (anything else is false).
Expand Down Expand Up @@ -86,19 +99,19 @@ void MyClass::configureKeyMapping() {
~~~

# Implementation note
## Implementation note

The viewer is the main entry point to dispatch key and mouse event.
The idea is that at a key press or mouse press event, the viewer is capable of determining which class will receive the events.

For instance see `Viewer.cpp` `Viewer::mousePressEvent`:
\snippet Gui/Viewer/Viewer.cpp event dispatch

# Key mapping and inheritence
## Key mapping and inheritence

If you want to define a derived class that inherits a base class with key mapping, and you want to have key mapping management in this derived, you have to consider the following implementation details:

* Base and derived classes will have two different contexts.
* Base and derived classes will have two different contexts if the derived class also implements KeyMappingManageable, if not derived class can use the base class context.
* Derived `setupKeymappingcallbacks` should call base `setupKeymappingcallbacks`, hence derived `configureKeymapping_impl` should only care about its own `KeyMappingAction`.

Here is an example snippets.
Expand Down Expand Up @@ -143,6 +156,52 @@ void MyViewer::configureKeyMapping_impl() {
}
~~~

# Limits
## Callback manager

An easy way to manage action callback is to use KeyMappingCallbackManager. This manager is a class member, initialize with Context.
One can register callback (std::function<void(QEvent*)>) that are triggered if the input event corresponds to the event binding.

The callback is responsible to test if the event corresponds to an event it can handle.

\note KeyPress and KeyRelease event both trigger the callback associated with a key event, in the callback you can use event->type() to check whether it's a key press or key release (or mouse move) event

Example usage

~~~{.cpp}
// during setup, once keymapping action are initialized
m_keyMappingCallbackManager.addEventCallback( TRACKBALLCAMERA_ZOOM,
[=]( QEvent* event ) { zoomCallback( event ); } );
// the callback is triggered for any binding corresponding to the action, what ever the event type.
// one can check event type to decide how to handle the action, here zoom is handled for both mouse move or wheel
// Note that when zoomCallback is triggered, it corresponds to the config file binding, including key or modifiers, so you don't have to check again.
void TrackballCameraManipulator::zoomCallback( QEvent* event ) {
if ( event->type() == QEvent::MouseMove ) {
auto mouseEvent = reinterpret_cast<QMouseEvent*>( event );
auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
handleCameraZoom( dx, dy );
}
else if ( event->type() == QEvent::Wheel ) {
auto wheelEvent = reinterpret_cast<QWheelEvent*>( event );
handleCameraZoom(
( wheelEvent->angleDelta().y() * 0.01_ra + wheelEvent->angleDelta().x() * 0.01_ra ) *
m_wheelSpeedModifier );
}
}
// handle the event is then
bool TrackballCameraManipulator::handleMousePressEvent( QMouseEvent* event,
const Qt::MouseButtons& buttons,
const Qt::KeyboardModifiers& modifiers,
int key ) {
// here callback manager check if there an action associated to event,key and then trigger the associated callback.
bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key );
return handled;
}
~~~

## Limits

* Multiple keys/buttons are not yet implemented.

0 comments on commit 83209e0

Please sign in to comment.