October 25, 2011

Mouse Programming in C - Part 1


Mouse Programming in C - Part 1
When it comes to advanced applications like Games, GUI apps or any graphical application. Mouse is the utmost necessity of a programmer. It’s a powerful tool since in such situations it’s both frustrating and time consuming to rely on keyboard as you do in parallel programming because it‘s sequential. Therefore a good knowledge of mouse programming is warranted for all playful and knowledgeable purposes and to all top-notch DOS programmers.
Mouse Programming can be a very long topic especially when beginner understanding is involved but everything becomes easy with practice.



THEORY

All input devices generate interrupts mouse is no exception to this rule. It also has got a chip inside it which generates interrupt 33h. Later mouse driver converts mouse activity in understandable data for operating system. In DOS (TURBO C) interrupt’s are easily accessible and programmable then to program a whole driver hence they will be used. Since we use interrupts to make mouse functions a basic understanding of interrupts and CPU registers is assumed.

MODES IN MOUSE PROGRAMMING 
Basically programs using mouse follow two approaches.
 # Request Mode
 # Event Mode
Request mode corresponds to polling usually running infinite loop, continuously getting mouse information and calling specific function on condition getting true (like button getting pressed).
Event mode corresponds to idea of interrupt it makes driver call your specified function on a particular activity (like mouse move).
Over cyberspace most articles are silent on Event mode they all use polling which is neither used professionally nor by advanced applications developed on mouse. But PART2 will show you a live example of implementing Event programming for mouse.
  
REQUEST MODE
Before starting off a quick review of interrupt’s going to be used in mouse programming.
There are exactly 24 service defined in 33h but only required ones are shown.
TABLE OF MOUSE FUNCTIONS

SERVICE
ARGUMENTS

RETURN VALUES
WORKING







00h
AX =00h

AX  = FFFFh or   0000h                  
If AX is FFFFh mouse driver installed otherwise not installed. Mouse driver is reset after call, but not displayed on screen.

01h
AX = 01h

           none
Shows mouse cursor on screen.

02h
AX = 02h

           None
Hides mouse cursor.

03h
AX = 03h

CX = (X) position
DX = (Y) position
BX = button status
                      ---BX---
8
7
6
5
4
3
2
1
0

If 0 bit is set ­– left button pressed.
If 1 bit is set – right button pressed.     
If 2 bit is set – middle button pressed.

04h
AX = 04h

CX =(X)position

DX=(X)position

            none
Sets mouse position

07h
AX = 07h
CX =min (X)
DX =max (X)

            none  
Restricts mouse horizontally between minimum X and maximum  X.

08h
AX = 08h

CX = min (Y)

DX = max (Y)

            none         
Restricts mouse vertically between minimum Y and maximum Y.

09h
AX = 09h

BX =horz hotspot

CX = vert hotspot

ES:DX = pointer to screen and cursor mask

            none   
Sets Graphical cursor
Screen mask -AND’ed to screen and cursor mask is XOR’ed.
Bytes 0 – 7 form screen mask.
Bytes 8 – F form the cursor bitmap. 

0Ch
AX = 0Ch

ES:DX = far           pointer to interrupt routine.

CX = interrupt mask.


            none   
4
3
2
1
0

Bit 0 = mouse move
Bit 1 = left button pressed
Bit 2 = left button released
Bit 3 = right button pressed
Bit 4 = right button released
…      =  unused

For speed and learning purposes it’s better to write all coding in assembly though you may find easy int86 style over cyberspace. Let’s write a GUI app with the use of these interrupts. As expected it’s a large code mainly due to BGI though it’s very basic.

PRACTICAL

/* Mouse Programming - part 1 by MyCFiles.com - Change The
Graphic “PATH” Befor Executing on line 214(like C:\\TC\\BGI) */

#include<graphics.h>
#include<stdio.h>
#include<conio.h>
#include<dos.h>

unsigned mouse[8][4] = {
                 0,    // 0000000000000000
                 32766,// 0111111111111110    this mask is and’ed
                 32766,// 0111111111111110    with screen
                 32766,// 0111111111111110
                 32766,// 0111111111111110
                 32766,// 0111111111111110
                 32766,// 0111111111111110
                 0,    // 0000000000000000
                
      65535,
                      65535,
                      65535,
                      65535,
                      65535,
                      65535,
                      65535,
                      65535,

65535,
                      32769,
                      32769,
                      32769,
                      32769,
                      32769,
                      32769,
                      65535,0,
                  
                     0,0,0,0,0,0,0};
typedef int BOOLEAN;

//ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ    GLOBAL VARS   ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
int mX,mY;
BOOLEAN lPress = 0,rPress = 0;

//ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ BUTTON STRUCTURE ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
typedef struct {
     int  x,y,xmax,ymax;
        BOOLEAN isPressed,isReleased;
        char Label[30];
        int col;
}BUTTON;

/*
ÍÍÍÍÍÍÍÍÍÍÍ OUR MOUSE FUNCTIONS ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
 ==> better write a mouse.h out of these functions
 */

void SetMouse() {

     asm mov ax , 00h               // initialise mouse driver
        asm int 33h

        asm mov ax , 01h               // display mouse
        asm int 33h

}

void HideMouse()    {

     asm mov ax , 02h
        asm int 33h
}

void SlaveMouse(int x,int y,int xmax,int ymax)  {

        asm mov cx , x
     asm mov dx , xmax
        asm mov ax , 07h
        asm int 33h             // slave in x and xmax

             asm mov cx , y
     asm mov dx , ymax

asm mov ax , 08h
asm int 33h                // slave in y and ymax

}

void ChangeCursor(unsigned Marr[8][4],int hx,int hy) {

        unsigned sgm = FP_SEG(Marr);    // get the segment
     unsigned off = FP_OFF(Marr);    // get the offset

        asm mov bx , hx       // our x hotspot
        asm mov cx , hy          // our y hotspot
        asm mov ax , sgm      // Load segment ...
        asm mov es , ax       // ...in es (remember mov es,off is not possible)
        asm mov dx , off      //  Load dx with offset
        asm mov ax , 09h
        asm int 33h
}

// this one is tricky

void GetStatus()     {
        asm mov ax , 03h
        asm int 33h

        asm mov mX, cx
        asm mov mY, dx
        asm push bx
        asm shr bx,1
        asm mov rPress,bx
        asm pop bx
        asm and bx,0001h
        asm mov lPress,bx
}



void addButton(BUTTON b[],int size)  {
        int i;

        int currentcolor = getcolor();
        char str[30];
        int Maxx,Maxy;



        for(i = 0; i < size ; i++,b++ )    {
        int x = b->x,y=b->y;
        strcpy(str,b->Label);

        Maxx = b->xmax = x + textwidth(str);
        Maxy = b->ymax = y + textheight(str);

        setfillstyle(1,b->col);
        bar(x,y,Maxx+5,Maxy+5);
     setcolor(WHITE);
     line(x,y,Maxx+5,y);         // First WHITE horizontal line
     line(x,y+1,Maxx+5,y+1);     // Second WHITE horizontal line
     line(x,y,x,Maxy+5);         // First WHITE verticle line
     setcolor(DARKGRAY);
     line(x-1,y,x-1,Maxy+5);     // Second DARKGRAY verticle line
     line(x+1,Maxy+4,Maxx+5,Maxy+4);// Double lined downward horizontal line
     line(x,Maxy+5,Maxx+5,Maxy+5);  // Downward DARKGRAY horizontal line
     line(x,y,Maxx+5,y);           // Third BLACK horizontal above line
     line(Maxx+5,Maxy+5,Maxx+5,y); // Third verticle DARKGRAY line
     setcolor(WHITE);
        outtextxy(x+4,y+3,str);
     setcolor(currentcolor);
     }

}

void Banim(BUTTON *b) {
        int x= b->x,y=b->y,xmax =b->xmax,ymax=b->ymax;
        int currentcolor = getcolor();


        setcolor(DARKGRAY);
     line(x,y,xmax+5,y);          // First WHITE horizontal line
     line(x,y+1,xmax+5,y+1);      // Second WHITE horizontal line
     line(x,y,x,ymax+5);         // First WHITE verticle line
        delay((xmax-x)/2);

        setcolor(WHITE);
     line(x,y,xmax+5,y);          // First WHITE horizontal line
     line(x,y+1,xmax+5,y+1);      // Second WHITE horizontal line
     line(x,y,x,ymax+5);         // First WHITE verticle line
        setcolor(currentcolor);
}

int Checkbutton(BUTTON *b,int size)  {
        int i;

     for(i=0; i < size;i++,b++) {

     GetStatus();    // get the current status of mouse

        if(mX > b->x && mY > b->y &&
                       mX < b->xmax+5 && mY < b->ymax+5)   {
            

              if (lPress || rPress) {           // if button clicked
                     Banim(b);                  // then animate            
                      return i;  // return the index of button clicked
           }
              else{        // blue out the button
                        setcolor(BLUE);
                     outtextxy(b->x+4,b->y+3,b->Label);
                        delay(b->xmax-b->x);    // to avoid flicker
                        setcolor(WHITE);
                        outtextxy(b->x+4,b->y+3,b->Label);

              }
     }
  }
  return -1;

}

void message(char *str)    {          // display our message

        setfillstyle(SOLID_FILL,RED);
        bar(0,450,640,480);
        outtextxy(20,450,str);

}
int main(void)  {

     BUTTON b[6];
        int gd = VGA,gm = VGAHI;
        int x;
        initgraph(&gd,&gm,"C:\\TC\\BGI"); /*add your bgi file path */    

        SetMouse();             // initialize and show mouse
       settextstyle(SMALL_FONT,HORIZ_DIR,6);

/////////////////////////// FILL BUTTON STRUCTURE ////////////////////

        b[0].x = 240;b[0].y = 50;
           strcpy(b[0].Label,"  C ");
                           b[0].col = RED;
     b[1].x = 250;b[1].y = 100;
           strcpy(b[1].Label," C++ ");
                           b[1].col = BROWN;
        b[2].x = 280; b[2].y = 150;
           strcpy(b[2].Label," JAVA ");
                           b[2].col = CYAN;
        b[3].x = 270; b[3].y = 205;
           strcpy(b[3].Label," ASSEMBLY ");
                           b[3].col = MAGENTA;
        b[4].x = 265;b[4].y = 260;
           strcpy(b[4].Label," MY C FILES ");
                           b[4].col = GREEN;
        b[5].x = 570;b[5].y = 10;
           strcpy(b[5].Label,"exit");
                           b[5].col = LIGHTGRAY;

        addButton(b,6);              // add Button’s to Screen


        ChangeCursor(mouse,3,4);           // change default cursor

//////////////////////// SOMEWHAT O..K  POLLING //////////////////////

        while(1)     {
     
    x = Checkbutton(b,6);       // get the button index
    switch(x)   {
          case 0: message("you liked C");
                break;
          case 1: message("you liked C++");
                break;
          case 2: message("you liked JAVA");
                break;
          case 3: message("you liked ASSEMBLY ");
                break;
          case 4: message("you liked MY C FILES");
                break;
          case 5: message("EXIT");
               closegraph();         // don’t forget
                  return 0;
          }

      }
}

Sample Output


The output is like when run under Emulated Turbo C in windows 7 environment.
   
CODE ANALYSIS
Forget “Graphics”!  there are endless possibilities. Better concentrate on Mouse BASICS. 

GLOBAL VARS AND STRUCTURE “BUTTON”
The global variables hold mouse’s current state as per the need of different functions. ‘mX’ and ‘mY’ hold mouse’s X and Y coordinate respectively followed by ‘lPress ’ and ‘rPress ’ set only when left or right mouse button is pressed.
The BUTTON structure fully describes a button on screen. From its initial X and Y cord’s to its maximum length and height followed by BUTTON’s Label and it’s color. You will see how easy polling becomes with this structure.
MOUSE FUNCTIONS
Few assembly instructions. The letter in italic are operands for these instructions.
mov  -> syntax – mov dest,source                                            // moves source in destination
int     -> syntax - int interruptno                                                  // generates interruptno
push  -> syntax – push var or reg                                              // saves a variable or register
pop    -> syntax – pop var or reg                                                                // gets pushed value back into var or reg
shr      -> syntax – shr var or reg, timestoshift                       // right shifts reg or var ‘timestoshift’ times
SetMouse()- Remember you need to initialize mouse driver and set it to its initial state before using any kind of interrupt’s to access mouse’s data. If you don’t results can be WEIRD!!! As the table states 00h initializes mouse driver on its presence but it’s too FANCY to check mouse or even its driver’s presence hence no condition check to FFFFh is given function is followed by showing mouse using 01h. You better break this function into 2.
HideMouse()- Often you will need to hide mouse. Assuming you playing a video on screen you will need to hide mouse and may be at some illegal place depending on your application’s purpose. Table states 02h for this purpose.
SlaveMouse() - A FANCY function with little use in person’s “signature” through mouse in some advanced applications. Table states two consecutive functions 07h and 08h for its usage. It’s quite easy to decode.
ChangeCursor()-  A useful utility indeed. You can set your own cursor. A mouse array is declared globally which is so written according to function’s need.
Declaring RIGHT array-
The integers are decoded here

          SCREEN MASK 0-15                         CURSOR MASK  15-31(starting and ending indexes)
         

Screen mask – It is ANDed with screen that means every 0 results in black color and 1 in what the screen is currently having under the mask. Put simply if you don’t want screen mask to disturb screen write that bit 1 and the thing you want to display should be 0. It is normally held under your cursor mask so it is not visible if you totally overlap it with cursor mask, black pixels will be seen otherwise.
Cursor mask – It is the mask XORed with screen that simply means put 0 where you want to display what exactly being displayed under cursor mask and place where you want to display your cursor should be kept 1.
 TIP - Always try to follow the convention of putting cursor mask over screen mask.
Hotspot is the location inside your screen mask which you want to act like a tracker, here 3 as X and 4 as Y coordinate are used.

GetStatus()-    Table states 03h function to get mouse status. Its definition may seem tricky.
Here is what and how it does.
First it retrieved the information using 03h. Next it set Global vars mX and mY to their respective usages. The way it retrieves lPress and rPress is   saves bx then shifts it right so you get the right key status in LSB then copy it to rPress next retrieve original bx then AND it with 1, in that way every bit except LSB is zeroed result is simply moved in lPress.

FEW WORDS ON GUI
The model used to create a button according to this code is quite simple.
1.       Create an array of BUTTON objects. Fill them with required details.
2.       Call addButton()to add these buttons to screen.
3.       Enter an infinite loop and call Checkbutton().It will return the index of button clicked, -1 otherwise.

The creation of BUTTON structure eases the way of GUI. Traditionally wherever mouse programming is involved dependency exists that means you cannot use any 1 of GUI detection functions in some other project simply due to fixed scope and lack of wide thoughts. The code breaks this barrier.

PROBLEMS WITH CODE
As you might notice code can be slow and flickering may result this is strictly not acceptable in professional apps. The root cause of this problem is that BGI is too slow. If you are familiar with mode 13h programming better implement this model over BGI.

Well that was fun to do and learn. Hope you enjoyed.
Part 2 will be dedicated to event mode mouse programming.
Don’t forget to ask queries.. :)

Related Posts :



3 comments:

Hey man i like your works. i have add your site links in my bookmarks widgets of my sites as "some more stuff on C programming language"
on http://shareprogrammingtips.com/

check out....http://c-gui-thunderbolt.page.tl/C-GUI-Home.htm

Post a Comment

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Related Posts with Thumbnails