00001
00002
00003
00004
00005
00006
00007
00008 #include <cassert>
00009 #include <cstring>
00010 #include <iostream>
00011 #include <iomanip>
00012 #include <Magick++.h>
00013 #include "WacomIntuos4LED.h"
00014
00015 using namespace std;
00016 using namespace Magick;
00017
00018 #define WAC_VENDOR_ID 0x056a
00019 #define WAC_INTUOS4_M_PRODUCT_ID 0x00b9
00020 #define WAC_USB_TIMEOUT 100
00021 #define WAC_USB_RETRIES 10
00022 #define ICON_WIDTH 64
00023 #define ICON_HEIGHT 16
00024
00025
00026
00027
00028 extern const unsigned char icon_alt[1024];
00029 extern const unsigned char icon_arrow_up[1024];
00030 extern const unsigned char icon_blank[1024];
00031 extern const unsigned char icon_button_1[1024];
00032 extern const unsigned char icon_button_2[1024];
00033 extern const unsigned char icon_button_3[1024];
00034 extern const unsigned char icon_button_4[1024];
00035 extern const unsigned char icon_button_5[1024];
00036 extern const unsigned char icon_button_6[1024];
00037 extern const unsigned char icon_button_7[1024];
00038 extern const unsigned char icon_button_8[1024];
00039 extern const unsigned char icon_ctrl[1024];
00040 extern const unsigned char icon_debian_logo[1024];
00041 extern const unsigned char icon_number_1[1024];
00042 extern const unsigned char icon_number_2[1024];
00043 extern const unsigned char icon_number_3[1024];
00044 extern const unsigned char icon_number_4[1024];
00045 extern const unsigned char icon_number_5[1024];
00046 extern const unsigned char icon_number_6[1024];
00047 extern const unsigned char icon_number_7[1024];
00048 extern const unsigned char icon_number_8[1024];
00049 extern const unsigned char icon_redo[1024];
00050 extern const unsigned char icon_save[1024];
00051 extern const unsigned char icon_shift[1024];
00052 extern const unsigned char icon_space[1024];
00053 extern const unsigned char icon_tux[1024];
00054 extern const unsigned char icon_undo[1024];
00055 extern const unsigned char icon_wacom_logo[1024];
00056 extern const unsigned char icon_zoom_in[1024];
00057 extern const unsigned char icon_zoom_out[1024];
00058
00059
00060 WacomIntuos4LED::WacomIntuos4LED() {
00061 initIconLibrary();
00062 }
00063
00064 void WacomIntuos4LED::initIconLibrary() {
00065 context=NULL;
00066 dev_handle=NULL;
00067
00068 icon_table["Alt"] = icon_alt;
00069 icon_table["ArrowUp"] = icon_arrow_up;
00070 icon_table["Blank"] = icon_blank;
00071 icon_table["ButtonOne"] = icon_button_1;
00072 icon_table["ButtonTwo"] = icon_button_2;
00073 icon_table["ButtonThree"] = icon_button_3;
00074 icon_table["ButtonFour"] = icon_button_4;
00075 icon_table["ButtonFive"] = icon_button_5;
00076 icon_table["ButtonSix"] = icon_button_6;
00077 icon_table["ButtonSeven"] = icon_button_7;
00078 icon_table["ButtonEight"] = icon_button_8;
00079 icon_table["Ctrl"] = icon_ctrl;
00080 icon_table["DebianLogo"] = icon_debian_logo;
00081 icon_table["NumberOne"] = icon_number_1;
00082 icon_table["NumberTwo"] = icon_number_2;
00083 icon_table["NumberThree"] = icon_number_3;
00084 icon_table["NumberFour"] = icon_number_4;
00085 icon_table["NumberFive"] = icon_number_5;
00086 icon_table["NumberSix"] = icon_number_6;
00087 icon_table["NumberSeven"] = icon_number_7;
00088 icon_table["NumberEight"] = icon_number_8;
00089 icon_table["Redo"] = icon_redo;
00090 icon_table["Save"] = icon_save;
00091 icon_table["Shift"] = icon_shift;
00092 icon_table["Space"] = icon_space;
00093 icon_table["Tux"] = icon_tux;
00094 icon_table["Undo"] = icon_undo;
00095 icon_table["WacomLogo"] = icon_wacom_logo;
00096 icon_table["ZoomIn"] = icon_zoom_in;
00097 icon_table["ZoomOut"] = icon_zoom_out;
00098 }
00099
00100 WacomIntuos4LED::~WacomIntuos4LED() {
00101 if (context != NULL) {
00102 libusb_exit(context);
00103 }
00104 }
00105
00106 unsigned char WacomIntuos4LED::transformShade(double shade) const {
00107 unsigned char c=(unsigned char)(shade*16.0);
00108 if (c>=0x10) c=0x0f;
00109 return c;
00110 }
00111
00112 int WacomIntuos4LED::toIndex(int x, int y) const {
00113 return (x+ICON_WIDTH*y);
00114 }
00115
00116 void WacomIntuos4LED::flipIconVertically(unsigned char *icon) const {
00117 unsigned char c;
00118
00119 for (int y = 0; y < ICON_HEIGHT; y++) {
00120 for (int x = 0; x < ICON_WIDTH/2; x++) {
00121 c = icon[toIndex(x,y)];
00122 icon[toIndex(x,y)] = icon[toIndex(ICON_WIDTH -1 - x ,y)];
00123 icon[toIndex(ICON_WIDTH -1 - x ,y)] = c;
00124 }
00125 }
00126 }
00127
00128 void WacomIntuos4LED::flipIconHorizontally(unsigned char *icon) const {
00129 unsigned char c;
00130
00131 for (int x = 0; x < ICON_WIDTH; x++) {
00132 for (int y = 0; y < ICON_HEIGHT/2; y++) {
00133 c = icon[toIndex(x,y)];
00134 icon[toIndex(x,y)] = icon[toIndex(x,ICON_HEIGHT-y-1)];
00135 icon[toIndex(x,ICON_HEIGHT-y-1)] = c;
00136 }
00137 }
00138
00139 for (int i=0; i<ICON_HEIGHT*ICON_WIDTH; i++) {
00140 c = (icon[i]>>4) + (icon[i]<<4);
00141 icon[i] = c;
00142 }
00143
00144
00145 }
00146
00147
00148 int WacomIntuos4LED::sendControlMsg(uint8_t bm_request_type, uint8_t b_request,
00149 uint16_t w_value, uint16_t w_index, unsigned char *data,
00150 uint16_t w_length, unsigned int timeout, unsigned int retries) {
00151 int rv = 0;
00152 int cntr = 0;
00153
00154 do {
00155 rv = libusb_control_transfer(dev_handle, bm_request_type,
00156 b_request,
00157 w_value,
00158 w_index,
00159 data,
00160 w_length,
00161 timeout
00162 );
00163 cntr++;
00164 } while (rv < 0 && cntr < retries);
00165
00166 return rv;
00167 }
00168
00169 bool WacomIntuos4LED::deviceEnabled() const {
00170 return (dev_handle != NULL);
00171 }
00172
00173 bool WacomIntuos4LED::deviceDisabled() const {
00174 return (dev_handle == NULL);
00175 }
00176
00177 bool WacomIntuos4LED::displayPalette(bool right_handed) {
00178 unsigned char icon[8][1024];
00179 unsigned char c;
00180
00181 for (int b=0; b<8; b++) {
00182 c = b;
00183 c = (c << 4) + b+1;
00184 for (int i=0; i<512; i++) {
00185 icon[b][i]=(2*b << 4) + 2*b;
00186 icon[b][512+i] = (2*b+1 << 4) + 2*b+1;
00187 }
00188 setIcon(b, icon[b], right_handed);
00189 }
00190
00191 }
00192
00193 bool WacomIntuos4LED::setTransferMode(bool mode) {
00194 int rv = 0;
00195 unsigned char buf[2];
00196
00197 if (deviceDisabled()) {
00198 return false;
00199 }
00200
00201 buf[0] = 0x21;
00202 buf[1] = mode;
00203
00204 rv = sendControlMsg(0x21,
00205 0x09,
00206 0x0321,
00207 0,
00208 buf,
00209 2,
00210 WAC_USB_TIMEOUT,
00211 WAC_USB_RETRIES);
00212
00213 return (rv >= 0);
00214 }
00215
00216 bool WacomIntuos4LED::setLibraryIcon(unsigned int button, string name, bool right_handed) {
00217 if (icon_table.count(name)==0) {
00218 return false;
00219 } else {
00220 return setIcon(button, icon_table[name], right_handed);
00221 }
00222 }
00223
00224
00225 bool WacomIntuos4LED::setImage(unsigned int button, string file, bool right_handed) {
00226 unsigned char data[1024];
00227
00228 if (imageToIcon(file, data)) {
00229 return setIcon(button, data, right_handed);
00230 } else {
00231 return false;
00232 }
00233 }
00234
00235
00236 bool WacomIntuos4LED::dumpImageAsStaticData(string file, string name) {
00237 unsigned char data[1024];
00238
00239 if (imageToIcon(file, data)) {
00240 dumpIconAsStaticData(data, name);
00241 return true;
00242 } else {
00243 return false;
00244 }
00245 }
00246
00247
00248 bool WacomIntuos4LED::setIcon(unsigned int button, const unsigned char *icon, bool right_handed) {
00249 unsigned char buf[259];
00250 int c = 0;
00251 int rv = 0;
00252 unsigned char data[1024];
00253
00254 if (button>=8) {
00255 return false;
00256 }
00257
00258 if (!setTransferMode(true)) {
00259 return false;
00260 }
00261
00262 memcpy(data, icon, 1024);
00263
00264 if (!right_handed) {
00265 button = 7-button;
00266 flipIconHorizontally(data);
00267 flipIconVertically(data);
00268 }
00269
00270 buf[0] = 0x23;
00271 buf[1] = button;
00272 for (int i = 0; i < 4; i++) {
00273 buf[2] = i;
00274 for (int j = 0; j < 256; j++) {
00275 buf[3 + j] = data[256 * i + j];
00276 }
00277
00278 rv = sendControlMsg(0x21,
00279 0x09,
00280 0x0323,
00281 0,
00282 buf,
00283 259,
00284 WAC_USB_TIMEOUT,
00285 WAC_USB_RETRIES);
00286
00287 if (rv < 0) {
00288 return false;
00289 }
00290 }
00291
00292 if (!setTransferMode(false)) {
00293 return false;
00294 }
00295
00296 return true;
00297 }
00298
00299 bool WacomIntuos4LED::imageToIcon(const string& file, unsigned char* icon) const {
00300 Image image(file.c_str());
00301 ColorGray color;
00302 unsigned char l, h;
00303 int i=0;
00304
00305 image.type(GrayscaleType);
00306 int rows = image.rows();
00307 int cols = image.columns();
00308
00309 if (rows!=32 || cols!=64) {
00310 return false;
00311 }
00312
00313 for (int y=0; y<rows; y+=2) {
00314 for (int x=0; x<cols; x++) {
00315 color = image.pixelColor(x,y);
00316 l = transformShade(color.shade());
00317 color = image.pixelColor(x,y+1);
00318 h = transformShade(color.shade());
00319 icon[i]= (h << 4) + l;
00320 i++;
00321 }
00322 }
00323
00324 flipIconVertically(icon);
00325
00326 return true;
00327 }
00328
00329 bool WacomIntuos4LED::clearButton(unsigned int button, bool right_handed) {
00330 unsigned char icon[1024];
00331
00332 for (int i=0; i<1024; i++) {
00333 icon[i]=0x00;
00334 }
00335
00336 return setIcon(button, icon, right_handed);
00337 }
00338
00339 bool WacomIntuos4LED::clearAllButtons() {
00340
00341 for (int b=0; b<8; b++) {
00342 clearButton(b);
00343 }
00344
00345 return true;
00346 }
00347
00348 bool WacomIntuos4LED::init(uint16_t vendor_id, uint16_t product_id) {
00349 int rv;
00350
00351
00352
00353
00354 rv = libusb_init(&context);
00355 if (rv < 0) {
00356 cerr << "ERROR: USB library init failed." << endl;
00357 return false;
00358 }
00359
00360 dev_handle = libusb_open_device_with_vid_pid(context, vendor_id, product_id);
00361
00362 if (libusb_kernel_driver_active(dev_handle, 0) == 1) {
00363 cout << "Active kernel driver found." << endl;
00364 if (libusb_detach_kernel_driver(dev_handle, 0) == 0) {
00365 cout << "Kernel Driver Detached!" << endl;
00366 }
00367 }
00368
00369 rv = libusb_claim_interface(dev_handle, 0);
00370 if (rv < 0) {
00371 cout << "ERROR: Cannot Claim Interface" << endl;
00372 return false;
00373 }
00374 return true;
00375 }
00376
00377 bool WacomIntuos4LED::autoDetectTablet() {
00378
00379 libusb_device **dev_list = NULL;
00380
00381 int nr_of_devices = 0;
00382
00383 bool found = false;
00384
00385 libusb_device_descriptor dev_descriptor;
00386
00387 int rv=0;
00388
00389 ssize_t i=0;
00390
00391 uint16_t vendor_id;
00392
00393 uint16_t product_id;
00394
00395
00396
00397
00398 rv = libusb_init(&context);
00399 if (rv < 0) {
00400 cerr << "ERROR: USB library init failed." << endl;
00401 return false;
00402 }
00403
00404
00405
00406
00407 nr_of_devices = libusb_get_device_list(context, &dev_list);
00408
00409
00410
00411
00412 if (nr_of_devices<0) {
00413 return false;
00414 }
00415
00416
00417
00418
00419 while (i < nr_of_devices && !found) {
00420
00421
00422
00423 rv = libusb_get_device_descriptor(dev_list[i], &dev_descriptor);
00424 if (rv<0) {
00425 cerr << "Error during retrieval of device information." << endl;
00426 } else {
00427
00428
00429
00430 vendor_id = dev_descriptor.idVendor;
00431 product_id = dev_descriptor.idProduct;
00432
00433
00434
00435
00436 if (vendor_id==WAC_VENDOR_ID) {
00437 if (product_id==WAC_INTUOS4_M_PRODUCT_ID) {
00438 found=true;
00439 }
00440 }
00441
00442 }
00443 i++;
00444 }
00445
00446
00447
00448
00449 libusb_free_device_list(dev_list, 1);
00450
00451
00452
00453
00454 if (found) {
00455 found = init(vendor_id, product_id);
00456 }
00457
00458
00459
00460
00461 return found;
00462 }
00463
00464 void WacomIntuos4LED::dumpIconNames() const {
00465
00466 map<string,const unsigned char*>::const_iterator map_it;
00467
00468 for (map_it=icon_table.begin(); map_it!=icon_table.end(); map_it++) {
00469 cout << map_it->first << endl;
00470 }
00471 }
00472
00473 void WacomIntuos4LED::dumpIconAsStaticData(unsigned char* icon, string name) const {
00474 int steps=16;
00475
00476 cout << "unsigned char " << name << "[1024] = {" << endl << "\t";
00477
00478 for (int i=0; i<1024; i++) {
00479 cout << "0x" << hex << setw(2) << setfill('0') << (int)icon[i];
00480 if (i<1023) {
00481 cout << ", ";
00482 }
00483 if ((i+1)%steps==0 && i<1023) {
00484 cout << endl << "\t";
00485 }
00486 }
00487 cout << endl << "};" << endl;
00488 }
00489