HID mouse (teensy)

At work I am not an IT guy and have limited privileges. Certain of the things I do on the PC seems inadequately automated. I liken it to using my father’s hand drill rather than a power drill. I would like to be able to press one button and combine say: move the mouse, click, move the mouse, click, type a few characters, move the mouse again .

It struck me that I should be able to build this into a teensy based device. The teensy and teensy++ are based on atmel chips that include built in USB and the teensyduino software includes extensions Mouse.move(byte xMove,byte yMove) etc. I should be able to program a teensy to perform in add-on hardware the keyboard/mouse macros that I think IT should have given me in software.

I’ve been playing with these on my Mac, trying to establish precise control of the way the signal from the teensy’s HID ‘mouse’ relates to pixels the cursor on my screen moves. I installed a program on the Mac that displays the mouse location in the menubar. I was pleased to see that Mouse.move(-127,127) seems to move 250 pixels on the Mac screen pretty consistently in each direction (x and y). I worked out similar correspondences at (31,31) (7,7) and (2,2) values on the Mouse.move scale. I can move on 45 degree angles and do the reciprocal movement back within a pixel on the Mac screen.

What’s odd is that when I Mouse.move(127,0) the cursor doesn’t seem to move 250 pixels in the x direction. At first, I encountered this in the context of having made multiple moves at once and thought I was encountering the mouse acceleration algorithm of the Mac OS. (That is, when you move the mouse quickly the cursor moves farther than when you move the mouse slowly the same distance) I installed a preference panel (http://zuckschwerdt.org/mac) to give me some control over that and have seen little real difference when I use that. Sticking to 45 degree angle moves made a real difference.

I suppose I can get at least close to wherever I want to go on the screen with a series of 45 degree moves, but it seems like a little more insight would let me do better than that.

 void mouseMove(int x,int y){
   int xMove=x;
   int yMove=y;
   byte xSub=0,ySub=0;
   byte xList[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   byte yList[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   //Mouse.move of 127 moves it 250 on the computer
     while (xMove < -125) { 
       xMove += 250;
 //      Mouse.move(-127,0);
       xList[xSub++]= -127;
       #ifdef DEBUG
       Serial<<"x+250 "<<xMove<<"; ";
       #endif

     }

     while (xMove > 125) { 
       xMove -= 250;
//       Mouse.move(127,0);
       xList[xSub++] = 127;
       #ifdef DEBUG
       Serial<<"x-250 "<<xMove<<"; ";
       #endif

     }

 //  Mouse.move 31 moves it 50 on the computer
     while (xMove < -25) { 
       xMove += 50;
 //      Mouse.move(-31,0);
       xList[xSub++] =  -31;   
       #ifdef DEBUG
       Serial<<"x+50 "<<xMove<<"; ";
       #endif

     }

     while (xMove > 25) { 
       xMove -= 50;
//       Mouse.move(31,0);
       xList[xSub++] =  31;
       #ifdef DEBUG
       Serial<<"x-50 "<<xMove<<"; ";
       #endif

     }       
  
 //  Mouse.move 7 moves it 5 on the computer
     while (xMove < -3) { 
       xMove += 5;
 //      Mouse.move(-7,0);
       xList[xSub++] =  -7;
       #ifdef DEBUG
       Serial<<"x+5 "<<xMove<<"; ";
       #endif

     }

     while (xMove > 3) { 
       xMove -= 5;
//       Mouse.move(7,0);
       xList[xSub++] =  7;
       #ifdef DEBUG
       Serial<<"x-5 "<<xMove<<"; ";
       #endif

     }       

 //  Mouse.move 2 moves it 0.5 on the computer
     while (xMove <= -1) { 
       xMove += 1;
//       Mouse.move(-2,0);

       xList[xSub++] =  -2;
//       Mouse.move(-2,0);
       xList[xSub++] =  -2;
       #ifdef DEBUG
       Serial<<"x+1 "<<xMove<<"; ";
       #endif
     }

     while (xMove >= 1) { 
       xMove -= 1;
 //      Mouse.move(2,0);
       xList[xSub++] =  2;
//       Mouse.move(2,0);
       xList[xSub++] =  2;
       #ifdef DEBUG
       Serial<<"x-1 "<<xMove<<"; ";
       #endif

     }   //now x should be dead on. 
     #ifdef DEBUG
       Serial.println(' ');
    #endif 
   //Mouse.move of 127 moves it 250 on the computer
     while (yMove < -125) { 
       yMove += 250;
//       Mouse.move(0,-127);
       yList[ySub++] =  -127;
       #ifdef DEBUG
       Serial<<"y+250 "<<yMove<<"; ";
       #endif
 
     }
     while (yMove > 125) { //dead on at 250 pixel jumps on the screen
       yMove -= 250;
//       Mouse.move(0,127);
       yList[ySub++] =  127;
       #ifdef DEBUG
       Serial<<"y-250 "<<yMove<<"; ";
       #endif

     }
 //  Mouse.move 31 moves it 50 on the computer
     while (yMove < -25) { 
       yMove += 50;
//       Mouse.move(0,-31);
       yList[ySub++] =  -31;
       #ifdef DEBUG
       Serial<<"y+50 "<<yMove<<"; ";
       #endif

     }

     while (yMove > 25) { 
       yMove -= 50;
 //      Mouse.move(0, 31);
       yList[ySub++] =  31;
       #ifdef DEBUG
       Serial<<"y-50 "<<yMove<<"; ";
       #endif

     }       
  
 //  Mouse.move 7 moves it 5 on the computer
     while (yMove < -3) { 
       yMove += 5;
//       Mouse.move(0,-7);
       yList[ySub++] =  -7;
       #ifdef DEBUG
       Serial<<"y+5 "<<yMove<<"; ";
       #endif

     }
     while (yMove > 3) { 
       yMove -=5;
//       Mouse.move(0, 7);
       yList[ySub++] =  7;
       #ifdef DEBUG
       Serial<<"y-5 "<<yMove<<"; ";
       #endif

     }       
  
 //  Mouse.move 2 moves it 0.5 on the computer
     while (yMove <= -1) { 
       yMove += 1;
//       Mouse.move(0,-2);
//       Mouse.move(0,-2);
       yList[ySub++] =  -2;
       yList[ySub++] =  -2;
       #ifdef DEBUG
       Serial<<"y+1 "<<yMove<<"; ";
       #endif

     }

     while (yMove >= 1) { 
       yMove -=1;
//       Mouse.move(0, 2);
//       Mouse.move(0, 2);
       yList[ySub++] =  2;
       yList[ySub++] =  2;
       #ifdef DEBUG
       Serial<<"y-1 "<<yMove<<"; ";
       #endif

     }     //now y should be dead on. 
     #ifdef DEBUG
     Serial.println(' ');
     #endif
     byte subCount = max(xSub,ySub);
     for (byte i=0;i<subCount;i++) {
       #ifdef DEBUG
       Serial<<_HEX((int)xList[i])<<"  "<<_HEX((int)yList[i])<<endl;
       #endif
       Mouse.move(xList[i],yList[i]);
       delay(DELAY);    }
     
 }//mouseMove

How does Mouse.move(127,1) behave?

I did these tests with the cursor starting at 1000,100 with the mouse position from the menubar in the comment fields

    Mouse.move(-127,1);  //  678,102    678,103
    delay(DELAY2);
    Mouse.move(-127,2);   //  356,107      357,108
    delay(DELAY2);
    Mouse.move(-127,7);   //  37,125    37,126
    delay(DELAY2);
    Mouse.move(-127,1);  // 679,103
    delay(DELAY2);
    Mouse.move(-127,31);     //  375,177
    delay(DELAY2);
    Mouse.move(-127,127);   //  125,427    --the 250 I've observed before
    delay(DELAY2);
    Mouse.move(-31,1);    //   966,101     966,101
    delay(DELAY2);
    Mouse.move(-31,2);     //   931,103    932,103
    delay(DELAY2);
    Mouse.move(-31,7);    //    894,111   894,111
    delay(DELAY2);
    Mouse.move(-31,1);    //  966,101
    delay(DELAY2);
    Mouse.move(-31,31);         //  916,151  --the 50 pixels I've observed before
    delay(DELAY2);
    Mouse.move(-31,127);      //   842,454
    delay(DELAY2);

Thinking about this overnight, I suppose I should just carefully measure what happens with 127,0 31,0 7,0 2,0 and revert the code to something like what I commented out. What is a little frustrating is that the most reliable measurements I make always seem to be on the 45 degree values.

As I pushed ahead with reverting to the commented out code I find Mouse.move(127,0) moves 322 pixels, Mouse.move(31,0) moves 33 pixels,Mouse.move(7,0) moves 4 pixels and Mouse.move(4,0) moves 1 pixel.

I also watched and realized that my algorithm (which does a sort of binary walk to the desired number) may try to step the cursor off the edge of the screen. So it may try to reduce the computer mouse location to less than 0. The computer mouse won't go there and so that is a source of error.

This is where I am at now. typically I get errors of about 5 pixels. For most buttons that might be close enough; I will try to fine tune it but as a practical matter the code will always need some tuning: it is dependent on screen resolution and mouse sensitivity preference settings and probably will be a little different between PC and Mac.

 void mouseMove(int x,int y){
   int xMove=x;
   int yMove=y;
   //Mouse.move of 127 moves it 322 on the computer
     while (xMove < -321) { 
       xMove += 322;
       Mouse.move(-127,0);
       #ifdef DEBUG
       Serial<<"x+322 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (xMove > 321) { 
       xMove -= 322;
       Mouse.move(127,0);
       #ifdef DEBUG
       Serial<<"x-322 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }

 //  Mouse.move 31 moves it 33 on the computer
     while (xMove < -32) { 
       xMove += 33;
       Mouse.move(-31,0);
       #ifdef DEBUG
       Serial<<"x+33 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (xMove > 32) { 
       xMove -= 33;
       Mouse.move(31,0);
       #ifdef DEBUG
       Serial<<"x-33 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }       
  
 //  Mouse.move 7 moves it 4 on the computer
     while (xMove < -3) { 
       xMove += 4;
       Mouse.move(-7,0);
       #ifdef DEBUG
       Serial<<"x+4 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (xMove > 3) { 
       xMove -= 4;
       Mouse.move(7,0);
       #ifdef DEBUG
       Serial<<"x-4 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }       

 //  Mouse.move 4 moves it 1 on the computer
     while (xMove <= -1) { 
       xMove += 1;
       Mouse.move(-4,0);
       #ifdef DEBUG
       Serial<<"x+1 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (xMove >= 1) { 
       xMove -= 1;
       Mouse.move(4,0);
       #ifdef DEBUG
       Serial<<"x-1 "<<xMove<<"; ";
       #endif
       delay(DELAY);
     }   //now x should be dead on. 
     #ifdef DEBUG
       Serial.println(' ');
    #endif 
   //Mouse.move of 127 moves it 322 on the computer
     while (yMove < -321) { 
       yMove += 322;
       Mouse.move(0,-127);
       #ifdef DEBUG
       Serial<<"y+322 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }
     while (yMove > 321) { 
       yMove -= 322;
       Mouse.move(0,127);
       #ifdef DEBUG
       Serial<<"y-322 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }
 //  Mouse.move 31 moves it 33 on the computer
     while (yMove < 32) { 
       yMove += 33;
       Mouse.move(0,-31);
       #ifdef DEBUG
       Serial<<"y+33 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (yMove > 32) { 
       yMove -= 33;
       Mouse.move(0, 31);
       #ifdef DEBUG
       Serial<<"y-33 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }       
  
 //  Mouse.move 7 moves it 4 on the computer
     while (yMove < -3) { 
       yMove += 4;
       Mouse.move(0,-7);
       #ifdef DEBUG
       Serial<<"y+4 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }
     while (yMove > 3) { 
       yMove -=4;
       Mouse.move(0, 7);
       #ifdef DEBUG
       Serial<<"y-4 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }       
  
 //  Mouse.move 4 moves it 1 on the computer
     while (yMove <= -1) { 
       yMove += 1;
       Mouse.move(0,-4);
       #ifdef DEBUG
       Serial<<"y+1 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }

     while (yMove >= 1) { 
       yMove -=1;
       Mouse.move(0, 4);
       #ifdef DEBUG
       Serial<<"y-1 "<<yMove<<"; ";
       #endif
       delay(DELAY);
     }     //now y should be dead on. 
     #ifdef DEBUG
     Serial.println(' ');
     #endif
 }//mouseMove