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
37TabletDevice::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
59TabletDevice::~TabletDevice()
60{
61	// cleanup
62	Stop();
63}
64
65// InitCheck
66status_t
67TabletDevice::InitCheck()
68{
69	status_t status = PointingDevice::InitCheck();
70	if (status >= B_OK)
71		status = DetectDevice(fReader);
72	return status;
73}
74
75// Start
76status_t
77TabletDevice::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
97status_t
98TabletDevice::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
111status_t
112TabletDevice::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
278void
279TabletDevice::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
289void
290TabletDevice::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
494void
495TabletDevice::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
531fParent->LogString() << "x: " << x << ", y: " << y << ", pressure: " << pressure << "\n";
532fParent->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
586if (data) {
587	event->AddData("raw usb data", B_RAW_TYPE, data, 12);
588}
589event->AddFloat("tablet x", tabletX);
590event->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
637void
638TabletDevice::SetContact(bool contact)
639{
640	fHasContact = contact;
641}
642
643// poll_usb_device
644int32
645TabletDevice::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
709bool
710TabletDevice::_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
724void
725TabletDevice::_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