1 /*
2 * Copyright 2003-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Copyright 2000-2002 Olaf van Es. All Rights Reserved.
6 * Distributed under the terms of the MIT license.
7 *
8 * These people have added and tested device ids:
9 *
10 * Frans van Nispen <frans@xentronix.com>
11 * Stefan Werner <stefan@keindesign.de>
12 * Hiroyuki Tsutsumi <???>
13 * Jeroen Oortwijn <oortwijn@gmail.com>
14 * Calvin Hill <calvin@hakobaito.co.uk>
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <File.h>
22 #include <InterfaceDefs.h>
23 #include <Screen.h>
24 #include <View.h>
25
26 #include "DeviceReader.h"
27 #include "MasterServerDevice.h"
28
29 #include "TabletDevice.h"
30
31 #define SNOOZE_AMOUNT 2500
32 #define JITTER_X .0007
33 #define JITTER_Y .0007
34 #define ACCELERATION_KICK_IN 2.3
35
36 // constructor
TabletDevice(MasterServerDevice * parent,DeviceReader * reader)37 TabletDevice::TabletDevice(MasterServerDevice* parent, DeviceReader* reader)
38 : PointingDevice(parent, reader),
39 fThreadID(B_ERROR),
40 fDeviceMode(DEVICE_UNKOWN),
41 fMaxX(1.0),
42 fMaxY(1.0),
43 fPosX(0.5),
44 fPosY(0.5),
45 fFakeMouseX(0.5),
46 fFakeMouseY(0.5),
47 fButtons(0),
48 fPressure(0.0),
49 fModifiers(0),
50 fEraser(0),
51 fTiltX(0.0),
52 fTiltY(0.0),
53 fClicks(0),
54 fHasContact(false)
55 {
56 }
57
58 // destructor
~TabletDevice()59 TabletDevice::~TabletDevice()
60 {
61 // cleanup
62 Stop();
63 }
64
65 // InitCheck
66 status_t
InitCheck()67 TabletDevice::InitCheck()
68 {
69 status_t status = PointingDevice::InitCheck();
70 if (status >= B_OK)
71 status = DetectDevice(fReader);
72 return status;
73 }
74
75 // Start
76 status_t
Start()77 TabletDevice::Start()
78 {
79 status_t status = B_NO_INIT;
80 if (fReader) {
81 fActive = true;
82 // get a nice name for our polling thread
83 const char* name;
84 _GetName(fReader->ProductID(), &name);
85 // start generating events
86 fThreadID = spawn_thread(poll_usb_device, name, 104, this);
87 if (fThreadID >= B_OK) {
88 resume_thread(fThreadID);
89 status = B_OK;
90 } else
91 status = fThreadID;
92 }
93 return status;
94 }
95
96 // Stop
97 status_t
Stop()98 TabletDevice::Stop()
99 {
100 status_t err = B_OK;
101
102 fActive = false;
103 if (fThreadID >= B_OK)
104 wait_for_thread(fThreadID, &err);
105 fThreadID = B_ERROR;
106
107 return err;
108 }
109
110 // DetectDevice
111 status_t
DetectDevice(const DeviceReader * reader)112 TabletDevice::DetectDevice(const DeviceReader* reader)
113 {
114 status_t status = B_OK;
115 switch (reader->ProductID()) {
116 case 0x00:
117 SetDevice(5040.0, 3780.0, DEVICE_PENPARTNER);
118 break;
119 case 0x03:
120 SetDevice(2048.0, 15360.0, DEVICE_PL500);
121 break;
122 case 0x10:
123 case 0x11:
124 case 0x13:
125 SetDevice(10206.0, 7422.0, DEVICE_GRAPHIRE);
126 break;
127 case 0x12: // Graphire 3 4x5
128 SetDevice(13918.0, 10206.0, DEVICE_GRAPHIRE);
129 break;
130 case 0x14: // Graphire 3 6x8
131 SetDevice(16704.0, 12064.0, DEVICE_GRAPHIRE);
132 break;
133 case 0x15: // Graphire 4 4x5 (tested)
134 SetDevice(10208.0, 7024.0, DEVICE_GRAPHIRE);
135 break;
136 case 0x16: // Graphire 4 6x8 (tested)
137 SetDevice(16704.0, 12064.0, DEVICE_GRAPHIRE);
138 break;
139 case 0x17: // BambooFun 4x5 (from Linux Wacom Project)
140 SetDevice(14760.0, 9225.0, DEVICE_BAMBOO);
141 break;
142 case 0x18: // BambooFun 6x8 (from Linux Wacom Project)
143 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO);
144 break;
145 case 0x20:
146 SetDevice(12700.0, 10600.0, DEVICE_INTUOS);
147 break;
148 case 0x21:
149 SetDevice(20320.0, 16240.0);
150 break;
151 case 0x22:
152 SetDevice(30480.0, 24060.0);
153 break;
154 case 0x23:
155 SetDevice(30480.0, 31680.0);
156 break;
157 case 0x24:
158 SetDevice(45720.0, 31680.0);
159 break;
160 case 0x30:
161 SetDevice(5408.0, 4056.0, DEVICE_PL500);
162 break;
163 case 0x31:
164 SetDevice(6144.0, 4608.0, DEVICE_PL500);
165 break;
166 case 0x32:
167 SetDevice(6126.0, 4604.0, DEVICE_PL500);
168 break;
169 case 0x33:
170 SetDevice(6260.0, 5016.0, DEVICE_PL500);
171 break;
172 case 0x34:
173 SetDevice(6144.0, 4608.0, DEVICE_PL500);
174 break;
175 case 0x35:
176 SetDevice(7220.0, 5780.0, DEVICE_PL500);
177 break;
178 case 0x3F:
179 SetDevice(87200.0, 65600.0, DEVICE_CINTIQ);
180 break;
181 case 0x41:
182 SetDevice(12700.0, 10600.0);
183 break;
184 case 0x42:
185 SetDevice(20320.0, 16240.0);
186 break;
187 case 0x43:
188 SetDevice(30480.0, 24060.0);
189 break;
190 case 0x44:
191 SetDevice(30480.0, 31680.0);
192 break;
193 case 0x45:
194 SetDevice(45720.0, 31680.0);
195 break;
196 case 0x47: // some I2 6x8 report as 0x47
197 SetDevice(20320.0, 16240.0);
198 break;
199 case 0x60:
200 SetDevice(5104.0, 3712.0, DEVICE_GRAPHIRE);
201 break;
202 case 0x61: // PenStation
203 // SetDevice(3403.0, 2475.0, DEVICE_GRAPHIRE); // this version was untested
204 SetDevice(3248.0, 2320.0, DEVICE_PENSTATION); // this version came from "beer"
205 break;
206 case 0x62: // Volito
207 SetDevice(5040.0, 3712.0, DEVICE_VOLITO);
208 break;
209 case 0x64: // PenPartner.1
210 // SetDevice(3450.0, 2100.0, DEVICE_PENSTATION);
211 SetDevice(3248.0, 2320.0, DEVICE_PENSTATION);
212 break;
213 case 0x65: // Bamboo (from Linux Wacom Project)
214 SetDevice(14760.0, 9225.0, DEVICE_BAMBOO);
215 break;
216 case 0x69: // Bamboo1 (from Linux Wacom Project)
217 SetDevice(5104.0, 3712.0, DEVICE_BAMBOO);
218 break;
219 case 0xB0:
220 SetDevice(25400.0, 20320.0, DEVICE_INTUOS3);
221 break;
222 case 0xB1:
223 SetDevice(40640.0, 30480.0, DEVICE_INTUOS3);
224 break;
225 case 0xB2:
226 SetDevice(60960.0, 45720.0, DEVICE_INTUOS3);
227 break;
228 case 0xB7: // Wacom PTZ-431W Intuos3 4x6
229 SetDevice(31496.0, 19685.0, DEVICE_INTUOS3);
230 break;
231 case 0xD0: // Wacom Bamboo 2FG (from Linux Wacom Project)
232 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
233 break;
234 case 0xD1: // Wacom BambooFun 2FG 4x5 (from Linux Wacom Project)
235 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
236 break;
237 case 0xD2: // Wacom Bamboo Craft (from Linux Wacom Project)
238 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
239 break;
240 case 0xD3: // Wacom BambooFun 2FG 6x8 (from Linux Wacom Project)
241 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
242 break;
243 case 0xD4: // Wacom Bamboo 4x5 (from Linux Wacom Project)
244 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
245 break;
246 case 0xD6: // Wacom Bamboo CTH-460/K (from Linux Wacom Project)
247 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
248 break;
249 case 0xD7: // Wacom Bamboo CTH-461/S (from Linux Wacom Project)
250 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
251 break;
252 case 0xD8: // Wacom Bamboo CTH-661/S1 (from Linux Wacom Project)
253 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
254 break;
255 case 0xDA: // Wacom Bamboo CTH-461/L (from Linux Wacom Project)
256 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
257 break;
258 case 0xDB: // Wacom Bamboo CTH-661 (from Linux Wacom Project)
259 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
260 break;
261 case 0xDD: // Wacom Bamboo Pen/Connect (CTL-470) (from Linux Wacom Project)
262 SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
263 break;
264 case 0x0301: // One by Wacom CTL-671
265 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
266 break;
267 case 0x037b: // One by Wacom CTL-672
268 SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
269 break;
270 default:
271 status = B_BAD_VALUE;
272 break;
273 }
274 return status;
275 }
276
277 // SetDevice
278 void
SetDevice(float maxX,float maxY,uint32 mode)279 TabletDevice::SetDevice(float maxX, float maxY, uint32 mode)
280 {
281 fDeviceMode = mode;
282 fMaxX = maxX;
283 fMaxY = maxY;
284 fJitterX = JITTER_X;
285 fJitterY = JITTER_Y;
286 }
287
288 // ReadData
289 void
ReadData(const uchar * data,int dataBytes,bool & hasContact,uint32 & mode,uint32 & buttons,float & x,float & y,float & pressure,int32 & clicks,int32 & eraser,float & wheelX,float & wheelY,float & tiltX,float & tiltY) const290 TabletDevice::ReadData(const uchar* data, int dataBytes, bool& hasContact,
291 uint32& mode, uint32& buttons, float& x, float& y, float& pressure,
292 int32& clicks, int32& eraser, float& wheelX, float& wheelY,
293 float& tiltX, float& tiltY) const
294 {
295 hasContact = false;
296 buttons = 0;
297 mode = MODE_PEN;
298 bool firstButton = false;
299 bool secondButton = false;
300 bool thirdButton = false;
301 uint16 xPos = 0;
302 uint16 yPos = 0;
303
304 switch (fDeviceMode) {
305 case DEVICE_PENPARTNER: {
306 xPos = data[2] << 8 | data[1];
307 yPos = data[4] << 8 | data[3];
308
309 eraser = (data[5] & 0x20);
310
311 int8 pressureData = data[6];
312 pressure = (float)(pressureData + 120) / 240.0;
313
314 firstButton = ((pressureData > -80) && !(data[5] & 0x20));
315 secondButton = (data[5] & 0x40);
316
317 hasContact = true;
318 break;
319 }
320 case DEVICE_GRAPHIRE:
321 case DEVICE_BAMBOO:
322 {
323 xPos = data[3] << 8 | data[2];
324 yPos = data[5] << 8 | data[4];
325
326 hasContact = (data[1] & 0x80);
327
328 uint16 pressureData = data[7] << 8 | data[6];
329 pressure = (float)pressureData / 511.0;
330 eraser = (data[1] & 0x20);
331
332 // mouse wheel support
333 if (data[1] & 0x40) { // mouse is on tablet!
334 wheelY = (float)(int8)data[6];
335 mode = MODE_MOUSE;
336 // override contact to loose it as soon as possible
337 // when mouse is lifted from tablet
338 hasContact = (uint8)data[7] >= 30;
339 pressure = 0.0;
340 eraser = 0;
341 }
342
343 firstButton = pressure > 0.0 ? true : (data[1] & 0x01);
344 secondButton = (data[1] & 0x02);
345 thirdButton = (data[1] & 0x04);
346
347 break;
348 }
349 case DEVICE_BAMBOO_PT:
350 {
351 if (dataBytes < 20) { // ignore touch-packets
352 xPos = data[3] << 8 | data[2];
353 yPos = data[5] << 8 | data[4];
354
355 hasContact = (data[1] & 0x20);
356
357 uint16 pressureData = data[7] << 8 | data[6];
358 pressure = (float)pressureData / 1023.0;
359 eraser = (data[1] & 0x08);
360
361 firstButton = (data[1] & 0x01);
362 secondButton = (data[1] & 0x02);
363 thirdButton = (data[1] & 0x04);
364
365 break;
366 }
367 }
368 case DEVICE_INTUOS:
369 case DEVICE_INTUOS3:
370 case DEVICE_CINTIQ:
371 if ((data[0] == 0x02) && !(((data[1] >> 5) & 0x03) == 0x02)) {
372 if (fDeviceMode == DEVICE_INTUOS3) {
373 xPos = (data[2] << 9) | (data[3] << 1)
374 | ((data[9] >> 1) & 1);
375 yPos = (data[4] << 9) | (data[5] << 1) | (data[9] & 1);
376 } else {
377 xPos = (data[2] << 8) | data[3];
378 yPos = (data[4] << 8) | data[5];
379 }
380 uint16 pressureData = data[6] << 2 | ((data[7] >> 6) & 0x03);
381 pressure = (float)pressureData / 1023.0;
382
383 // mouse and wheel support
384 if (data[1] == 0xf0) { // mouse is on tablet!
385 mode = MODE_MOUSE;
386
387 if (data[8] == 0x02)
388 wheelY = 1.0;
389 else if (data[8] == 0x01)
390 wheelY = -1.0;
391
392 firstButton = (data[8] & 0x04);
393 secondButton = (data[8] & 0x10);
394 thirdButton = (data[8] & 0x08);
395
396 // override contact to loose it as soon as possible
397 // when mouse is lifted from tablet
398 hasContact = data[9] <= 0x68;
399 pressure = 0.0;
400 eraser = 0;
401 } else {
402 firstButton = (data[6] > 2);
403 // For Intuos it MUST be >1,
404 // but '>1' still gets false actuations (shaking)
405 secondButton = (data[1] & 0x02);
406 thirdButton = (data[1] & 0x04);
407 hasContact = (data[1] & 0x40);
408 // TODO: is this meaningful? (always true on Intuos)
409 if (fDeviceMode == DEVICE_INTUOS) { // TODO: test perhaps superfluous?
410 // Original Intuos protocol:
411 // data[6] is used to signal use of the eraser,
412 // as well as being the high bits of pressure.
413 // While not in contact:
414 // If the pen end is lowermost data[6] = 1;
415 // If the eraser end is down data[6] = 0, and pressure is strictly 0
416 // data[9] (top 5 bits: 0x70..0xd0) indicates height above the tablet.
417 eraser = fEraser;
418 // keep established value unless not touching pad
419 // Eraser state only valid when away from surface
420 if (data[6] <= 1 && data[9] > 0x80) { // not touching tablet
421 if (pressureData == 0) eraser = 1; // strictly 0 means eraser
422 else if (pressureData > 6) eraser = 0; // avoid slop
423 }
424 }
425 // Get raw tilt values (0..54..127)
426 int8 tiltDataX = ((data[7] & 0x3f) << 1) | ((data[8] & 0x80) >> 7);
427 int8 tiltDataY = data[8] & 0x7f;
428 // convert to floats
429 tiltX = (float)(tiltDataX - 64) / 64.0;
430 tiltY = (float)(tiltDataY - 64) / 64.0;
431 }
432 }
433 break;
434 case DEVICE_PL500: {
435 hasContact = ( data[1] & 0x20);
436 xPos = data[2] << 8 | data[3];
437 yPos = data[5] << 8 | data[6];
438 firstButton = (data[4] & 0x08);
439 secondButton = (data[4] & 0x10);
440 thirdButton = (data[4] & 0x20);
441 uint16 pressureData = (data[4] & 0x04) >> 2 | (data[7] & 0x7f) << 1;
442 pressure = (float)pressureData / 511.0;
443 break;
444 }
445 case DEVICE_VOLITO: {
446 eraser = 0;
447 thirdButton = 0;
448
449 xPos = data[3] << 8 | data[2];
450 yPos = data[5] << 8 | data[4];
451
452 hasContact = (data[1] & 0x80);
453
454 firstButton = (data[1] & 0x01) == 1;
455 secondButton = data[1] & 0x04;
456
457 uint16 pressureData = data[7] << 8 | data[6];
458 pressure = (float)pressureData / 511.0;
459
460 if (data[1] & 0x40) { // mouse is on tablet
461 wheelY = 0;
462 mode = MODE_MOUSE;
463 hasContact = (uint8)data[7] >= 30;
464 pressure = 0.0;
465 secondButton = data[1] & 0x02;
466 }
467
468 break;
469 }
470 case DEVICE_PENSTATION: {
471 xPos = data[3] << 8 | data[2];
472 yPos = data[5] << 8 | data[4];
473 hasContact = (data[1] & 0x10);
474 uint16 pressureData = data[7] << 8 | data[6];
475 pressure = (float)pressureData / 511.0;
476 firstButton = (data[1] & 0x01);
477 secondButton = (data[1] & 0x02);
478 thirdButton = (data[1] & 0x04);
479 break;
480 }
481 }
482 if (pressure > 1.0)
483 pressure = 1.0;
484 else if (pressure < 0.0)
485 pressure = 0.0;
486 buttons = (firstButton ? B_PRIMARY_MOUSE_BUTTON : 0)
487 | (secondButton ? B_SECONDARY_MOUSE_BUTTON : 0)
488 | (thirdButton ? B_TERTIARY_MOUSE_BUTTON : 0);
489 x = (float)xPos;
490 y = (float)yPos;
491 }
492
493 // SetStatus
494 void
SetStatus(uint32 mode,uint32 buttons,float x,float y,float pressure,int32 clicks,uint32 modifiers,int32 eraser,float wheelX,float wheelY,float tiltX,float tiltY,const uchar * data)495 TabletDevice::SetStatus(uint32 mode, uint32 buttons, float x, float y,
496 float pressure, int32 clicks, uint32 modifiers, int32 eraser,
497 float wheelX, float wheelY, float tiltX, float tiltY, const uchar* data)
498 {
499 if (fActive) {
500 uint32 what = B_MOUSE_MOVED;
501 if (buttons > fButtons)
502 what = B_MOUSE_DOWN;
503 else if (buttons < fButtons)
504 what = B_MOUSE_UP;
505
506
507 #if DEBUG
508 float tabletX = x;
509 float tabletY = y;
510 #endif
511 x /= fMaxX;
512 y /= fMaxY;
513
514 float deltaX = 0.0;
515 float deltaY = 0.0;
516
517 float absDeltaX = 0.0;
518 float absDeltaY = 0.0;
519
520 float unfilteredX = x;
521 float unfilteredY = y;
522
523 if (fHasContact) {
524 deltaX = x - fPosX;
525 deltaY = y - fPosY;
526
527 absDeltaX = fabsf(deltaX);
528 absDeltaY = fabsf(deltaY);
529
530 #if 0 //DEBUG
531 fParent->LogString() << "x: " << x << ", y: " << y << ", pressure: " << pressure << "\n";
532 fParent->LogString() << "tilt x: " << tiltX << ", tilt y: " << tiltY << "\n\n";
533 #endif
534 // apply a bit of filtering
535 if (absDeltaX < fJitterX)
536 x = fPosX;
537 if (absDeltaY < fJitterY)
538 y = fPosY;
539 }
540
541 // only do send message if something changed
542 if (x != fPosX || y != fPosY || fButtons != buttons || pressure != fPressure
543 || fEraser != eraser || fTiltX != tiltX || fTiltY != tiltY) {
544
545 bigtime_t now = system_time();
546
547 // common fields for any mouse message
548 BMessage* event = new BMessage(what);
549 event->AddInt64("when", now);
550 event->AddInt32("buttons", buttons);
551 if (mode == MODE_PEN) {
552 event->AddFloat("x", x);
553 event->AddFloat("y", y);
554 event->AddFloat("be:tablet_x", unfilteredX);
555 event->AddFloat("be:tablet_y", unfilteredY);
556 event->AddFloat("be:tablet_pressure", pressure);
557 event->AddInt32("be:tablet_eraser", eraser);
558 if (_DeviceSupportsTilt()) {
559 event->AddFloat("be:tablet_tilt_x", tiltX);
560 event->AddFloat("be:tablet_tilt_y", tiltY);
561 }
562 // adjust mouse coordinates as well
563 // to have the mouse appear at the pens
564 // last position when switching
565 fFakeMouseX = unfilteredX;
566 fFakeMouseY = unfilteredY;
567 } else if (mode == MODE_MOUSE) {
568 // apply acceleration
569 float accelerationX = fJitterX * ACCELERATION_KICK_IN;
570 // if (absDeltaX > accelerationX)
571 deltaX *= absDeltaX / accelerationX;
572 float accelerationY = fJitterY * ACCELERATION_KICK_IN;
573 // if (absDeltaY > accelerationY)
574 deltaY *= absDeltaY / accelerationY;
575 // calculate screen coordinates
576 fFakeMouseX = min_c(1.0, max_c(0.0, fFakeMouseX + deltaX));
577 fFakeMouseY = min_c(1.0, max_c(0.0, fFakeMouseY + deltaY));
578 event->AddFloat("x", fFakeMouseX);
579 event->AddFloat("y", fFakeMouseY);
580 event->AddFloat("be:tablet_x", fFakeMouseX);
581 event->AddFloat("be:tablet_y", fFakeMouseY);
582 }
583 event->AddInt32("modifiers", modifiers);
584
585 #if DEBUG
586 if (data) {
587 event->AddData("raw usb data", B_RAW_TYPE, data, 12);
588 }
589 event->AddFloat("tablet x", tabletX);
590 event->AddFloat("tablet y", tabletY);
591 #endif
592 // additional fields for mouse down or up
593 if (what == B_MOUSE_DOWN) {
594 if (now - fLastClickTime < fParent->DoubleClickSpeed()) {
595 fClicks++;
596 if (fClicks > 3)
597 fClicks = 1;
598 } else {
599 fClicks = 1;
600 }
601 fLastClickTime = now;
602 event->AddInt32("clicks", fClicks);
603 } else if (what == B_MOUSE_UP)
604 event->AddInt32("clicks", 0);
605
606 status_t ret = fParent->EnqueueMessage(event);
607 if (ret < B_OK)
608 PRINT(("EnqueueMessage(): %s\n", strerror(ret)));
609
610 // apply values to members
611 fPosX = x;
612 fPosY = y;
613 fButtons = buttons;
614 fPressure = pressure;
615 fModifiers = modifiers;
616 fEraser = eraser;
617 fTiltX = tiltX;
618 fTiltY = tiltY;
619 }
620
621 // separate wheel changed message
622 if (fWheelX != wheelX || fWheelY != wheelY) {
623 BMessage* event = new BMessage(B_MOUSE_WHEEL_CHANGED);
624 event->AddInt64("when", system_time());
625 event->AddFloat("be:wheel_delta_x", wheelX);
626 event->AddFloat("be:wheel_delta_y", wheelY);
627 fParent->EnqueueMessage(event);
628
629 // apply values to members
630 fWheelX = wheelX;
631 fWheelY = wheelY;
632 }
633 }
634 }
635
636 // SetContact
637 void
SetContact(bool contact)638 TabletDevice::SetContact(bool contact)
639 {
640 fHasContact = contact;
641 }
642
643 // poll_usb_device
644 int32
poll_usb_device(void * arg)645 TabletDevice::poll_usb_device(void* arg)
646 {
647 TabletDevice* tabletDevice = (TabletDevice*)arg;
648 DeviceReader* reader = tabletDevice->fReader;
649
650 if (!reader || reader->InitCheck() < B_OK)
651 return B_BAD_VALUE;
652
653 int dataBytes = reader->MaxPacketSize();
654 if (dataBytes > 128)
655 return B_BAD_VALUE;
656
657 uchar data[max_c(12, dataBytes)];
658
659 while (tabletDevice->IsActive()) {
660
661 status_t ret = reader->ReadData(data, dataBytes);
662
663 if (ret == dataBytes) {
664 // data we read from the wacom device
665 uint32 mode;
666 bool hasContact = false;
667 uint32 buttons = 0;
668 float x = 0.0;
669 float y = 0.0;
670 float pressure = 0.0;
671 int32 clicks = 0;
672 int32 eraser = 0;
673 float wheelX = 0.0;
674 float wheelY = 0.0;
675 float tiltX = 0.0;
676 float tiltY = 0.0;
677 // let the device extract all information from the data
678 tabletDevice->ReadData(data, dataBytes, hasContact, mode, buttons,
679 x, y, pressure, clicks, eraser,
680 wheelX, wheelY, tiltX, tiltY);
681 if (hasContact) {
682 // apply the changes to the device
683 tabletDevice->SetStatus(mode, buttons, x, y, pressure,
684 clicks, modifiers(), eraser,
685 wheelX, wheelY, tiltX, tiltY, data);
686 } else
687 PRINT(("device has no contact\n"));
688 tabletDevice->SetContact(hasContact);
689 } else {
690 PRINT(("failed to read %ld bytes, read: %ld or %s\n",
691 dataBytes, ret, strerror(ret)));
692
693 if (ret < B_OK) {
694 if (ret == B_TIMED_OUT)
695 snooze(SNOOZE_AMOUNT);
696 else if (ret == B_INTERRUPTED)
697 snooze(SNOOZE_AMOUNT);
698 else {
699 return ret;
700 }
701 }
702 }
703 }
704
705 return B_OK;
706 }
707
708 // _DeviceSupportsTilt
709 bool
_DeviceSupportsTilt() const710 TabletDevice::_DeviceSupportsTilt() const
711 {
712 bool tilt = false;
713 switch (fDeviceMode) {
714 case DEVICE_INTUOS:
715 case DEVICE_INTUOS3:
716 case DEVICE_CINTIQ:
717 tilt = true;
718 break;
719 }
720 return tilt;
721 }
722
723 // _GetName
724 void
_GetName(uint16 productID,const char ** name) const725 TabletDevice::_GetName(uint16 productID, const char** name) const
726 {
727 switch (productID) {
728 case 0x00:
729 *name = "Wacom USB";
730 break;
731 case 0x03: // driver does not support this yet
732 *name = "Wacom Cintiq Partner USB";
733 break;
734 case 0x10:
735 *name = "Wacom Graphire USB";
736 break;
737 case 0x11:
738 *name = "Wacom Graphire2 4x5\" USB";
739 break;
740 case 0x12:
741 *name = "Wacom Graphire2 5x7\" USB";
742 break;
743 case 0x13:
744 *name = "Wacom Graphire3 4x5\" USB";
745 break;
746 case 0x14:
747 *name = "Wacom Graphire3 6x8\" USB";
748 break;
749 case 0x15:
750 *name = "Wacom Graphire4 4x5\" USB";
751 break;
752 case 0x16:
753 *name = "Wacom Graphire4 6x8\" USB";
754 break;
755 case 0x17:
756 *name = "Wacom BambooFun 4x5\" USB";
757 break;
758 case 0x18:
759 *name = "Wacom BambooFun 6x8\" USB";
760 break;
761 case 0x20:
762 *name = "Wacom Intuos 4x5\" USB";
763 break;
764 case 0x21:
765 *name = "Wacom Intuos 6x8\" USB";
766 break;
767 case 0x22:
768 *name = "Wacom Intuos 9x12\" USB";
769 break;
770 case 0x23:
771 *name = "Wacom Intuos 12x12\" USB";
772 break;
773 case 0x24:
774 *name = "Wacom Intuos 12x18\" USB";
775 break;
776 case 0x30:
777 *name = "Wacom PL400 USB";
778 break;
779 case 0x31:
780 *name = "Wacom PL500 USB";
781 break;
782 case 0x32:
783 *name = "Wacom PL600 USB";
784 break;
785 case 0x33:
786 *name = "Wacom PL600SX USB";
787 break;
788 case 0x34:
789 *name = "Wacom PL550 USB";
790 break;
791 case 0x35:
792 *name = "Wacom PL800 USB";
793 break;
794
795 case 0x3F:
796 *name = "Wacom Cintiq 21UX USB";
797 break;
798
799 case 0x41:
800 *name = "Wacom Intuos2 4x5\" USB";
801 break;
802 case 0x42:
803 *name = "Wacom Intuos2 6x8\" USB";
804 break;
805 case 0x43:
806 *name = "Wacom Intuos2 9x12\" USB";
807 break;
808 case 0x44:
809 *name = "Wacom Intuos2 12x12\" USB";
810 break;
811 case 0x45:
812 *name = "Wacom Intuos2 12x18\" USB";
813 break;
814 case 0x47: // some I2 6x8s seem to report as 0x47
815 *name = "Wacom Intuos2 6x8\" USB";
816 break;
817
818 case 0x60:
819 *name = "Wacom Volito USB";
820 break;
821 case 0x61:
822 *name = "Wacom PenStation USB";
823 break;
824 case 0x62:
825 *name = "Wacom Volito2 USB";
826 break;
827 case 0x64:
828 *name = "Wacom PenPartner.1 USB";
829 break;
830 case 0x65:
831 *name = "Wacom Bamboo USB";
832 break;
833 case 0x69:
834 *name = "Wacom Bamboo1 USB";
835 break;
836
837 case 0xB0:
838 *name = "Wacom Intuos3 4x5 USB";
839 break;
840 case 0xB1:
841 *name = "Wacom Intuos3 6x8 USB";
842 break;
843 case 0xB2:
844 *name = "Wacom Intuos3 9x12 USB";
845 break;
846
847 case 0xD0:
848 *name = "Wacom Bamboo 2FG USB";
849 break;
850 case 0xD1:
851 *name = "Wacom BambooFun 2FG 4x5\" USB";
852 break;
853 case 0xD2:
854 *name = "Wacom Bamboo Craft USB";
855 break;
856 case 0xD3:
857 *name = "Wacom BambooFun 2FG 6x8\" USB";
858 break;
859 case 0xD4:
860 *name = "Wacom Bamboo 4x5\" USB";
861 break;
862 case 0xD6:
863 *name = "Wacom Bamboo (CTH-460/K)";
864 break;
865 case 0xD7:
866 *name = "Wacom Bamboo (CTH-461/S)";
867 break;
868 case 0xD8:
869 *name = "Wacom Bamboo (CTH-661/S1)";
870 break;
871 case 0xDA:
872 *name = "Wacom Bamboo (CTH-461/L)";
873 break;
874 case 0xDB:
875 *name = "Wacom Bamboo (CTH-661)";
876 break;
877 case 0xDD:
878 *name = "Wacom Bamboo Pen/Connect (CTL-470)";
879 break;
880 case 0x0301:
881 *name = "One by Wacom (CTL-671)";
882 break;
883 case 0x037b:
884 *name = "One by Wacom (CTL-672)";
885 break;
886
887 default:
888 *name = "<unkown wacom tablet>";
889 break;
890 }
891 }
892
893