title: C# Tracking mouse movement at a resolution greater than monitor resolution
body: <p><strong>Problem</strong></p>
  
  <p>I'm using a C# application to record keyboard and mouse movement, processing that movement and sending serial data out to a micro-controller that interpreters that data and moves a set of servos.  In the past I had created a box or image that was the resolution(number of steps) my servos were capable of, clipped the mouse to that box or image, and processed where the cursor was in that box and sent data to my servos to move to that position.</p>
  
  <p>This worked fine and dandy till I needed to move a greater amount of steps than my monitor has resolution.</p>
  
  <p>So my question is what options are available to me for tracking mouse movement up to 10,000 steps/resolution in the X and Y axis?</p>
  
  <p><strong>Possible solution route</strong></p>
  
  <p>Thinking outside the box I think I could hide and center the mouse on the screen, record how much the mouse moved on mousemoved events, process that data, then recenter the mouse on the screen to give me unlimited movement in each axis.</p>
  
  <p>Enclosed below is my PIC18F2420 code.  Currently it is fed x and y positions via serial communications from my C# application.  Data is stored in a ring buffer as it is received and processed as soon as possible. </p>
  
  <p>PIC CODE</p>
  
  <pre><code>#include &lt;p18f2420.h&gt;
  #include &lt;cType.h&gt;
  #include &lt;usart.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include &lt;timers.h&gt;
  #include &lt;delays.h&gt;
  /**********************************************************************************************/
  //DEFINES
  #define switch_0 PORTCbits.RC4
  #define switch_1 PORTCbits.RC5
  #define bufferSize 48
  /**********************************************************************************************/
  /**********************************************************************************************/
  //Function prototypes
  
  void high_isr(void);
  void int2ASCII(unsigned int output);
  void UART_putChar(unsigned char value);
  char readBuffer();
  char emptyBuffer();
  char peekBuffer();
  void limitServo0(); //limit movement via predetermined min/max
  void limitServo1();
  /**********************************************************************************************/
  
  unsigned char hertz = 75;  //value to generate 5-=60 hertz wave default value 75
  unsigned int timer0, servo0Min, servo0Max;
  unsigned int timer1, servo1Min, servo1Max;
  unsigned char servo0Rate = 10;
  unsigned char ByteOut;
  char array[bufferSize];  //input rs-232 buffer
  char valueArray[bufferSize];
  char dataArray[bufferSize];
  char tempArray[bufferSize];
  unsigned char tempIndex;
  unsigned char head = 0;
  unsigned char tail = 0;
  //variables used to disect the comma delimited string
  char CVdata;  //do we have a command and value?
  char CVvalue;  //bool value like above
  //BOOLEAN IF values
  
  /**********************************************************************************************/
  //Interrupt Service Routine
  #pragma code high_vector=0x08
  
  void interrupt_at_high_vector (void)
  {
  _asm GOTO high_isr _endasm
  }
  #pragma code /* return to the default code section */
  #pragma interrupt high_isr
  void high_isr (void)
  {
  if(PIR1bits.TMR2IF == 1)
  {
      //T0CONbits.TMR0ON = 0;
      //T1CONbits.TMR1ON = 0;     
      INTCONbits.TMR0IF = 0;  //Turn off Int Flag
      PIR1bits.TMR1IF = 0;
      PIR1bits.TMR2IF = 0;    //Turn off Int Flag
      LATCbits.LATC3 = 1;     //Turn on data line
      TMR0H = timer0/256;     //Extract HIGH byte always do Hbyte first
      TMR0L = timer0;         //Extract LOW byte
  }
  if(PIR1bits.TMR1IF == 1)
  {
      PIR1bits.TMR1IF = 0;
      //T1CONbits.TMR1ON = 0;
      //PIR1bits.TMR2IF = 0;      //Turn off Int Flag
      INTCONbits.TMR0IF = 0;  //Turn off Int Flag
      LATCbits.LATC2 = 0;
      PR2 = hertz;            //Generate 50-60hertz pulse
  }
  if(INTCONbits.TMR0IF == 1)
  {
      LATCbits.LATC2 = 1;
      //PIR1bits.TMR1IF = 0;
      //PIR1bits.TMR2IF = 0;      //Turn off Int Flag
      //T0CONbits.TMR0ON = 0;
      //T1CONbits.TMR1ON = 1;
      INTCONbits.TMR0IF = 0;  //Turn off Int Flag
      LATCbits.LATC3 = 0;
      TMR1H = timer1/256;
      TMR1L = timer1;
  }
  if(PIR1bits.RCIF == 1)
  {
      PIR1bits.RCIF = 0;  
      array[tail] = RCREG;
      //array[tail] = ReadUSART();
      tail++;
      if(tail == bufferSize)
      {
          tail = 0;
      }
      /* Clear the interrupt flag  */
  }
  }
  
  /**********************************************************************************************/
  
  
  void main(void)
  {
  /**********************************************************************************************/
  //Initialize
  memset(array, '\0' , bufferSize);
  memset(tempArray, '\0' , bufferSize);
  memset(dataArray, '\0' , bufferSize);
  memset(valueArray, '\0' , bufferSize);
  TRISC = 0b10110000;//RC4 and RC5 inputs for switches
  servo0Max = 65000;  //Max value allowed  PAN 65000
  servo0Min = 62000;  //Min value allowed 63500
  servo1Max = 65000;  //Tilt 64138
  servo1Min = 62000;  //TILT 63864
  timer0 = 64250;  //Initial position
  timer1 = 64200;
  CVdata = 0;
  CVvalue = 0;
  tempIndex = 0;
  LATCbits.LATC0 = 0;
  
  /**********************************************************************************************/
  //USART
  
  OpenUSART(USART_TX_INT_OFF &amp;
          USART_RX_INT_ON &amp;
          USART_CONT_RX &amp;
          USART_ASYNCH_MODE &amp;
          USART_EIGHT_BIT &amp;
          USART_BRGH_HIGH
          , 16);//change back to 16 for 57.6  103 for 9.6
  RCSTAbits.ADDEN = 0;//Testing this out might not help with overflow
  TXSTAbits.SYNC = 0;
  INTCONbits.GIE = 1;
  INTCONbits.PEIE = 1;
  TXSTAbits.BRGH = 1;
  BAUDCONbits.BRG16 = 1;
  
  /**********************************************************************************************/
  //Initialize Timer0
  
  OpenTimer0(TIMER_INT_ON &amp;
       T0_SOURCE_INT &amp;
       T0_16BIT);
  T0CONbits.PSA = 1;
  INTCONbits.TMR0IF = 0;
  /**********************************************************************************************/
  
  /**********************************************************************************************/
  //Initialize Timer1
  OpenTimer1(TIMER_INT_ON &amp;
      T1_16BIT_RW &amp;
      T1_SOURCE_INT &amp;
      T1_PS_1_1);
  T1CONbits.T1CKPS1 = 0;   // bits 5-4  Prescaler Rate Select bits
  T1CONbits.T1CKPS0 = 0;   // bit 4
  T1CONbits.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
  T1CONbits.T1SYNC = 1;    // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
  T1CONbits.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock     (FOSC/4)
  T1CONbits.TMR1ON = 1;    // bit 0 enables timer
  /**********************************************************************************************/
  
  /**********************************************************************************************/
  //Initialize Timer2
  
  OpenTimer2( TIMER_INT_ON &amp;
          T2_PS_1_16 &amp;
          T2_POST_1_16);
  PR2 = hertz;
  PIE1bits.TMR2IE = 1;
  IPR1bits.TMR2IP = 1;
  INTCONbits.GIEH = 1; //enable global interrupts
  INTCONbits.GIEL = 1;
  /**********************************************************************************************/
  
  while(1)  
  {
      while(emptyBuffer());
      if(CVdata == 0 &amp;&amp; CVvalue == 1)
      {
          //ERROR THIS SHOULDN't HAPPEN!  FLUSH BUFFER
          CVdata = 0;
          CVvalue = 0;
      }       
      if(CVdata == 0 &amp;&amp; CVvalue == 0)
      {
          if(peekBuffer() != ',')
          {
              tempArray[tempIndex] = readBuffer();
              tempIndex++;
          }
          else
          {
              readBuffer();//if comma sent first read it and throw away           
              if(tempIndex &gt; 0) //comma read and data in buffer
              {
                  memcpy(dataArray, tempArray, tempIndex);
                  tempIndex = 0;
                  CVdata = 1;
                  memset(tempArray, 'a' , bufferSize);
              }
          }
      }
      if(CVdata ==1 &amp;&amp; CVvalue == 0)
      {
          if(peekBuffer() != ',')
          {
              if(isdigit(peekBuffer()))
              {
                  tempArray[tempIndex] = readBuffer();
                  tempIndex++;
              }
              else
                  readBuffer();
          }
          else
          {
              //readBuffer();
              if(tempIndex &gt; 0)
              {
                  memcpy(valueArray, tempArray, tempIndex);
                  tempIndex = 0;
                  CVvalue = 1;
                  memset(tempArray, 'a', bufferSize);
  
              }
          }
      }
      if(CVdata == 1 &amp;&amp; CVvalue == 1)
      {
          switch(dataArray[0])
          {
              case 'x':
              case 'X':
              {
                  //timer0 = current = atof(valueArray);//ISSUE HERE first char null
                  timer0 = (unsigned int)atoi(valueArray);
                  break;
              }
              case 'y':
              case 'Y':
              {
                  timer1 = (unsigned int)atoi(valueArray);
                  break;
              }
          }
          CVdata = 0;
          CVvalue = 0;
          memset(dataArray, 'a' , bufferSize);
          memset(valueArray, 'a' , bufferSize);
      }
  
      limitServo0();
      limitServo1();
  }
  }
  
  /**********************************************************************************************/
  //Functions
  
  void int2ASCII(unsigned int output)
  {
  unsigned char digit = 0;
  while (output &gt;= 10000) { output -= 10000; digit++; } UART_putChar(digit + 0x30); digit = 0;
  while (output &gt;=  1000) { output -=  1000; digit++; } UART_putChar(digit + 0x30); digit = 0;
  while (output &gt;=   100) { output -=   100; digit++; } UART_putChar(digit + 0x30); digit = 0;
  while (output &gt;=    10) { output -=    10; digit++; } UART_putChar(digit + 0x30); digit = 0;
  while (output &gt;=     1) { output -=     1; digit++; } UART_putChar(digit + 0x30);
  }
  
  void UART_putChar(unsigned char value)
  {
  while(PIR1bits.TXIF == 0);     
  TXREG = value;
  }
  
  char readBuffer()
  {
  if(tail != head)
  {
      ByteOut = array[head];
      head++;
      if(head == bufferSize)
      {
          head = 0;
      }
      return ByteOut;
  }
  //LATCbits.LATC0 = 1;
  }
  char peekBuffer()
  {
  return array[head];
  }
  char emptyBuffer()
  {
  if(tail == head)
      return 1;
  else
      return 0;
  }
  void limitServo0()
  {
  if(timer0 &gt; servo0Max)
      {
          timer0 = servo0Max;
      }
      if(timer0 &lt; servo0Min)
      {
          timer0 = servo0Min;
      }   
  }
  
  void limitServo1()
  {
  if(timer1 &gt; servo1Max)
      {
          timer1 = servo1Max;
      }
      if(timer1 &lt; servo1Min)
      {
          timer1 = servo1Min;
      }
  }
  </code></pre>
  
  <p>An Example of my previous tracking via bitmap can be viewed on my youtube channel at: <a href="http://www.youtube.com/watch?v=rBhkV3dnyiU&amp;list=UULGlw5rGZfETaiPs49JBEuA&amp;index=41" rel="nofollow">http://www.youtube.com/watch?v=rBhkV3dnyiU&amp;list=UULGlw5rGZfETaiPs49JBEuA&amp;index=41</a></p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>After some research it seems I can write a XNA application, capture mouse movement, and output serial communications.  I would really really like a windows forms solution but I do have XNA experience so guess I'll work on converting my application until another solution presents itself.</p>