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.
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---
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
|
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) */
Graphic “PATH” Befor Executing on line 214(like C:\\TC\\BGI) */
#include<graphics.h>
#include<stdio.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;
}
}
}
Refer this article Turbo C++ for windows vista and windows7 64 bit, 32 bit
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 – 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.. :)
Don’t forget to ask queries.. :)
Categories:
c tutorial
,
Mouse Programming
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/
Thank you jiagr.. :)
check out....http://c-gui-thunderbolt.page.tl/C-GUI-Home.htm
Post a Comment