The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bitsy/devpenmouse.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 #define Image   IMAGE
    9 #include        <draw.h>
   10 #include        <memdraw.h>
   11 #include        <cursor.h>
   12 #include        "screen.h"
   13 #include        <ctype.h>
   14 
   15 typedef struct Mouseinfo        Mouseinfo;
   16 typedef struct Mousestate       Mousestate;
   17 typedef struct Calibration      Calibration;
   18 
   19 struct Calibration
   20 {
   21         long    scalex;
   22         long    scaley;
   23         long    transx;
   24         long    transy;
   25 } calibration = {
   26         -16435,
   27         23275,
   28         253,
   29         -23
   30 };
   31 
   32 /* The pen goes down, tracks some and goes up again.  The pen alone can
   33  * only simulate a one-button mouse.
   34  * To simulate a more-button (five, in this case) mouse, we use the four
   35  * keys along the the bottom of the iPaq as modifiers.
   36  * When one (or more) of the modifier keys is (are) down, a pen-down event
   37  * causes the corresponding bottons to go down.  If no modifier key is
   38  * depressed, a pen-down event is translated into a button-one down event.
   39  * Releasing the modifier keys has no direct effect.  The pen-up event is
   40  * the one that triggers mouse-up events.
   41  */
   42 struct Mousestate
   43 {
   44         Point   xy;                     /* mouse.xy */
   45         int             buttons;        /* mouse.buttons */
   46         int             modifiers;      /* state of physical buttons 2, 3, 4, 5 */
   47         ulong   counter;        /* increments every update */
   48         ulong   msec;           /* time of last event */
   49 };
   50 
   51 struct Mouseinfo
   52 {
   53         Lock;
   54         Mousestate;
   55         ulong   lastcounter;    /* value when /dev/mouse read */
   56         ulong   resize;
   57         ulong   lastresize;
   58         Rendez  r;
   59         Ref;
   60         QLock;
   61         int     open;
   62         int     inopen;
   63         Mousestate      queue[16];      /* circular buffer of click events */
   64         int     ri;     /* read index into queue */
   65         int     wi;     /* write index into queue */
   66         uchar   qfull;  /* queue is full */
   67 };
   68 
   69 Mouseinfo       mouse;
   70 int             mouseshifted;
   71 
   72 int     penmousechanged(void*);
   73 static void     penmousetrack(int b, int x, int y);
   74 
   75 enum{
   76         Qdir,
   77         Qmouse,
   78         Qmousein,
   79         Qmousectl,
   80 };
   81 
   82 static Dirtab mousedir[]={
   83         ".",                    {Qdir, 0, QTDIR},       0,      DMDIR|0555,
   84         "mouse",                {Qmouse},               0,      0666,
   85         "mousein",      {Qmousein},             0,      0220,
   86         "mousectl",     {Qmousectl},            0,      0660,
   87 };
   88 
   89 enum
   90 {
   91         CMcalibrate,
   92         CMswap,
   93 };
   94 
   95 static Cmdtab penmousecmd[] =
   96 {
   97         CMcalibrate,    "calibrate",    0,
   98         CMswap,         "swap",         1,
   99 };
  100 
  101 static uchar buttonmap[8] = {
  102         0, 1, 2, 3, 4, 5, 6, 7,
  103 };
  104 static int mouseswap;
  105 
  106 extern  Memimage*       gscreen;
  107 
  108 void
  109 penbutton(int up, int b) {
  110         // button 5 (side button) immediately causes an event
  111         // when the pen is down (button 1), other buttons also
  112         // cause events, allowing chording with button 1
  113         if ((b & 0x20) || (mouse.buttons & 0x1)) {
  114                 if (up)
  115                         mouse.buttons &= ~b;
  116                 else
  117                         mouse.buttons |= b;
  118                 penmousetrack(mouse.buttons, -1, -1);
  119         } else {
  120                 if (up)
  121                         mouse.modifiers &= ~b;
  122                 else
  123                         mouse.modifiers |= b;
  124         }
  125 }
  126 
  127 void
  128 pentrackxy(int x, int y) {
  129 
  130         if (x == -1) {
  131                 /* pen up. associate with button 1 through 5 up */
  132                 mouse.buttons &= ~0x1f;
  133         } else {
  134                 x = ((x*calibration.scalex)>>16) + calibration.transx;
  135                 y = ((y*calibration.scaley)>>16) + calibration.transy;
  136                 if ((mouse.buttons & 0x1f) == 0) {
  137                         if (mouse.modifiers)
  138                                 mouse.buttons |= mouse.modifiers;
  139                         else
  140                                 mouse.buttons |= 0x1;
  141                 }
  142         }
  143         penmousetrack(mouse.buttons, x, y);
  144 }
  145 
  146 static void
  147 penmousereset(void)
  148 {
  149         if(!conf.monitor)
  150                 return;
  151 }
  152 
  153 static void
  154 penmouseinit(void)
  155 {
  156         if(!conf.monitor)
  157                 return;
  158 }
  159 
  160 static Chan*
  161 penmouseattach(char *spec)
  162 {
  163         if(!conf.monitor)
  164                 error(Egreg);
  165         return devattach('m', spec);
  166 }
  167 
  168 static Walkqid*
  169 penmousewalk(Chan *c, Chan *nc, char **name, int nname)
  170 {
  171         return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
  172 }
  173 
  174 static int
  175 penmousestat(Chan *c, uchar *db, int n)
  176 {
  177         return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
  178 }
  179 
  180 static Chan*
  181 penmouseopen(Chan *c, int omode)
  182 {
  183         switch((ulong)c->qid.path){
  184         case Qdir:
  185                 if(omode != OREAD)
  186                         error(Eperm);
  187                 break;
  188         case Qmouse:
  189                 lock(&mouse);
  190                 if(mouse.open){
  191                         unlock(&mouse);
  192                         error(Einuse);
  193                 }
  194                 mouse.open = 1;
  195                 mouse.ref++;
  196                 unlock(&mouse);
  197                 break;
  198         case Qmousein:
  199         /*      error("disabled");      */
  200                 lock(&mouse);
  201                 if(mouse.inopen){
  202                         unlock(&mouse);
  203                         error(Einuse);
  204                 }
  205                 mouse.inopen = 1;
  206                 unlock(&mouse);
  207                 break;
  208         default:
  209                 incref(&mouse);
  210         }
  211         c->mode = openmode(omode);
  212         c->flag |= COPEN;
  213         c->offset = 0;
  214         return c;
  215 }
  216 
  217 static void
  218 penmousecreate(Chan*, char*, int, ulong)
  219 {
  220         if(!conf.monitor)
  221                 error(Egreg);
  222         error(Eperm);
  223 }
  224 
  225 static void
  226 penmouseclose(Chan *c)
  227 {
  228         if(c->qid.path != Qdir && (c->flag&COPEN)){
  229                 lock(&mouse);
  230                 if(c->qid.path == Qmouse)
  231                         mouse.open = 0;
  232                 else if(c->qid.path == Qmousein){
  233                         mouse.inopen = 0;
  234                         unlock(&mouse);
  235                         return;
  236                 }
  237                 --mouse.ref;
  238                 unlock(&mouse);
  239         }
  240 }
  241 
  242 static long
  243 penmouseread(Chan *c, void *va, long n, vlong)
  244 {
  245         char buf[4*12+1];
  246         static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
  247         Mousestate m;
  248 
  249         switch((ulong)c->qid.path){
  250         case Qdir:
  251                 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
  252 
  253         case Qmousectl:
  254                 sprint(buf, "c%11ld %11ld %11ld %11ld",
  255                                 calibration.scalex, calibration.scaley,
  256                                 calibration.transx, calibration.transy);
  257                 if(n > 1+4*12)
  258                         n = 1+4*12;
  259                 memmove(va, buf, n);
  260                 return n;
  261 
  262         case Qmouse:
  263                 while(penmousechanged(0) == 0)
  264                         sleep(&mouse.r, penmousechanged, 0);
  265 
  266                 mouse.qfull = 0;
  267 
  268                 /*
  269                  * No lock of the indices is necessary here, because ri is only
  270                  * updated by us, and there is only one mouse reader
  271                  * at a time.  I suppose that more than one process
  272                  * could try to read the fd at one time, but such behavior
  273                  * is degenerate and already violates the calling
  274                  * conventions for sleep above.
  275                  */
  276                 if(mouse.ri != mouse.wi) {
  277                         m = mouse.queue[mouse.ri];
  278                         if(++mouse.ri == nelem(mouse.queue))
  279                                 mouse.ri = 0;
  280                 } else {
  281                         m = mouse.Mousestate;
  282                 }
  283                 sprint(buf, "m%11d %11d %11d %11lud",
  284                         m.xy.x, m.xy.y,
  285                         m.buttons,
  286                         m.msec);
  287                 mouse.lastcounter = m.counter;
  288                 if(n > 1+4*12)
  289                         n = 1+4*12;
  290                 if(mouse.lastresize != mouse.resize){
  291                         mouse.lastresize = mouse.resize;
  292                         buf[0] = 'r';
  293                 }
  294                 memmove(va, buf, n);
  295                 return n;
  296         }
  297         return 0;
  298 }
  299 
  300 static void
  301 setbuttonmap(char* map)
  302 {
  303         int i, x, one, two, three;
  304 
  305         one = two = three = 0;
  306         for(i = 0; i < 3; i++){
  307                 if(map[i] == 0)
  308                         error(Ebadarg);
  309                 if(map[i] == '1'){
  310                         if(one)
  311                                 error(Ebadarg);
  312                         one = 1<<i;
  313                 }
  314                 else if(map[i] == '2'){
  315                         if(two)
  316                                 error(Ebadarg);
  317                         two = 1<<i;
  318                 }
  319                 else if(map[i] == '3'){
  320                         if(three)
  321                                 error(Ebadarg);
  322                         three = 1<<i;
  323                 }
  324                 else
  325                         error(Ebadarg);
  326         }
  327         if(map[i])
  328                 error(Ebadarg);
  329 
  330         memset(buttonmap, 0, 8);
  331         for(i = 0; i < 8; i++){
  332                 x = 0;
  333                 if(i & 1)
  334                         x |= one;
  335                 if(i & 2)
  336                         x |= two;
  337                 if(i & 4)
  338                         x |= three;
  339                 buttonmap[x] = i;
  340         }
  341 }
  342 
  343 static long
  344 penmousewrite(Chan *c, void *va, long n, vlong)
  345 {
  346         char *p;
  347         Point pt;
  348         Cmdbuf *cb;
  349         Cmdtab *ct;
  350         char buf[64];
  351         int b;
  352 
  353         p = va;
  354         switch((ulong)c->qid.path){
  355         case Qdir:
  356                 error(Eisdir);
  357 
  358         case Qmousectl:
  359                 cb = parsecmd(va, n);
  360                 if(waserror()){
  361                         free(cb);
  362                         nexterror();
  363                 }
  364                 ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
  365                 switch(ct->index){
  366                 case CMswap:
  367                         if(mouseswap)
  368                                 setbuttonmap("123");
  369                         else
  370                                 setbuttonmap("321");
  371                         mouseswap ^= 1;
  372                         break;
  373                 case CMcalibrate:
  374                         if (cb->nf == 1) {
  375                                 calibration.scalex = 1<<16;
  376                                 calibration.scaley = 1<<16;
  377                                 calibration.transx = 0;
  378                                 calibration.transy = 0;
  379                         } else if (cb->nf == 5) {
  380                                 if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-')
  381                                  || (!isdigit(*cb->f[2]) && *cb->f[2] != '-')
  382                                  || (!isdigit(*cb->f[3]) && *cb->f[3] != '-')
  383                                  || (!isdigit(*cb->f[4]) && *cb->f[4] != '-'))
  384                                         error("bad syntax in control file message");
  385                                 calibration.scalex = strtol(cb->f[1], nil, 0);
  386                                 calibration.scaley = strtol(cb->f[2], nil, 0);
  387                                 calibration.transx = strtol(cb->f[3], nil, 0);
  388                                 calibration.transy = strtol(cb->f[4], nil, 0);
  389                         } else
  390                                 cmderror(cb, Ecmdargs);
  391                         break;
  392                 }
  393                 free(cb);
  394                 poperror();
  395                 return n;
  396 
  397         case Qmousein:
  398                 if(n > sizeof buf-1)
  399                         n = sizeof buf -1;
  400                 memmove(buf, va, n);
  401                 buf[n] = 0;
  402                 p = 0;
  403                 pt.x = strtol(buf+1, &p, 0);
  404                 if(p == 0)
  405                         error(Eshort);
  406                 pt.y = strtol(p, &p, 0);
  407                 if(p == 0)
  408                         error(Eshort);
  409                 b = strtol(p, &p, 0);
  410                 penmousetrack(b, pt.x, pt.y);
  411                 return n;
  412                 
  413         case Qmouse:
  414                 if(n > sizeof buf-1)
  415                         n = sizeof buf -1;
  416                 memmove(buf, va, n);
  417                 buf[n] = 0;
  418                 p = 0;
  419                 pt.x = strtoul(buf+1, &p, 0);
  420                 if(p == 0)
  421                         error(Eshort);
  422                 pt.y = strtoul(p, 0, 0);
  423                 qlock(&mouse);
  424                 if(ptinrect(pt, gscreen->r))
  425                         penmousetrack(mouse.buttons, pt.x, pt.y);
  426                 qunlock(&mouse);
  427                 return n;
  428         }
  429 
  430         error(Egreg);
  431         return -1;
  432 }
  433 
  434 Dev penmousedevtab = {
  435         'm',
  436         "penmouse",
  437 
  438         penmousereset,
  439         penmouseinit,
  440         devshutdown,
  441         penmouseattach,
  442         penmousewalk,
  443         penmousestat,
  444         penmouseopen,
  445         penmousecreate,
  446         penmouseclose,
  447         penmouseread,
  448         devbread,
  449         penmousewrite,
  450         devbwrite,
  451         devremove,
  452         devwstat,
  453 };
  454 
  455 /*
  456  *  called at interrupt level to update the structure and
  457  *  awaken any waiting procs.
  458  */
  459 static void
  460 penmousetrack(int b, int x, int y)
  461 {
  462         int lastb;
  463 
  464         if (x >= 0)
  465                 mouse.xy = Pt(x, y);
  466         lastb = mouse.buttons;
  467         mouse.buttons = b;
  468         mouse.counter++;
  469         mouse.msec = TK2MS(MACHP(0)->ticks);
  470 
  471         /*
  472          * if the queue fills, we discard the entire queue and don't
  473          * queue any more events until a reader polls the mouse.
  474          */
  475         if(!mouse.qfull && lastb != b) {        /* add to ring */
  476                 mouse.queue[mouse.wi] = mouse.Mousestate;
  477                 if(++mouse.wi == nelem(mouse.queue))
  478                         mouse.wi = 0;
  479                 if(mouse.wi == mouse.ri)
  480                         mouse.qfull = 1;
  481         }
  482         wakeup(&mouse.r);
  483         drawactive(1);
  484         resetsuspendtimer();
  485 }
  486 
  487 int
  488 penmousechanged(void*)
  489 {
  490         return mouse.lastcounter != mouse.counter ||
  491                 mouse.lastresize != mouse.resize;
  492 }
  493 
  494 Point
  495 penmousexy(void)
  496 {
  497         return mouse.xy;
  498 }
  499 
  500 /*
  501  * notify reader that screen has been resized (ha!)
  502  */
  503 void
  504 mouseresize(void)
  505 {
  506         mouse.resize++;
  507         wakeup(&mouse.r);
  508 }
  509 

Cache object: 8a2005c5ddebcbcc0d334a22af2b38bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.