Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

tablet.C

Go to the documentation of this file.
00001 // tablet.C
00002 
00003 #if defined(linux) || defined(_AIX)
00004 #include <sys/ioctl.h>
00005 #elif WIN32
00006 // XXX: Temporary until win32 serial support gets figured out
00007 #define ioctl(a,b,c)
00008 #else
00009 #include <sys/filio.h>
00010 #endif
00011 
00012 #include "dev.H"
00013 #include "tablet.H"
00014 
00015 #include "std/config.H"
00016 
00017 using namespace mlib;
00018 
00019 #define BIT(N, INT)         ((1 << N) & ((int)(INT)))
00020 #define BITS(SN, EN, INT)    (((1 << EN) -1) & (~((1 << SN)-1)) & ((int)(INT)))
00021 
00022 static bool debug = Config::get_var_bool("DEBUG_TABLET",false,true);
00023 
00024 TabletDesc::TabletDesc(
00025    TabletType t
00026    )
00027 {
00028    switch (t) {
00029     case CROSS      : *this = TabletDesc(B19200, 5, "@",     5000);
00030       brcase LCD        : *this = TabletDesc(B9600,  7,  "",     3162);
00031       brcase TINY       : *this = TabletDesc(B9600,  7,  "",     3162);
00032       brcase MULTI_MODE : *this = TabletDesc(B9600,  7, "MU1\n", 15000);
00033       brcase LARGE      : *this = TabletDesc(B9600,  7,  "",     15000);
00034       brcase SMALL      : *this = TabletDesc(B9600,  7,  "",     6000);
00035       brcase INTUOS     : *this = TabletDesc(B9600,  9,  "MT1\nID1\nIT0\n", 16240);
00036    }
00037    _type = t;
00038 }
00039 
00040 Tablet::Tablet( 
00041    FD_MANAGER *manager,
00042    TabletDesc::TabletType  ttype,
00043    const char *dev,
00044    const char *name
00045    ) : TTYfd(manager, dev, name), _styl_buttons( &_stylus ), _desc(ttype)
00046 {
00047    if (!_dev[0])
00048       strcpy(_dev, DEV_DFLT_SERIAL_PORT);
00049 }
00050 
00051 int 
00052 Tablet::activate()
00053 {
00054    int ret = TTYfd::activate();
00055    if (ret) {
00056       set_speed   (_desc._baud);
00057       set_stopbits(1);
00058       set_charsize(CS8);
00059       set_parity  (TTY_NONE);
00060 
00061       if (_desc._init_str != str_ptr()) {
00062          if (write(**_desc._init_str, strlen(**_desc._init_str), 20) < 0)
00063             perror("initializing tablet");
00064       }
00065    }
00066 
00067    return ret;
00068 }
00069 
00070 // Read the "tablet setting" from the Wacom Tablet using the ~R command.
00071 // modify bit number 'bit_num' to be 1 or 0 based on 'value'.  Then
00072 // write the "tablet setting" using the ~W command.
00073 void
00074 Tablet::mod_setting_bit( int bit_num, int value )
00075 {
00076    // check that it's a wacom tablet..
00077    if (_desc._type == TabletDesc::TINY       ||
00078        _desc._type == TabletDesc::SMALL      ||
00079        _desc._type == TabletDesc::LARGE      ||
00080        _desc._type == TabletDesc::MULTI_MODE ||
00081        _desc._type == TabletDesc::LCD        ||
00082        _desc._type == TabletDesc::INTUOS) {
00083       char buffer[256];
00084 
00085       if (write("~R\n", 3, 20) < 0)
00086          perror("Tablet::mod_setting_bit(..)");
00087 
00088       nread(buffer, strlen("~Rdddddddd,ddd,dd,dddd,dddd\n"), 20);
00089 
00090       cerr << "buffer = '" << buffer << "'" << endl;
00091 
00092       int byte = (bit_num / 8);
00093       int bit  = (bit_num % 8);
00094 
00095       // only allow modification of 1st 8 bytes
00096       // (does it make sense to modify other bytes?)
00097       assert(byte >= 0 && byte < 8);
00098 
00099       if (value) {
00100          // (plus 2 because of the 2 command chars (i.e., "~R") )
00101          buffer[byte+2] |=  (1 << bit); 
00102       } else {
00103          buffer[byte+2] &= ~(1 << bit);
00104       }
00105 
00106       buffer[1] = '*'; // cmd to use so new settings take effect immediately
00107       cerr << "buffer = '" << buffer << "'" << endl;
00108 //       write(buffer, strlen("~*dddddddd,ddd,dd,dddd,dddd\n"), 20);
00109    } else {
00110       cerr << "*** don't know how to 'mod_setting_bit' "
00111            << "for tablet in use.." << endl;
00112    }
00113 }
00114 
00115 TabletEvent::TabletEvent( 
00116    char        *buf, 
00117    TabletDesc  *desc
00118    ):_desc(desc), _is_valid(1)
00119 {
00120    double yres = double(_desc->_yres);
00121    // Try to make sure this record is aligned properly-- that is the 7th
00122    // bit of the 1st byte should be set to `1`.
00123    assert(BIT(7, buf[0]));
00124   
00125    // Generate appropriate event for byte contents of 'buf'
00126    // Compute values for pos[0], pos[1], and buttons
00127    double rawx, rawy;
00128 
00129    if (_desc->_type == TabletDesc::CROSS) {
00130       rawx = (((buf[2] & 0x7f)<<7) | (buf[1] & 0x7f));// X coord from byte 1 & 2
00131       rawy = (((buf[4] & 0x7f)<<7) | (buf[3] & 0x7f));// Y coord from byte 4 & 5
00132       _pos[0]  = 2*(rawx/ 7000.0 - 0.5);
00133       _pos[1]  = 2*(rawy/ yres - 0.5);
00134       _buttons = buf[0] & 3;
00135       _device  = STYLUS;
00136       _touching_tablet = BIT(5,buf[0]);    // (is device touching the tablet?)
00137 
00138    } else if(_desc->_type == TabletDesc::INTUOS) {
00139       _device = STYLUS;
00140       int dev = BIT(0,buf[0]);
00141       static int device_type[2];
00142       _is_eraser = ((device_type[dev]&0x7ff) != 0x0022);
00143 
00144       if((buf[0] & 0xfc) == 0xc0) {
00145          /* device id packet */
00146          device_type[dev] = ((buf[1]&0x7f) << 5) | ((buf[2]&0x7c) >> 2);
00147          _is_valid = 0;
00148       }
00149       else if((buf[0] & 0xfe) == 0x80) {
00150          /* out of proximity packet */
00151          _touching_tablet = 0;
00152          _is_valid = 0;         /* hack to make jot work */
00153       }
00154       else if((buf[0]&0xb8) == 0xa0) {
00155          /* pen packet */
00156          rawx = (((buf[1] & 0x7f) << 9) | ((buf[2] & 0x7f) << 2)
00157                  | ((buf[3] & 0x60) >> 5));
00158          rawy = (((buf[3] & 0x1f) << 11) | ((buf[4] & 0x7f) << 4)
00159                  | ((buf[5] & 0x78) >> 3));
00160 
00161 
00162          // XXX - for 8x6 inch INTUOS tablet, investigations indicate
00163          // that the x-resolution is 20320:
00164          double sizex = 20320;
00165          double sizey = yres;
00166 
00167          // XXX - Temporary hack for 4x5 inch size.
00168          // event:
00169          static bool small_tablet = Config::get_var_bool("TABLET_SIZE_SMALL",false,true);
00170          
00171          if (small_tablet) {
00172             sizex=12700.0;
00173             sizey=10360.0;
00174          }
00175 
00176          _pos[0] = 2*(rawx/sizex - 0.5);
00177          _pos[1] = -2*(rawy/sizey - 0.5);
00178          _stylus_pressure = (((buf[5]&0x7)<<7) | (buf[6]&0x7f)) - 512;
00179          _buttons = ((buf[0] & 0x6) | (_stylus_pressure >= -480));
00180          _touching_tablet = BIT(6,buf[0]);
00181 
00182          if (Config::get_var_bool("DBUG_PRESSURE",false,true))
00183             cerr << _stylus_pressure << endl;
00184 
00185       }
00186       else {
00187          _is_valid = 0;
00188          fprintf(stderr, "Unknown tablet packet %02X\n", buf[0]);
00189       }
00190    } else {
00191 
00192       // Bit #5 of the first byte indicates which cursor's button and position
00193       // information is being reported.
00194       _device = (BIT(5,buf[0])) ? STYLUS : PUCK;
00195 
00196       rawx = (((buf[1] & 0x7f)<<7) | (buf[2] & 0x7f));
00197       rawy = (((buf[4] & 0x7f)<<7) | (buf[5] & 0x7f));
00198       if (_desc->_type == TabletDesc::LCD ||
00199           _desc->_type == TabletDesc::TINY) { 
00200          _pos[0] =  2*(rawx/ (yres * (211.2/158.4)) - 0.5);
00201          _pos[1] = -2*(rawy/  yres - 0.5);
00202       } else {
00203          if (yres > 7000)
00204             _pos[0] = 2*(rawx/ yres - 0.5);
00205          else _pos[0] = 2*(rawx/ yres - 0.675);
00206          _pos[1] = -2*(rawy/ yres - 0.5);
00207       }
00208       _buttons = (buf[3] >> 3) & 15; // Eraser & button in byte 3
00209       
00210       _touching_tablet = BIT(6,buf[0]);    // (is device touching the tablet?)
00211    
00212       _stylus_pressure = (int(buf[6]) & 0x3f) << 1 | ((int(buf[3]) >> 2) & 0x01);
00213       if (!BIT(6,buf[6]))
00214          _stylus_pressure += 127;
00215 
00216       if (Config::get_var_bool("DBUG_PRESSURE",false,true))
00217          cerr << _stylus_pressure << endl;
00218 
00219       if (_device == PUCK) {         // offset the position of the puck so your
00220          _pos[0] += 0.2;             // hand isn't "in the way"
00221          _pos[1] += 0.2;
00222       }
00223    }
00224 
00225    _pos[0] += Config::get_var_dbl("TABLET_OFFSET_X",0.0,true);
00226    _pos[1] += Config::get_var_dbl("TABLET_OFFSET_Y",0.0,true);
00227 }
00228 
00229 void 
00230 TabletQueue::do_enqueue( 
00231    TabletEvent &event 
00232    )
00233 {
00234    _queue[_tail] = event;
00235 
00236    if (_tail == _length-1)
00237       _tail = 0;
00238    else
00239       _tail++;
00240 
00241    if (_tail==_head)   // This should never happen!
00242       cerr << "*** ERROR: Queue overflow!" << char(7) << endl;
00243 }
00244 
00245 void 
00246 TabletQueue::enqueue( 
00247    TabletEvent &event
00248    )
00249 {
00250    if (empty()) // If there are no events in the queue, always enqueue this one.
00251       do_enqueue(event);
00252    else {
00253       // Determine the index to the last event (we know the queue is not empty)
00254       int last_event_index = ((_tail - 1) == -1) ? _length-1 : (_tail-1);
00255 
00256       // If the button state of this event is different from the last
00257       // event, always enqueue the event.
00258       if ( (event.get_buttons() != _queue[last_event_index].get_buttons()) )
00259          do_enqueue(event);
00260       else {
00261          // If the button state of this event is the same as the last event,
00262          // replace the last event with the current one.
00263          if (event.touching_tablet() != 
00264              _queue[last_event_index].touching_tablet())
00265             do_enqueue(event);
00266          else
00267             _queue[last_event_index] = event;
00268       }
00269    }
00270 }
00271 
00272 TabletEvent 
00273 TabletQueue::dequeue()
00274 {
00275    assert(!empty());
00276 
00277    TabletEvent event = _queue[_head];
00278 
00279    if( _head == _length-1 )
00280       _head = 0;
00281    else
00282       _head++;
00283 
00284    return event;
00285 }
00286 
00287 TabletMultimode::TabletMultimode( 
00288    FD_MANAGER              *mgr,
00289    TabletDesc::TabletType   ttype,
00290    const char              *tty,
00291    const char              *name
00292    ) : Tablet(mgr, ttype, tty, name), _puck_buttons(&_puck), 
00293    _using_stylus_eraser(0)
00294 {
00295    _num_bytes_left_from_last_read = 0;
00296 
00297    _stylus_queue.reset();
00298    _puck_queue  .reset();
00299 }
00300 
00301 void 
00302 TabletMultimode::enqueue_available_tablet_events()
00303 {
00304    // Read all data in input buff & combine w/ any remaining data from
00305    // last read
00306    int bytes_read = nread(_tablet_data_buffer + _num_bytes_left_from_last_read,
00307 //         4096 - _num_bytes_left_from_last_read, // NO! read only 24bytes ahead
00308            24 - _num_bytes_left_from_last_read,
00309            _timeout);
00310 
00311    if ( bytes_read < 0 ) {
00312       // Could not read any bytes!? (... maybe no events were sent.)
00313       if (debug) {
00314          cerr << "** WARNING: TabletMultimode could not read any"  << endl;
00315          cerr << "            data from the tablet."               << endl;
00316          cerr << "            (bytes_read = " << bytes_read << ")" << endl;
00317       }
00318       return;
00319    }
00320 
00321    //cerr << "bytes_in_buffer = " << _num_bytes_left_from_last_read << "\t";
00322    // What is the total number of bytes we have read?
00323    int bytes_in_buffer = (bytes_read + _num_bytes_left_from_last_read);
00324    //cerr << "(" << bytes_in_buffer << ")" << endl;
00325 
00326    // Be sure we are synchronized with the tablet records-- if not, then
00327    // throw away the first few bytes until we are.
00328    if (! BIT(7, _tablet_data_buffer[0]) ) {
00329       // this code should only hapeen once, MAYBE, the first loop through this
00330       // method. Otherwise, we are losing bytes from the tablet or ... ???
00331       int offset = 1;
00332 //       for (; !BIT(7, _tablet_data_buffer[offset]) && offset < _desc._rec_len; offset++) 
00333       for (; !BIT(7, _tablet_data_buffer[offset]) && offset < bytes_in_buffer; offset++) 
00334          ;
00335 
00336       if (offset == _desc._rec_len) {
00337          cerr << "** ERROR: Cannot find start of tablet record!" << endl;
00338 //          assert(0);
00339       }
00340 
00341       for (int i = offset; i < bytes_in_buffer; i++)
00342          _tablet_data_buffer[i-offset] = _tablet_data_buffer[i];
00343 
00344       bytes_in_buffer -= offset;
00345 
00346       if (debug)
00347          cerr << "** Finding tablet record start (skipped "
00348              << offset << " bytes)" << endl;
00349    }
00350 
00351    // How many complete records are there in the input buffer?
00352    int num_complete_records = (bytes_in_buffer / _desc._rec_len);
00353 
00354    // Add all the events we know about to the queue of events to handle.
00355    for (int i=0; i < num_complete_records; i++) {
00356       if (BIT(7, _tablet_data_buffer[i*_desc._rec_len])) {
00357          // Create a new "TabletEvent"
00358          TabletEvent event(_tablet_data_buffer+i*_desc._rec_len, &_desc);
00359 
00360          if(event.is_valid()) {
00361             // Insert it into the queue of events for the right input device
00362             if (event.get_device() == TabletEvent::STYLUS)
00363                _stylus_queue.enqueue(event);
00364             else _puck_queue  .enqueue(event);
00365          }
00366       } else
00367          if (debug)
00368             cerr << "** WARNING: bad record read from tablet (#" <<i<<" )"
00369                  << endl;
00370    }
00371 
00372    // If an incomplete record has started to be read (ie. we read an uneven 
00373    // multiple of _rec_len  bytes) move those bytes to the front of the input 
00374    // buffer & handle them the next time this method is called.
00375    _num_bytes_left_from_last_read = (bytes_in_buffer % _desc._rec_len);
00376    for (int b=0; b<_num_bytes_left_from_last_read; b++)
00377       _tablet_data_buffer[b] = _tablet_data_buffer[bytes_in_buffer-
00378                                                   _num_bytes_left_from_last_read + b];
00379 }
00380 
00381 void 
00382 TabletMultimode::sample()
00383 {
00384    // Read in & enqueue all available tablet events
00385    enqueue_available_tablet_events();
00386 
00387    TabletEvent event;
00388 
00389    // Alternate between reporting stylus and puck events (if both queues 
00390    // have events waiting to be reported)
00391    if (!_stylus_queue.empty() && !_puck_queue.empty()) {
00392       if (_device_to_report == PUCK) {
00393          _device_to_report = STYLUS;
00394 
00395          event = _puck_queue.dequeue();
00396       }
00397       else {
00398          _device_to_report = PUCK;
00399 
00400          event = _stylus_queue.dequeue();
00401       }
00402    }
00403    else {
00404       if (!_stylus_queue.empty())
00405          event = _stylus_queue.dequeue();
00406       else if( !_puck_queue.empty() )
00407          event = _puck_queue.dequeue();
00408       else     // All queues are empty-- nothing to report!
00409          return;
00410    }
00411 
00412    Evd::DEVmod     mods       = DEVmod_gen::mods();
00413    DEVice_buttons &old_buttons= event.get_device() == TabletEvent::PUCK ? 
00414       _puck_buttons : _styl_buttons;
00415 
00416    if(_desc._type == TabletDesc::INTUOS) {
00417       /* Currently we only support the stylus */
00418       int bit;
00419       if(event.is_eraser()) bit = 3;
00420       else bit = 0;
00421       if(BIT(0, event.get_buttons()) != old_buttons.get(bit)) {
00422          if(BIT(0, event.get_buttons())) {
00423             old_buttons.event(bit, DEVice_buttons::DOWN, mods);
00424          }
00425          else old_buttons.event(bit, DEVice_buttons::UP, mods);
00426       }
00427       for(bit = 1; bit < 3; bit++) {
00428          int state = BIT(bit, event.get_buttons()) ? 1 : 0;
00429          if(state != old_buttons.get(bit)) {
00430             if(state) old_buttons.event(bit, DEVice_buttons::DOWN, mods);
00431             else old_buttons.event(bit, DEVice_buttons::UP, mods);
00432          }
00433       }
00434       if(event.is_eraser()) bit = 7;
00435       else bit = 8;
00436       if(event.touching_tablet() != old_buttons.get(bit)) {
00437          if(event.touching_tablet()) {
00438             old_buttons.event(bit, DEVice_buttons::DOWN, mods);
00439          }
00440          else old_buttons.event(bit, DEVice_buttons::UP, mods);
00441       }
00442       if (event.get_device() == TabletEvent::PUCK) {
00443          _puck  .event(XYpt(event.get_pos()[0],
00444                             event.get_pos()[1]), mods);
00445       }
00446       else {
00447          _stylus_pressure = event.stylus_pressure();
00448          _stylus.set_pressure((_stylus_pressure + 511)/1024.0);
00449          _stylus.event(XYpt(event.get_pos()[0],
00450                             event.get_pos()[1]), mods);
00451       }
00452    }
00453    else {
00454       // If the stylus is touching the tablet AND the 3rd button is down AND
00455       // the last event showed the stylus was *not* touching... then we're
00456       // using the eraser.
00457       //
00458       if (event.get_device() == TabletEvent::STYLUS &&
00459           BIT(2,event.get_buttons()) &&   // button 3 is pressed
00460           !old_buttons.get(2) &&          // and button 3 wasn't pressed before
00461           event.touching_tablet() &&      // and the stylus is touching now
00462           !old_buttons.get(8)) {          // but it wasn't before
00463          _using_stylus_eraser = true;
00464          old_buttons.event(7, DEVice_buttons::DOWN, mods);
00465          for (int i = 0; i < 2; i++) { // check the state of each button
00466             int state = BIT(i,event.get_buttons()) ? 1 : 0;
00467             if (state != old_buttons.get(i)) {
00468                if (state) {
00469                   if (i != 0) {
00470                      old_buttons.event(i, DEVice_buttons::DOWN, mods);
00471                   }
00472                } else {
00473                   old_buttons.event(i, DEVice_buttons::UP  , mods);
00474                }
00475             }
00476          }
00477       }
00478 
00479       // set new button state & generate button events
00480       if (event.get_device() == TabletEvent::STYLUS && _using_stylus_eraser) {
00481          // If button #1 (bit 0 of 'event.get_buttons()') is set, then
00482          // set button #4 (bit 3) of the stylus' buttons indicating the eraser
00483          // is being pressed on the tablet surface.
00484          const int eraser_bit = 3;
00485 
00486          int state = BIT(0, event.get_buttons()) ? 1 : 0;
00487          if (state != old_buttons.get(eraser_bit)) {
00488             if (state)
00489                old_buttons.event(eraser_bit, DEVice_buttons::DOWN, mods);
00490             else old_buttons.event(eraser_bit, DEVice_buttons::UP  , mods);
00491          }
00492       }
00493       else {
00494          if (event.touching_tablet()) {   // only generate button events when 
00495             //   touching the tablet
00496             for (int i = 0; i < 3; i++) { // check the state of each button
00497                int state = BIT(i,event.get_buttons()) ? 1 : 0;
00498                if (state != old_buttons.get(i)) {
00499                   if (state) 
00500                      old_buttons.event(i, DEVice_buttons::DOWN, mods);
00501                   else old_buttons.event(i, DEVice_buttons::UP  , mods);
00502                }
00503             }
00504          }
00505       }
00506      
00507       // set new 2d device position & generate events
00508       int touching(event.touching_tablet() ? 1 : 0);
00509       if (touching != old_buttons.get(8)) {
00510          if (touching)
00511             old_buttons.event(8, DEVice_buttons::DOWN, mods);
00512          else old_buttons.event(8, DEVice_buttons::UP  , mods);
00513       }
00514 
00515       if (event.get_device() == TabletEvent::PUCK) {
00516          _puck  .event(XYpt(event.get_pos()[0],
00517                             event.get_pos()[1]), mods);
00518       } else {
00519          _stylus_pressure = event.stylus_pressure();
00520          _stylus.event(XYpt(event.get_pos()[0],
00521                             event.get_pos()[1]), mods);
00522       }
00523 
00524       // If the stylus has been lifted from the tablet & we were drawing
00525       // with the eraser, then we're not using the eraser anymore.
00526       // NOTE: this must be done *after* buttons are set since they are
00527       // dependent on the value of '_using_stylus_eraser'.
00528       if ((!event.touching_tablet() || !BIT(2,event.get_buttons())) && 
00529           _using_stylus_eraser) {
00530          old_buttons.event(7, DEVice_buttons::UP, mods);
00531          _using_stylus_eraser = false;
00532       }
00533    }
00534 }

Generated on Mon Sep 18 11:39:33 2006 for jot by  doxygen 1.4.4