OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "views/touchui/touch_factory.h" | 5 #include "views/touchui/touch_factory.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 #include <gdk/gdkx.h> | 8 #include <gdk/gdkx.h> |
9 #include <X11/cursorfont.h> | 9 #include <X11/cursorfont.h> |
10 #include <X11/extensions/XInput.h> | 10 #include <X11/extensions/XInput.h> |
(...skipping 11 matching lines...) Expand all Loading... | |
22 // The X cursor is hidden if it is idle for kCursorIdleSeconds seconds. | 22 // The X cursor is hidden if it is idle for kCursorIdleSeconds seconds. |
23 int kCursorIdleSeconds = 5; | 23 int kCursorIdleSeconds = 5; |
24 | 24 |
25 // Given the TouchParam, return the correspoding XIValuatorClassInfo using | 25 // Given the TouchParam, return the correspoding XIValuatorClassInfo using |
26 // the X device information through Atom name matching. | 26 // the X device information through Atom name matching. |
27 XIValuatorClassInfo* FindTPValuator(Display* display, | 27 XIValuatorClassInfo* FindTPValuator(Display* display, |
28 XIDeviceInfo* info, | 28 XIDeviceInfo* info, |
29 views::TouchFactory::TouchParam tp) { | 29 views::TouchFactory::TouchParam tp) { |
30 // Lookup table for mapping TouchParam to Atom string used in X. | 30 // Lookup table for mapping TouchParam to Atom string used in X. |
31 // A full set of Atom strings can be found at xserver-properties.h. | 31 // A full set of Atom strings can be found at xserver-properties.h. |
32 // For Slot ID, See this chromeos revision: http://git.chromium.org/gitweb/? | |
33 // p=chromiumos/overlays/chromiumos-overlay.git; | |
34 // a=commit;h=9164d0a75e48c4867e4ef4ab51f743ae231c059a | |
35 static struct { | 32 static struct { |
36 views::TouchFactory::TouchParam tp; | 33 views::TouchFactory::TouchParam tp; |
37 const char* atom; | 34 const char* atom; |
38 } kTouchParamAtom[] = { | 35 } kTouchParamAtom[] = { |
39 { views::TouchFactory::TP_TOUCH_MAJOR, "Abs MT Touch Major" }, | 36 { views::TouchFactory::TP_TOUCH_MAJOR, "Abs MT Touch Major" }, |
40 { views::TouchFactory::TP_TOUCH_MINOR, "Abs MT Touch Minor" }, | 37 { views::TouchFactory::TP_TOUCH_MINOR, "Abs MT Touch Minor" }, |
41 { views::TouchFactory::TP_ORIENTATION, "Abs MT Orientation" }, | 38 { views::TouchFactory::TP_ORIENTATION, "Abs MT Orientation" }, |
42 { views::TouchFactory::TP_PRESSURE, "Abs MT Pressure" }, | 39 { views::TouchFactory::TP_PRESSURE, "Abs MT Pressure" }, |
40 #if !defined(USE_XI2_MT) | |
41 // For Slot ID, See this chromeos revision: http://git.chromium.org/gitweb/? | |
42 // p=chromiumos/overlays/chromiumos-overlay.git; | |
43 // a=commit;h=9164d0a75e48c4867e4ef4ab51f743ae231c059a | |
43 { views::TouchFactory::TP_SLOT_ID, "Abs MT Slot ID" }, | 44 { views::TouchFactory::TP_SLOT_ID, "Abs MT Slot ID" }, |
45 #endif | |
44 { views::TouchFactory::TP_TRACKING_ID, "Abs MT Tracking ID" }, | 46 { views::TouchFactory::TP_TRACKING_ID, "Abs MT Tracking ID" }, |
45 { views::TouchFactory::TP_LAST_ENTRY, NULL }, | 47 { views::TouchFactory::TP_LAST_ENTRY, NULL }, |
46 }; | 48 }; |
47 | 49 |
48 const char* atom_tp = NULL; | 50 const char* atom_tp = NULL; |
49 | 51 |
50 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTouchParamAtom); i++) { | 52 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTouchParamAtom); i++) { |
51 if (tp == kTouchParamAtom[i].tp) { | 53 if (tp == kTouchParamAtom[i].tp) { |
52 atom_tp = kTouchParamAtom[i].atom; | 54 atom_tp = kTouchParamAtom[i].atom; |
53 break; | 55 break; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 // static | 122 // static |
121 TouchFactory* TouchFactory::GetInstance() { | 123 TouchFactory* TouchFactory::GetInstance() { |
122 return Singleton<TouchFactory>::get(); | 124 return Singleton<TouchFactory>::get(); |
123 } | 125 } |
124 | 126 |
125 TouchFactory::TouchFactory() | 127 TouchFactory::TouchFactory() |
126 : is_cursor_visible_(true), | 128 : is_cursor_visible_(true), |
127 keep_mouse_cursor_(false), | 129 keep_mouse_cursor_(false), |
128 cursor_timer_(), | 130 cursor_timer_(), |
129 pointer_device_lookup_(), | 131 pointer_device_lookup_(), |
132 #if defined(USE_XI2_MT) | |
133 touch_device_list_() { | |
134 #else | |
130 touch_device_list_(), | 135 touch_device_list_(), |
131 slots_used_() { | 136 slots_used_() { |
137 #endif | |
132 #if defined(TOUCH_UI) | 138 #if defined(TOUCH_UI) |
133 if (!base::MessagePumpForUI::HasXInput2()) | 139 if (!base::MessagePumpForUI::HasXInput2()) |
134 return; | 140 return; |
135 #endif | 141 #endif |
136 | 142 |
137 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 143 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
138 XColor black; | 144 XColor black; |
139 black.red = black.green = black.blue = 0; | 145 black.red = black.green = black.blue = 0; |
140 Display* display = ui::GetXDisplay(); | 146 Display* display = ui::GetXDisplay(); |
141 Pixmap blank = XCreateBitmapFromData(display, ui::GetX11RootWindow(), | 147 Pixmap blank = XCreateBitmapFromData(display, ui::GetX11RootWindow(), |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 void TouchFactory::UpdateDeviceList(Display* display) { | 189 void TouchFactory::UpdateDeviceList(Display* display) { |
184 // Detect touch devices. | 190 // Detect touch devices. |
185 // NOTE: The new API for retrieving the list of devices (XIQueryDevice) does | 191 // NOTE: The new API for retrieving the list of devices (XIQueryDevice) does |
186 // not provide enough information to detect a touch device. As a result, the | 192 // not provide enough information to detect a touch device. As a result, the |
187 // old version of query function (XListInputDevices) is used instead. | 193 // old version of query function (XListInputDevices) is used instead. |
188 // If XInput2 is not supported, this will return null (with count of -1) so | 194 // If XInput2 is not supported, this will return null (with count of -1) so |
189 // we assume there cannot be any touch devices. | 195 // we assume there cannot be any touch devices. |
190 int count = 0; | 196 int count = 0; |
191 touch_device_lookup_.reset(); | 197 touch_device_lookup_.reset(); |
192 touch_device_list_.clear(); | 198 touch_device_list_.clear(); |
199 #if !defined(USE_XI2_MT) | |
193 XDeviceInfo* devlist = XListInputDevices(display, &count); | 200 XDeviceInfo* devlist = XListInputDevices(display, &count); |
194 for (int i = 0; i < count; i++) { | 201 for (int i = 0; i < count; i++) { |
195 if (devlist[i].type) { | 202 if (devlist[i].type) { |
196 const char* devtype = XGetAtomName(display, devlist[i].type); | 203 const char* devtype = XGetAtomName(display, devlist[i].type); |
197 if (devtype && !strcmp(devtype, XI_TOUCHSCREEN)) { | 204 if (devtype && !strcmp(devtype, XI_TOUCHSCREEN)) { |
198 touch_device_lookup_[devlist[i].id] = true; | 205 touch_device_lookup_[devlist[i].id] = true; |
199 touch_device_list_.push_back(devlist[i].id); | 206 touch_device_list_.push_back(devlist[i].id); |
200 } | 207 } |
201 } | 208 } |
202 } | 209 } |
203 if (devlist) | 210 if (devlist) |
204 XFreeDeviceList(devlist); | 211 XFreeDeviceList(devlist); |
212 #endif | |
205 | 213 |
206 // Instead of asking X for the list of devices all the time, let's maintain a | 214 // Instead of asking X for the list of devices all the time, let's maintain a |
207 // list of pointer devices we care about. | 215 // list of pointer devices we care about. |
208 // It should not be necessary to select for slave devices. XInput2 provides | 216 // It should not be necessary to select for slave devices. XInput2 provides |
209 // enough information to the event callback to decide which slave device | 217 // enough information to the event callback to decide which slave device |
210 // triggered the event, thus decide whether the 'pointer event' is a | 218 // triggered the event, thus decide whether the 'pointer event' is a |
211 // 'mouse event' or a 'touch event'. | 219 // 'mouse event' or a 'touch event'. |
212 // However, on some desktops, some events from a master pointer are | 220 // However, on some desktops, some events from a master pointer are |
213 // not delivered to the client. So we select for slave devices instead. | 221 // not delivered to the client. So we select for slave devices instead. |
214 // If the touch device has 'GrabDevice' set and 'SendCoreEvents' unset (which | 222 // If the touch device has 'GrabDevice' set and 'SendCoreEvents' unset (which |
215 // is possible), then the device is detected as a floating device, and a | 223 // is possible), then the device is detected as a floating device, and a |
216 // floating device is not connected to a master device. So it is necessary to | 224 // floating device is not connected to a master device. So it is necessary to |
217 // also select on the floating devices. | 225 // also select on the floating devices. |
218 pointer_device_lookup_.reset(); | 226 pointer_device_lookup_.reset(); |
219 XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &count); | 227 XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &count); |
220 for (int i = 0; i < count; i++) { | 228 if (devices) { |
Daniel Kurtz
2011/09/09 14:26:18
This isn't needed. On error, devices = NULL, but
ningxin.hu
2011/09/10 17:09:45
Thanks for the comments. I will correct this.
| |
221 XIDeviceInfo* devinfo = devices + i; | 229 for (int i = 0; i < count; i++) { |
222 if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) { | 230 if (!devices[i].enabled) |
223 pointer_device_lookup_[devinfo->deviceid] = true; | 231 continue; |
232 XIDeviceInfo* devinfo = devices + i; | |
Daniel Kurtz
2011/09/09 14:26:18
For consistency, assign devinfo first, then do:
ningxin.hu
2011/09/10 17:09:45
OK. I will follow up with a separated patch for th
| |
233 #if defined(USE_XI2_MT) | |
234 for (int k = 0; k < devinfo->num_classes; ++k) { | |
235 XIAnyClassInfo* xiclassinfo = devinfo->classes[k]; | |
236 if (xiclassinfo->type == XITouchClass) { | |
237 XITouchClassInfo* tci = (XITouchClassInfo *)xiclassinfo; | |
Daniel Kurtz
2011/09/09 14:26:18
reinterpret_cast<XITouchClassInfo*>xiclassinfo;
ningxin.hu
2011/09/10 17:09:45
I will correct this.
| |
238 // Only care direct touch device (such as touch screen) right now | |
239 if (tci->mode == XIDirectTouch) { | |
240 touch_device_lookup_[devinfo->deviceid] = true; | |
241 touch_device_list_.push_back(devinfo->deviceid); | |
242 } | |
243 } | |
244 } | |
245 #endif | |
246 if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) | |
247 pointer_device_lookup_[devinfo->deviceid] = true; | |
224 } | 248 } |
225 } | 249 } |
226 if (devices) | 250 if (devices) |
227 XIFreeDeviceInfo(devices); | 251 XIFreeDeviceInfo(devices); |
228 | 252 |
229 SetupValuator(); | 253 SetupValuator(); |
230 } | 254 } |
231 | 255 |
232 bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { | 256 bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { |
233 DCHECK_EQ(GenericEvent, xev->type); | 257 DCHECK_EQ(GenericEvent, xev->type); |
258 XIEvent* event = static_cast<XIEvent*>(xev->xcookie.data); | |
259 XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(event); | |
234 | 260 |
235 XGenericEventCookie* cookie = &xev->xcookie; | 261 #if defined(USE_XI2_MT) |
236 if (cookie->evtype != XI_ButtonPress && | 262 if (event->evtype == XI_TouchBegin || |
237 cookie->evtype != XI_ButtonRelease && | 263 event->evtype == XI_TouchUpdate || |
238 cookie->evtype != XI_Motion) | 264 event->evtype == XI_TouchEnd) { |
265 return touch_device_lookup_[xiev->sourceid]; | |
266 } | |
267 #endif | |
268 if (event->evtype != XI_ButtonPress && | |
269 event->evtype != XI_ButtonRelease && | |
270 event->evtype != XI_Motion) | |
239 return true; | 271 return true; |
240 | 272 |
241 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(cookie->data); | |
242 return pointer_device_lookup_[xiev->deviceid]; | 273 return pointer_device_lookup_[xiev->deviceid]; |
243 } | 274 } |
244 | 275 |
245 void TouchFactory::SetupXI2ForXWindow(Window window) { | 276 void TouchFactory::SetupXI2ForXWindow(Window window) { |
246 // Setup mask for mouse events. It is possible that a device is loaded/plugged | 277 // Setup mask for mouse events. It is possible that a device is loaded/plugged |
247 // in after we have setup XInput2 on a window. In such cases, we need to | 278 // in after we have setup XInput2 on a window. In such cases, we need to |
248 // either resetup XInput2 for the window, so that we get events from the new | 279 // either resetup XInput2 for the window, so that we get events from the new |
249 // device, or we need to listen to events from all devices, and then filter | 280 // device, or we need to listen to events from all devices, and then filter |
250 // the events from uninteresting devices. We do the latter because that's | 281 // the events from uninteresting devices. We do the latter because that's |
251 // simpler. | 282 // simpler. |
252 | 283 |
253 Display* display = ui::GetXDisplay(); | 284 Display* display = ui::GetXDisplay(); |
254 | 285 |
255 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; | 286 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; |
256 memset(mask, 0, sizeof(mask)); | 287 memset(mask, 0, sizeof(mask)); |
257 | 288 |
289 #if defined(USE_XI2_MT) | |
290 XISetMask(mask, XI_TouchBegin); | |
291 XISetMask(mask, XI_TouchUpdate); | |
292 XISetMask(mask, XI_TouchEnd); | |
293 #endif | |
258 XISetMask(mask, XI_ButtonPress); | 294 XISetMask(mask, XI_ButtonPress); |
259 XISetMask(mask, XI_ButtonRelease); | 295 XISetMask(mask, XI_ButtonRelease); |
260 XISetMask(mask, XI_Motion); | 296 XISetMask(mask, XI_Motion); |
261 | 297 |
262 XIEventMask evmask; | 298 XIEventMask evmask; |
263 evmask.deviceid = XIAllDevices; | 299 evmask.deviceid = XIAllDevices; |
264 evmask.mask_len = sizeof(mask); | 300 evmask.mask_len = sizeof(mask); |
265 evmask.mask = mask; | 301 evmask.mask = mask; |
266 XISelectEvents(display, window, &evmask, 1); | 302 XISelectEvents(display, window, &evmask, 1); |
267 XFlush(display); | 303 XFlush(display); |
(...skipping 11 matching lines...) Expand all Loading... | |
279 } | 315 } |
280 | 316 |
281 SetupValuator(); | 317 SetupValuator(); |
282 } | 318 } |
283 | 319 |
284 bool TouchFactory::IsTouchDevice(unsigned deviceid) const { | 320 bool TouchFactory::IsTouchDevice(unsigned deviceid) const { |
285 return deviceid < touch_device_lookup_.size() ? | 321 return deviceid < touch_device_lookup_.size() ? |
286 touch_device_lookup_[deviceid] : false; | 322 touch_device_lookup_[deviceid] : false; |
287 } | 323 } |
288 | 324 |
325 #if !defined(USE_XI2_MT) | |
289 bool TouchFactory::IsSlotUsed(int slot) const { | 326 bool TouchFactory::IsSlotUsed(int slot) const { |
290 CHECK_LT(slot, kMaxTouchPoints); | 327 CHECK_LT(slot, kMaxTouchPoints); |
291 return slots_used_[slot]; | 328 return slots_used_[slot]; |
292 } | 329 } |
293 | 330 |
294 void TouchFactory::SetSlotUsed(int slot, bool used) { | 331 void TouchFactory::SetSlotUsed(int slot, bool used) { |
295 CHECK_LT(slot, kMaxTouchPoints); | 332 CHECK_LT(slot, kMaxTouchPoints); |
296 slots_used_[slot] = used; | 333 slots_used_[slot] = used; |
297 } | 334 } |
335 #endif | |
298 | 336 |
299 bool TouchFactory::GrabTouchDevices(Display* display, ::Window window) { | 337 bool TouchFactory::GrabTouchDevices(Display* display, ::Window window) { |
300 #if defined(TOUCH_UI) | 338 #if defined(TOUCH_UI) |
301 if (!base::MessagePumpForUI::HasXInput2() || | 339 if (!base::MessagePumpForUI::HasXInput2() || |
302 touch_device_list_.empty()) | 340 touch_device_list_.empty()) |
303 return true; | 341 return true; |
304 #endif | 342 #endif |
305 | 343 |
306 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; | 344 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; |
307 bool success = true; | 345 bool success = true; |
308 | 346 |
309 memset(mask, 0, sizeof(mask)); | 347 memset(mask, 0, sizeof(mask)); |
348 #if defined(USE_XI2_MT) | |
349 XISetMask(mask, XI_TouchBegin); | |
350 XISetMask(mask, XI_TouchUpdate); | |
351 XISetMask(mask, XI_TouchEnd); | |
352 #endif | |
310 XISetMask(mask, XI_ButtonPress); | 353 XISetMask(mask, XI_ButtonPress); |
311 XISetMask(mask, XI_ButtonRelease); | 354 XISetMask(mask, XI_ButtonRelease); |
312 XISetMask(mask, XI_Motion); | 355 XISetMask(mask, XI_Motion); |
313 | 356 |
314 XIEventMask evmask; | 357 XIEventMask evmask; |
315 evmask.mask_len = sizeof(mask); | 358 evmask.mask_len = sizeof(mask); |
316 evmask.mask = mask; | 359 evmask.mask = mask; |
317 for (std::vector<int>::const_iterator iter = | 360 for (std::vector<int>::const_iterator iter = |
318 touch_device_list_.begin(); | 361 touch_device_list_.begin(); |
319 iter != touch_device_list_.end(); ++iter) { | 362 iter != touch_device_list_.end(); ++iter) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 float* value) { | 451 float* value) { |
409 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); | 452 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); |
410 if (xiev->sourceid >= kMaxDeviceNum) | 453 if (xiev->sourceid >= kMaxDeviceNum) |
411 return false; | 454 return false; |
412 int v = valuator_lookup_[xiev->sourceid][tp]; | 455 int v = valuator_lookup_[xiev->sourceid][tp]; |
413 if (v >= 0 && XIMaskIsSet(xiev->valuators.mask, v)) { | 456 if (v >= 0 && XIMaskIsSet(xiev->valuators.mask, v)) { |
414 *value = xiev->valuators.values[v]; | 457 *value = xiev->valuators.values[v]; |
415 return true; | 458 return true; |
416 } | 459 } |
417 | 460 |
461 // With XInput 2.1, Tracking ID could be provided in the detail field | |
462 if (tp == TP_TRACKING_ID) { | |
463 *value = xiev->detail; | |
464 return true; | |
465 } | |
466 | |
418 return false; | 467 return false; |
419 } | 468 } |
420 | 469 |
421 bool TouchFactory::NormalizeTouchParam(unsigned int deviceid, | 470 bool TouchFactory::NormalizeTouchParam(unsigned int deviceid, |
422 TouchParam tp, | 471 TouchParam tp, |
423 float* value) { | 472 float* value) { |
424 float max_value; | 473 float max_value; |
425 float min_value; | 474 float min_value; |
426 if (GetTouchParamRange(deviceid, tp, &min_value, &max_value)) { | 475 if (GetTouchParamRange(deviceid, tp, &min_value, &max_value)) { |
427 *value = (*value - min_value) / (max_value - min_value); | 476 *value = (*value - min_value) / (max_value - min_value); |
428 DCHECK(*value >= 0.0 && *value <= 1.0); | 477 DCHECK(*value >= 0.0 && *value <= 1.0); |
429 return true; | 478 return true; |
430 } | 479 } |
431 return false; | 480 return false; |
432 } | 481 } |
433 | 482 |
434 bool TouchFactory::GetTouchParamRange(unsigned int deviceid, | 483 bool TouchFactory::GetTouchParamRange(unsigned int deviceid, |
435 TouchParam tp, | 484 TouchParam tp, |
436 float* min, | 485 float* min, |
437 float* max) { | 486 float* max) { |
438 if (valuator_lookup_[deviceid][tp] >= 0) { | 487 if (valuator_lookup_[deviceid][tp] >= 0) { |
439 *min = touch_param_min_[deviceid][tp]; | 488 *min = touch_param_min_[deviceid][tp]; |
440 *max = touch_param_max_[deviceid][tp]; | 489 *max = touch_param_max_[deviceid][tp]; |
441 return true; | 490 return true; |
442 } | 491 } |
443 return false; | 492 return false; |
444 } | 493 } |
445 | 494 |
446 } // namespace views | 495 } // namespace views |
OLD | NEW |