Author : Alexander Russell
Page : << Previous 8 Next >>
*
;* *
;*****************************************************
; real code for real men
; adjust for proper memory model
.MODEL SMALL,C
.CODE
PUBLIC mouse_event_func,mouse_int
mouse_event_func DD ?
mouse_int PROC FAR
PUSHF
CALL CS:[mouse_event_func]
RET
mouse_int ENDP
END
This ASM function is called by the int33h driver. Mouse_int() in turn calls what ever function mouse_event_func points to. Mouse_event_func is a pointer to a function - it is not itself a function.
This is the c code to use the mouse.
#define ESC 27
short mouse_x, mouse_y;
short mouse_present;
short mouse_hidden=0;
short button_stat=0;
unsigned short flags;
extern void far *far mouse_event_func;
void mouse_int(void);
typedef struct
{
unsigned int flags, x, y, button_flag;
}
mouse_info_t;
#define MAX_MOUSE_EVENTS 10
#define MOUSE_MOVE 1
#define MOUSE_L_DN 2
#define MOUSE_L_UP 4
#define MOUSE_R_DN 8
#define MOUSE_R_UP 16
#define EVENT_MASK 31 /* the logical OR of the 5 above vars */
mouse_info_t mouse_info[MAX_MOUSE_EVENTS];
int head=0;
int tail=0;
/* the low level interrupt handler calls this */
/* ---------------------- mouse_handler() ----------------- April 1,1993 */
void far interrupt mouse_handler(void)
{
/* save info returned by mouse device driver */
asm {
mov flags, ax
mov mouse_x, cx
mov mouse_y, dx
mov button_stat, bx
}
// place the mouse information in a circular queue
mouse_info[tail].x=mouse_x;
mouse_info[tail].y=mouse_y;
mouse_info[tail].button_flag=button_stat;
mouse_info[tail].flags=flags;
tail++;
if ( tail == MAX_MOUSE_EVENTS )
tail=0;
if ( tail == head )
{
head++;
if ( head == MAX_MOUSE_EVENTS )
head=0;
}
}
/*
the assembler function mouse_int() calls
mouse_event_func whenever the mouse moves, or a button
is pressed, or released. mouse_event_func points to mouse_handler
which ques up the mouse events, get_event can be used to read these
events.
/* is there a mouse, install int handlers */
/* ---------------------- init_mouse() -------------- April 1,1993 */
short init_mouse(void)
{
unsigned short c_seg, c_off;
asm {
xor ax, ax
int 033h
/* note BX holds number of buttons, but we don't care */
mov mouse_present, ax
}
if ( mouse_present )
{
/* install our own handler */
mouse_event_func=mouse_handler; /* global func pointer */
/* install mouse_int as mouse handler, which will call
mouse_handler */
c_seg=FP_SEG(mouse_int);
c_off=FP_OFF(mouse_int);
asm {
mov ax, c_seg
mov es, ax
mov dx, c_off
mov ax, 0ch
mov cx, EVENT_MASK
int 033h
}
/* set mouse x, y limits */
asm {
mov ax, 7
mov cx, 0
mov dx, 359
int 033h
mov ax, 8
mov cx, 0
mov dx, 239
int 033h
/* set initial mouse_x, mouse_y */
mov ax, 3
int 033h
mov mouse_x, cx
mov mouse_y, dx
}
}
return(mouse_present);
}
* ---------------------- deinit_mouse() ------------------ April 1,1993 */
void deinit_mouse(void)
{
if ( mouse_present )
{
/* deinstall our mouse handler by making int 33 never call it */
asm {
mov ax, 0ch
xor cx, cx /* mask == 0, handler never called */
int 033h
/* reset mouse driver */
xor ax, ax
int 033h
}
}
}
See the source files joy.c, mouse.c, mousetub.asm, and key.c for mini programs that demonstrate using all this i/o code.
Event QueueThe next step is to combine all these different input streams into a single combined stream of input. Doing this makes the game program's code much simpler. This combined input stream is demonstrated in chap4.c Below is an excerpt from chap4.c.
// add an event to out generic input queue
/* ---------------------- add_input() ------------------- October 8,1998 */
void add_input(event_t *event)
{
in[i_tail].type=event->type;
in[i_tail].sub_type=event->sub_type;
in[i_tail].x=event->x;
in[i_tail].y=event->y;
in[i_tail].data1=event->data1;
in[i_tail].data2=event->data2;
i_tail++;
if ( i_tail == MAX_INPUT )
i_tail=0;
if ( i_tail == i_head )
{
i_head++;
if ( i_head == MAX_INPUT )
i_head=0;
}
}
// see if there any user generated input waiting for processing
int check_input(event_t *event)
{
int is_event=0;
static unsigned long next_joy_check=0;
event_t new_event;
int dx, dy;
if ( get_tick() > next_joy_check )
{
// read the joy stick only at regular intervals
read_joy();
// this dx/dy thing is to prevent extra joy events caused
// by normal joystick instability
dx=abs(last_joy_x - joy_x);
dy=abs(last_joy_y - joy_y);
if ( dx > 10 || dy > 10 )
{
// add a joy event
new_event.type=JOY;
new_event.sub_type=J_MOVE;
new_event.x=joy_x;
new_event.y=joy_y;
add_input(&new_event);
last_joy_x=joy_x;
last_joy_y=joy_y;
}
next_joy_check=get_tick();
}
read_joy_buttons();
if ( last_b0 != b0 )
{
new_event.type=JOY;
new_event.sub_type=J_BUTTON0;
new_event.data1=!b0;
add_input(&new_event);
last_b0=b0;
}
if ( last_b1 != b1 )
{
new_event.type=JOY;
new_event.sub_type=J_BUTTON1;
new_event.data1=!b1;
add_input(&new_event);
last_b1=b1;
}
// place any pending mouse events in generic queue
// could easily make mouse code place its events directly in
// generic input queue
while ( head != tail )
{
new_event.type=MOUSE;
new_event.x=mouse_info[head].x;
new_event.y=mouse_info[head].y;
if ( mouse_info[head].flags & MOUSE_MOVE )
new_event.sub_type=M_MOVE;
else
{
if ( mouse_info[head].flags & MOUSE_L_DN )
new_event.sub_type=M_L_BUT_DOWN;
else
{
if ( mouse_info[head].flags & MOUSE_L_UP )
new_event.sub_type=M_L_BUT_UP;
else
{
if ( mouse_info[head].flags & MOUSE_R_DN )
new_event.sub_type=M_R_BUT_DOWN;
else
{
if ( mouse_info[head].flags & MOUSE_R_UP )
new_event.sub_type=M_R_BUT_UP;
}
}
}
}
add_input(&new_event);
head++;
if ( head == MAX_MOUSE_EVENTS )
head=0;
}
// place any pending keyboard events in queue
// in a real game you might want to do some processing to
// the raw scan codes to convert them to ASCI or an other
// more convenient format
while ( gb_scan_head != gb_scan_tail )
{
new_event.type=KEY;
new_event.data1=gb_scan_q[gb_scan_head];
// 0xe0 indicates a key from the SECOND keypad, real code will
// follow
if ( new_event.data1 == 0xe0 )
{
gb_scan_head++;
continue;
}
gb_scan_head++;
if ( new_event.data1 & KEY_UP_MASK )
new_event.sub_type=KEY_UP;
else
new_event.sub_type=KEY_DOWN;
new_event.data1&=KEY_ALL_MASK; // clear high bit
// this is where you would convert the raw scan code to ascii
// and do other high level processing if required
// eg new_event.data2=get_ascii(new_event.data1);
add_input(&new_event);
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// check if there are any pending events, and
Page : << Previous 8 Next >>