summaryrefslogtreecommitdiff
path: root/LayerManagerBase/include/InputManager.h
blob: eb31b5f5b97794b317dd01afab04b37e15ef0ef1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/***************************************************************************
*
* Copyright 2012 Valeo
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*        http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
****************************************************************************/

#ifndef _INPUTMANAGER_H_
#define _INPUTMANAGER_H_


#include <map>
#include <vector>
#include <pthread.h>


class IScene;
class Surface;

#include "ilm_types.h"

/**
 * @brief Identifier for the different type of input devices supported by LayerManager.
 *        Fields can be used as a bit mask
 */
typedef ilmInputDevice InputDevice;
#define INPUT_DEVICE_KEYBOARD   ((InputDevice) ILM_INPUT_DEVICE_KEYBOARD)
#define INPUT_DEVICE_POINTER    ((InputDevice) ILM_INPUT_DEVICE_POINTER)
#define INPUT_DEVICE_TOUCH      ((InputDevice) ILM_INPUT_DEVICE_TOUCH)
#define INPUT_DEVICE_ALL        ((InputDevice) ILM_INPUT_DEVICE_ALL)


/**
 * @brief List the different states an input can be.
 */
typedef enum
{
    INPUT_STATE_PRESSED,    /*!< input is pressed    */
    INPUT_STATE_MOTION,     /*!< input is in motion  */
    INPUT_STATE_RELEASED,   /*!< input is released   */
    INPUT_STATE_OTHER       /*!< input is in an other, not listed, state  */
} InputEventState;


/**
 * @brief Type that describe a point.
 * Keep it POD (Plain Old Datatype) for performance reasons when dealing with touch event
 */
typedef struct
{
    InputEventState state;  /*<! State of the point       */
    int x;                  /*<! X position of the point  */
    int y;                  /*<! Y position of the point  */
}  Point;


/**
 * @brief Type to hold list of points
 */
typedef std::vector<Point> PointVect;
typedef PointVect::iterator PointVectIterator;


class InputManager
{
public:
    /** Ctor / Dtor
        */
    InputManager(IScene* s);
    ~InputManager();

    /** Methods to report input events
        *  They all return the surface to transfer the event to, or NULL if the event should not be dispatched
        */
    Surface * reportKeyboardEvent(InputEventState state, long keyId);
    Surface * reportTouchEvent(PointVect& pv);
    Surface * reportPointerEvent(Point& p);

    /** Methods to control the focus
        */
    bool setKeyboardFocusOn(unsigned int surfId);
    bool updateInputEventAcceptanceOn(unsigned int surfId, InputDevice devices, bool accept);

    /** Few getters
        */
    unsigned int getKeyboardFocusSurfaceId();

private:
    Surface * electSurfaceForPointerEvent(int& x, int& y);
    void transformGlobalToLocalCoordinates(Surface* surf, int& x, int& y);

    /*
        * Private Getters / Setters
        * Needed because access to their associated member requires exclusive area
        */

    /** \brief Set the keyboard focus on a particular surface */
    void _setKbdFocus(Surface * s);
    /** \brief Get the surface which has keyboard focus */
    Surface * _getKbdFocus();
    /** \brief Set the pointer focus on a particular surface */
    void _setPointerFocus(Surface * s);
    /** \brief Get the surface which has pointer focus */
    Surface * _getPointerFocus();
    /** \brief Set the touch focus on a particular surface */
    void _setTouchFocus(Surface * s);
    /** \brief Get the surface which has touch focus */
    Surface * _getTouchFocus();


private:
    IScene * m_pScene;                  /*!< Pointer to the scene */
    std::map<long, Surface*> m_KeyMap;  /*!< Map that associate keypressed event to the surface it has been forward to.
                                            See @ref<InputManager-KeypressedMap>. */
    pthread_mutex_t m_mutex;            /*!< Mutex to avoid concurrent access to shared variables */

    /* Access to the below members must be protected by mutex to avoid concurrent accesses */
    Surface * m_KbdFocus;               /*!< Pointer to the surface which has the focus for keyboard event.
                                                Should only be accessed via its getter / setter */
    Surface * m_PointerFocus;           /*!< Pointer to the surface which has the focus for pointer event.
                                                Should only be accessed via its getter / setter */
    Surface * m_TouchFocus;             /*!< Pointer to the surface which has the focus for touch event.
                                                Should only be accessed via its getter / setter */
};


/**
 * @section <InputManager-extra-documentation> (InputManager extra documentation)
 *
 * @subsection <InputManager-Requirements> (InputManager Requirements)
 *  <ul>
 *  \anchor<LM_INPUT_REQ_01>
 *    <li>
 *      LM_INPUT_REQ_01:
 *      LM should support input events dispatching to the relevant surface.
 *      Input devices can be keyboard, mouse or (multi)touch foil.
 *    </li>
 *
 *  \anchor<LM_INPUT_REQ_02>
 *    <li>
 *      LM_INPUT_REQ_02:
 *      Keyboard pressed events will be dispatched to the surface elected as being
 *      the "keyboard focused" surface.
 *      Keyboard released events will be dispatched to the surface which received
 *      the same key pressed event.
 *    </li>
 *
 *  \anchor<LM_INPUT_REQ_03>
 *    <li>
 *      LM_INPUT_REQ_03:
 *      A surface gain the Keyboard focus if the LM command "surfaceSetKeyboardFocus"
 *      is called on that surface. The elected surface can be changed at any time.
 *    </li>
 *
 *  \anchor<LM_INPUT_REQ_04>
 *  <li>
 *    LM_INPUT_REQ_04:
 *    Mouse & touch events will be dispatched to the surface elected as being the "Pointed" surface,
 *    even if theses events are outside of the surface. Coordinates will be adjusted relatively to the surface.
 *  </li>
 *
 *  \anchor<LM_INPUT_REQ_05>
 *  <li>
 *    LM_INPUT_REQ_05:
 *    A surface gain the "Pointed surface" status as soon as a Pointer event in "Pressed"
 *    state is reported under it.
 *    The conditions to gain this status is that the surface or its containing layer should:
 *     + be visible
 *     + be opaque (opacity != 0).
 *     + has a native content
 *  </li>
 *
 *  \anchor<LM_INPUT_REQ_06>
 *  <li>
 *    LM_INPUT_REQ_06:
 *    A surface can request to not receive particular input events. In this case, the surface should not be considered
 *    for focus election & the events must be dispatched to an other surface, if relevant.
 *  </li>
 *
 *  </ul>
 *
 *
 *
 *
 * @subsection <InputManager-KeypressedMap> (InputManager KeyPressed map)
 *
 * Note that reportKeyboardEvent() method takes a long as 2nd argument.
 * This is actually an identifier of the key being reported. It's purpose is to avoid a race in the following scenario :
 * 1- Surface S1 is the keyboard elected surface
 * 2- Key X is pressed, so we indicate the renderer to forward to S1
 * 3- The command "surfaceSetKeyboardFocus" is called on S2, so the surface S2 is now the keyboard elected one
 * 4- Key X is released.
 * We should then forward the KeyRelased event to S1 since we have reported the pressed event to it.
 * So we need a map that associate keyPressed  -> Surface. When the same key is released, we must forward that event
 * to the original surface, and not to the elected one.
 *
 *
 */


#endif /* ! #ifndef _INPUTMANAGER_H_ */