| 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 for (int i = 0; i < count; i++) { |
| 221 XIDeviceInfo* devinfo = devices + i; | 229 XIDeviceInfo* devinfo = devices + i; |
| 222 if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) { | 230 #if defined(USE_XI2_MT) |
| 231 for (int k = 0; k < devinfo->num_classes; ++k) { |
| 232 XIAnyClassInfo* xiclassinfo = devinfo->classes[k]; |
| 233 if (xiclassinfo->type == XITouchClass) { |
| 234 XITouchClassInfo* tci = |
| 235 reinterpret_cast<XITouchClassInfo *>(xiclassinfo); |
| 236 // Only care direct touch device (such as touch screen) right now |
| 237 if (tci->mode == XIDirectTouch) { |
| 238 touch_device_lookup_[devinfo->deviceid] = true; |
| 239 touch_device_list_.push_back(devinfo->deviceid); |
| 240 } |
| 241 } |
| 242 } |
| 243 #endif |
| 244 if (devinfo->use == XIFloatingSlave || devinfo->use == XISlavePointer) |
| 223 pointer_device_lookup_[devinfo->deviceid] = true; | 245 pointer_device_lookup_[devinfo->deviceid] = true; |
| 224 } | |
| 225 } | 246 } |
| 226 if (devices) | 247 if (devices) |
| 227 XIFreeDeviceInfo(devices); | 248 XIFreeDeviceInfo(devices); |
| 228 | 249 |
| 229 SetupValuator(); | 250 SetupValuator(); |
| 230 } | 251 } |
| 231 | 252 |
| 232 bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { | 253 bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { |
| 233 DCHECK_EQ(GenericEvent, xev->type); | 254 DCHECK_EQ(GenericEvent, xev->type); |
| 255 XIEvent* event = static_cast<XIEvent*>(xev->xcookie.data); |
| 256 XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(event); |
| 234 | 257 |
| 235 XGenericEventCookie* cookie = &xev->xcookie; | 258 #if defined(USE_XI2_MT) |
| 236 if (cookie->evtype != XI_ButtonPress && | 259 if (event->evtype == XI_TouchBegin || |
| 237 cookie->evtype != XI_ButtonRelease && | 260 event->evtype == XI_TouchUpdate || |
| 238 cookie->evtype != XI_Motion) | 261 event->evtype == XI_TouchEnd) { |
| 262 return touch_device_lookup_[xiev->sourceid]; |
| 263 } |
| 264 #endif |
| 265 if (event->evtype != XI_ButtonPress && |
| 266 event->evtype != XI_ButtonRelease && |
| 267 event->evtype != XI_Motion) |
| 239 return true; | 268 return true; |
| 240 | 269 |
| 241 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(cookie->data); | |
| 242 return pointer_device_lookup_[xiev->deviceid]; | 270 return pointer_device_lookup_[xiev->deviceid]; |
| 243 } | 271 } |
| 244 | 272 |
| 245 void TouchFactory::SetupXI2ForXWindow(Window window) { | 273 void TouchFactory::SetupXI2ForXWindow(Window window) { |
| 246 // Setup mask for mouse events. It is possible that a device is loaded/plugged | 274 // 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 | 275 // 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 | 276 // 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 | 277 // 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 | 278 // the events from uninteresting devices. We do the latter because that's |
| 251 // simpler. | 279 // simpler. |
| 252 | 280 |
| 253 Display* display = ui::GetXDisplay(); | 281 Display* display = ui::GetXDisplay(); |
| 254 | 282 |
| 255 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; | 283 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; |
| 256 memset(mask, 0, sizeof(mask)); | 284 memset(mask, 0, sizeof(mask)); |
| 257 | 285 |
| 286 #if defined(USE_XI2_MT) |
| 287 XISetMask(mask, XI_TouchBegin); |
| 288 XISetMask(mask, XI_TouchUpdate); |
| 289 XISetMask(mask, XI_TouchEnd); |
| 290 #endif |
| 258 XISetMask(mask, XI_ButtonPress); | 291 XISetMask(mask, XI_ButtonPress); |
| 259 XISetMask(mask, XI_ButtonRelease); | 292 XISetMask(mask, XI_ButtonRelease); |
| 260 XISetMask(mask, XI_Motion); | 293 XISetMask(mask, XI_Motion); |
| 261 | 294 |
| 262 XIEventMask evmask; | 295 XIEventMask evmask; |
| 263 evmask.deviceid = XIAllDevices; | 296 evmask.deviceid = XIAllDevices; |
| 264 evmask.mask_len = sizeof(mask); | 297 evmask.mask_len = sizeof(mask); |
| 265 evmask.mask = mask; | 298 evmask.mask = mask; |
| 266 XISelectEvents(display, window, &evmask, 1); | 299 XISelectEvents(display, window, &evmask, 1); |
| 267 XFlush(display); | 300 XFlush(display); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 279 } | 312 } |
| 280 | 313 |
| 281 SetupValuator(); | 314 SetupValuator(); |
| 282 } | 315 } |
| 283 | 316 |
| 284 bool TouchFactory::IsTouchDevice(unsigned deviceid) const { | 317 bool TouchFactory::IsTouchDevice(unsigned deviceid) const { |
| 285 return deviceid < touch_device_lookup_.size() ? | 318 return deviceid < touch_device_lookup_.size() ? |
| 286 touch_device_lookup_[deviceid] : false; | 319 touch_device_lookup_[deviceid] : false; |
| 287 } | 320 } |
| 288 | 321 |
| 322 #if !defined(USE_XI2_MT) |
| 289 bool TouchFactory::IsSlotUsed(int slot) const { | 323 bool TouchFactory::IsSlotUsed(int slot) const { |
| 290 CHECK_LT(slot, kMaxTouchPoints); | 324 CHECK_LT(slot, kMaxTouchPoints); |
| 291 return slots_used_[slot]; | 325 return slots_used_[slot]; |
| 292 } | 326 } |
| 293 | 327 |
| 294 void TouchFactory::SetSlotUsed(int slot, bool used) { | 328 void TouchFactory::SetSlotUsed(int slot, bool used) { |
| 295 CHECK_LT(slot, kMaxTouchPoints); | 329 CHECK_LT(slot, kMaxTouchPoints); |
| 296 slots_used_[slot] = used; | 330 slots_used_[slot] = used; |
| 297 } | 331 } |
| 332 #endif |
| 298 | 333 |
| 299 bool TouchFactory::GrabTouchDevices(Display* display, ::Window window) { | 334 bool TouchFactory::GrabTouchDevices(Display* display, ::Window window) { |
| 300 #if defined(TOUCH_UI) | 335 #if defined(TOUCH_UI) |
| 301 if (!base::MessagePumpForUI::HasXInput2() || | 336 if (!base::MessagePumpForUI::HasXInput2() || |
| 302 touch_device_list_.empty()) | 337 touch_device_list_.empty()) |
| 303 return true; | 338 return true; |
| 304 #endif | 339 #endif |
| 305 | 340 |
| 306 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; | 341 unsigned char mask[XIMaskLen(XI_LASTEVENT)]; |
| 307 bool success = true; | 342 bool success = true; |
| 308 | 343 |
| 309 memset(mask, 0, sizeof(mask)); | 344 memset(mask, 0, sizeof(mask)); |
| 345 #if defined(USE_XI2_MT) |
| 346 XISetMask(mask, XI_TouchBegin); |
| 347 XISetMask(mask, XI_TouchUpdate); |
| 348 XISetMask(mask, XI_TouchEnd); |
| 349 #endif |
| 310 XISetMask(mask, XI_ButtonPress); | 350 XISetMask(mask, XI_ButtonPress); |
| 311 XISetMask(mask, XI_ButtonRelease); | 351 XISetMask(mask, XI_ButtonRelease); |
| 312 XISetMask(mask, XI_Motion); | 352 XISetMask(mask, XI_Motion); |
| 313 | 353 |
| 314 XIEventMask evmask; | 354 XIEventMask evmask; |
| 315 evmask.mask_len = sizeof(mask); | 355 evmask.mask_len = sizeof(mask); |
| 316 evmask.mask = mask; | 356 evmask.mask = mask; |
| 317 for (std::vector<int>::const_iterator iter = | 357 for (std::vector<int>::const_iterator iter = |
| 318 touch_device_list_.begin(); | 358 touch_device_list_.begin(); |
| 319 iter != touch_device_list_.end(); ++iter) { | 359 iter != touch_device_list_.end(); ++iter) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 float* value) { | 448 float* value) { |
| 409 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); | 449 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); |
| 410 if (xiev->sourceid >= kMaxDeviceNum) | 450 if (xiev->sourceid >= kMaxDeviceNum) |
| 411 return false; | 451 return false; |
| 412 int v = valuator_lookup_[xiev->sourceid][tp]; | 452 int v = valuator_lookup_[xiev->sourceid][tp]; |
| 413 if (v >= 0 && XIMaskIsSet(xiev->valuators.mask, v)) { | 453 if (v >= 0 && XIMaskIsSet(xiev->valuators.mask, v)) { |
| 414 *value = xiev->valuators.values[v]; | 454 *value = xiev->valuators.values[v]; |
| 415 return true; | 455 return true; |
| 416 } | 456 } |
| 417 | 457 |
| 458 // With XInput 2.1, Tracking ID could be provided in the detail field |
| 459 if (tp == TP_TRACKING_ID) { |
| 460 *value = xiev->detail; |
| 461 return true; |
| 462 } |
| 463 |
| 418 return false; | 464 return false; |
| 419 } | 465 } |
| 420 | 466 |
| 421 bool TouchFactory::NormalizeTouchParam(unsigned int deviceid, | 467 bool TouchFactory::NormalizeTouchParam(unsigned int deviceid, |
| 422 TouchParam tp, | 468 TouchParam tp, |
| 423 float* value) { | 469 float* value) { |
| 424 float max_value; | 470 float max_value; |
| 425 float min_value; | 471 float min_value; |
| 426 if (GetTouchParamRange(deviceid, tp, &min_value, &max_value)) { | 472 if (GetTouchParamRange(deviceid, tp, &min_value, &max_value)) { |
| 427 *value = (*value - min_value) / (max_value - min_value); | 473 *value = (*value - min_value) / (max_value - min_value); |
| 428 DCHECK(*value >= 0.0 && *value <= 1.0); | 474 DCHECK(*value >= 0.0 && *value <= 1.0); |
| 429 return true; | 475 return true; |
| 430 } | 476 } |
| 431 return false; | 477 return false; |
| 432 } | 478 } |
| 433 | 479 |
| 434 bool TouchFactory::GetTouchParamRange(unsigned int deviceid, | 480 bool TouchFactory::GetTouchParamRange(unsigned int deviceid, |
| 435 TouchParam tp, | 481 TouchParam tp, |
| 436 float* min, | 482 float* min, |
| 437 float* max) { | 483 float* max) { |
| 438 if (valuator_lookup_[deviceid][tp] >= 0) { | 484 if (valuator_lookup_[deviceid][tp] >= 0) { |
| 439 *min = touch_param_min_[deviceid][tp]; | 485 *min = touch_param_min_[deviceid][tp]; |
| 440 *max = touch_param_max_[deviceid][tp]; | 486 *max = touch_param_max_[deviceid][tp]; |
| 441 return true; | 487 return true; |
| 442 } | 488 } |
| 443 return false; | 489 return false; |
| 444 } | 490 } |
| 445 | 491 |
| 446 } // namespace views | 492 } // namespace views |
| OLD | NEW |