5 #include <X11/XKBlib.h>
6 #include <dali/integration-api/debug.h>
9 #include "debug/x-input2-debug.h"
23 // For multi-touch we need XI2 version 2.2
24 int XI2MinorVersionRequired = 2;
25 int XI2MajorVersionRequired = 2;
28 XInput2::XInput2( XID window, Display* display, WindowEventInterface* eventInterface )
29 : mEventInterface( eventInterface ),
33 mMultiTouchSupport( false )
41 void XInput2::Initialize()
43 // Check if X supports the multi-touch protocol
44 QueryMultiTouchSupport();
46 // Query what input devices are available on the system.
49 // Select the input events we want to receive from the input devices available
54 int XInput2::GetExtensionId() const
56 return mXI2ExtensionId;
59 bool XInput2::FilteredDevice( int deviceId ) const
61 for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
63 if( mInputDeviceInfo[i].deviceId == deviceId )
71 bool XInput2::PreProcessEvent( XIDeviceEvent *deviceEvent ) const
73 // @todo need to do some testing to see if this check is actually required
74 // E.g. if IME window is sending events, this check may fail
75 if( deviceEvent->event != mWindow )
79 // emulated flags means that the event has been emulated from another XI 2.x event for legacy client support
80 // We don't call XISelectEvents on these events so hopefully shouldn't get them.
81 if( ( deviceEvent->flags & XIPointerEmulated ) || ( deviceEvent->flags & XITouchEmulatingPointer ) )
86 if( !FilteredDevice( deviceEvent->deviceid ))
93 void XInput2::CreateKeyEvent( const XIDeviceEvent* deviceEvent, KeyEvent& keyEvent ) const
95 // get the physical key code ( range 8..255)
96 KeyCode keycode = deviceEvent->detail;
98 keyEvent.keyCode = keycode;
99 keyEvent.state = KeyEvent::Down;
100 keyEvent.keyModifier = deviceEvent->mods.effective;
102 // extract key symbol. The symbol is typically the name visible on the key
103 // e.g. key code 201 might = Brightness increase, or a Korean character depending on the keyboard mapping.
104 // @todo For XKbKeycodeToKeysym to work correctly we need the group and level.
105 // investigate using XkbGetState to get initial state then start monitoring for XkbStateNotify events
106 KeySym sym = XkbKeycodeToKeysym( mDisplay, keycode, 0 /* group */ , keyEvent.IsShiftModifier() );
107 char* keyname = XKeysymToString( sym );
109 keyEvent.keyPressedName = keyname;
110 keyEvent.time = deviceEvent->time;
114 // prototyping implementation
115 void XInput2::ProcessKeyEvent( XKeyEvent* xEvent )
118 keyEvent.keyCode = xEvent->keycode;
119 keyEvent.state = KeyEvent::Down;
121 KeySym sym = XkbKeycodeToKeysym( mDisplay, xEvent->keycode, 0 /* group */ , keyEvent.IsShiftModifier() );
122 char* keyname = XKeysymToString( sym );
123 keyEvent.keyPressedName = keyname;
124 keyEvent.time = xEvent->time;
126 mEventInterface->KeyEvent( keyEvent );
128 void XInput2::ProcessClientMessage( XEvent* event )
130 // Format for client message for key event
132 // xev.xclient.type = ClientMessage;
133 // xev.xclient.display = keyrouter.disp;
134 // xev.xclient.window = window;
135 // xev.xclient.format = 32;
136 // xev.xclient.message_type = ecore_x_atom_get("VDINPUT_KEYEVENT");
137 // xev.xclient.data.l[0] = ev->time; /* time */
138 // xev.xclient.data.l[1] = ev->state; /* modifier */
139 // xev.xclient.data.l[2] = ev->code; /* keycode */
140 // xev.xclient.data.l[3] = ev->value; /* press/release */
141 // xev.xclient.data.l[4] = ev->device_id; /* deviceId */
143 Atom input_atom = XInternAtom( mDisplay, "VDINPUT_KEYEVENT", false);
146 keyEvent.state = KeyEvent::Down;
148 // if atom is "VDINPUT_KEYEVENT"
149 if( input_atom == event->xclient.message_type )
152 keyEvent.keyModifier = event->xclient.data.l[1];
153 keyEvent.keyCode = event->xclient.data.l[2];
155 // only transmit keydown events
156 if( event->xclient.data.l[3] != 2)
158 return; // 2 = key down, 3 = key release
161 KeySym sym = XkbKeycodeToKeysym( mDisplay, keyEvent.keyCode, 0 /* group */ , keyEvent.IsShiftModifier() );
162 char* keyname = XKeysymToString( sym );
163 keyEvent.keyPressedName = keyname;
164 keyEvent.time = event->xclient.data.l[0];
166 mEventInterface->KeyEvent( keyEvent );
170 void XInput2::ProcessGenericEvent( XGenericEventCookie* cookie )
172 XIDeviceEvent* deviceEvent = static_cast< XIDeviceEvent* >(cookie->data);
174 X11Debug::LogXI2Event( cookie );
176 bool requiresProcessing = PreProcessEvent( deviceEvent );
178 if( ! requiresProcessing )
183 Integration::Point point;
184 point.SetDeviceId( deviceEvent->deviceid );
185 point.SetScreenPosition( Vector2( deviceEvent->event_x, deviceEvent->event_y ) );
186 Time time( deviceEvent->time ); // X is using uint32 for time field ( see XI2proto.h )
188 switch( cookie->evtype)
193 point.SetState( PointState::MOTION );
194 mEventInterface->TouchEvent( point, time );
200 point.SetState( PointState::DOWN );
201 mEventInterface->TouchEvent( point, time );
205 case XI_ButtonRelease:
207 point.SetState( PointState::UP );
208 mEventInterface->TouchEvent( point, time );
213 mEventInterface->WindowFocusIn();
218 mEventInterface->WindowFocusOut();
224 CreateKeyEvent( deviceEvent, keyEvent );
225 mEventInterface->KeyEvent( keyEvent );
235 void XInput2::QueryMultiTouchSupport()
237 int minor = XI2MinorVersionRequired;
238 int major = XI2MajorVersionRequired;
239 int firstEventCode, firstErrorCode;
241 // Check if the extension is available and get the extension id
242 if( !XQueryExtension(mDisplay, "XInputExtension", &mXI2ExtensionId, &firstEventCode, &firstErrorCode) )
244 DALI_LOG_ERROR(" XInputExtension not available \n");
248 // inform X that DALi ( the client ) supports XI2 version 2.2
249 // it will assign the X servers supported version to the parameters
250 int ret = XIQueryVersion( mDisplay, &major, &minor);
251 if( ret == BadValue )
253 DALI_LOG_ERROR(" XIQueryVersion %d,%d failed \n", major, minor );
257 // check the version is supports multi-touch
258 if( ( major * 1000 + minor ) >= ( XI2MajorVersionRequired * 1000 + XI2MinorVersionRequired ) )
260 mMultiTouchSupport = true;
264 DALI_LOG_ERROR( "XInput 2.2 or greater required for multi-touch\n");
268 void XInput2::QueryDevices()
270 int numberOfDevices( 0 );
272 // QueryDevice returns information about one or more input devices
273 XIDeviceInfo* deviceInfoArray = XIQueryDevice( mDisplay, XIAllDevices, &numberOfDevices);
274 XIDeviceInfo* device = deviceInfoArray;
276 X11Debug::LogInputDeviceInfo( deviceInfoArray, numberOfDevices );
278 mInputDeviceInfo.Resize( numberOfDevices );
280 for( int i = 0; i < numberOfDevices; ++i, ++device )
284 info.AssignDeviceInfo( device );
286 mInputDeviceInfo.PushBack( info );
289 XIFreeDeviceInfo( deviceInfoArray );
292 void XInput2::SelectEvents( int deviceId, const Dali::Vector< unsigned int >& filter )
294 if( filter.Size() == 0)
299 // each event like XI_ButtonPress is stored as unique bit, so if there's 32 events we need 4 bytes
300 // the XIMaskLen macro provides the length for us at compile time.
301 unsigned char mask[ XIMaskLen( XI_LASTEVENT ) ] = {};
302 XIEventMask eventMask;
304 eventMask.deviceid = deviceId;
305 eventMask.mask_len = sizeof( mask);
306 eventMask.mask = mask;
308 for( VectorBase::SizeType i = 0; i< filter.Count(); ++i )
310 XISetMask( mask, filter[i] );
313 XISelectEvents( mDisplay, mWindow, &eventMask, 1);
316 void XInput2::SelectInputEvents()
319 * From the X documentation:
320 * "A master pointer is a virtual pointer device that does not represent a physical device.
321 * If a slave device generates an event, the event is also generated by the respective master device.
322 * Multiple slave devices can be attached to a single master device."
323 * master = cursor / keyboard focus,
324 * slave = physical device
326 * For motion events, we currently just listen to the slave devices. This allows us the ability to
327 * perform a XIGrabDevice on the slave if we need to, which will temporarily detach it from the master.
328 * In DALi we currently don't perform a grab as typically we just have a single x-window displayed.
329 * Where as other toolkits may have a window for a popup and want do know when the mouse is clicked outside
330 * of the popup, to close it.
332 Dali::Vector< unsigned int > eventFilter;
333 eventFilter.Reserve( 6 ); // typically filter no more than 6 events
335 for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
337 const XInput2Device& device( mInputDeviceInfo[ i ] );
341 // Floating slave devices also can generate key events. For example, TV remote controllers.
342 if( ( device.use == XIFloatingSlave ) || ( device.use == XISlavePointer ) || ( device.use == XISlaveKeyboard ) )
344 if( device.buttonClass )
346 eventFilter.PushBack( XI_ButtonPress );
347 eventFilter.PushBack( XI_ButtonRelease );
348 eventFilter.PushBack( XI_Motion );
350 if( device.touchClass )
352 eventFilter.PushBack( XI_TouchUpdate );
353 eventFilter.PushBack( XI_TouchBegin );
354 eventFilter.PushBack( XI_TouchEnd );
356 if( device.keyClass )
358 eventFilter.PushBack( XI_KeyPress );
359 eventFilter.PushBack( XI_KeyRelease );
363 if( eventFilter.Count() > 0 )
365 SelectEvents( device.deviceId, eventFilter );
369 } // namespace internal
370 } // namespace adaptor