/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * DOS mouse module. * * By Shawn Hargreaves. * * 3-button support added by Fabian Nunez. * * Mark Wodrich added double-buffered drawing of the mouse pointer and * the set_mouse_sprite_focus() function. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintdos.h" #ifndef ALLEGRO_DOS #error something is wrong with the makefile #endif static int mouse_mx = 0; /* internal position, in mickeys */ static int mouse_my = 0; static int mouse_sx = 2; /* mickey -> pixel scaling factor */ static int mouse_sy = 2; static int mouse_minx = 0; /* mouse range */ static int mouse_miny = 0; static int mouse_maxx = 319; static int mouse_maxy = 199; static int mymickey_x = 0; /* for get_mouse_mickeys() */ static int mymickey_y = 0; static int mymickey_ox = 0; static int mymickey_oy = 0; #ifdef ALLEGRO_DJGPP static _go32_dpmi_seginfo mouse_seginfo; #endif static __dpmi_regs mouse_regs; #define MICKEY_TO_COORD_X(n) ((n) / mouse_sx) #define MICKEY_TO_COORD_Y(n) ((n) / mouse_sy) #define COORD_TO_MICKEY_X(n) ((n) * mouse_sx) #define COORD_TO_MICKEY_Y(n) ((n) * mouse_sy) #define CLEAR_MICKEYS() \ { \ __dpmi_regs regs; \ regs.x.ax = 11; \ __dpmi_int(0x33, ®s); \ mymickey_ox = 0; \ mymickey_oy = 0; \ } /* this driver does all our own position tracking, avoiding int 0x33 bugs */ static int mick_init(void); static void mick_exit(void); static void mick_position(int x, int y); static void mick_set_range(int x1, int y1, int x2, int y2); static void mick_set_speed(int xspeed, int yspeed); static void mick_get_mickeys(int *mickeyx, int *mickeyy); MOUSE_DRIVER mousedrv_mickeys = { MOUSEDRV_MICKEYS, empty_string, empty_string, "Mickey mouse", mick_init, mick_exit, NULL, NULL, mick_position, mick_set_range, mick_set_speed, mick_get_mickeys, NULL, NULL, NULL }; /* this driver uses the int 0x33 movement callbacks */ static int int33_init(void); static void int33_exit(void); static void int33_position(int x, int y); static void int33_set_range(int x1, int y1, int x2, int y2); static void int33_set_speed(int xspeed, int yspeed); static void int33_get_mickeys(int *mickeyx, int *mickeyy); MOUSE_DRIVER mousedrv_int33 = { MOUSEDRV_INT33, empty_string, empty_string, "Int 0x33 mouse", int33_init, int33_exit, NULL, NULL, int33_position, int33_set_range, int33_set_speed, int33_get_mickeys, NULL, NULL, NULL }; /* this driver polls int 0x33 from a timer handler */ static int polling_init(void); static void polling_exit(void); static void polling_timer_poll(void); MOUSE_DRIVER mousedrv_polling = { MOUSEDRV_POLLING, empty_string, empty_string, "Polling mouse", polling_init, polling_exit, NULL, polling_timer_poll, int33_position, int33_set_range, int33_set_speed, int33_get_mickeys, NULL, NULL, NULL }; /* this driver is a wrapper for the polling driver*/ static int winnt_init(void); MOUSE_DRIVER mousedrv_winnt = { MOUSEDRV_POLLING, empty_string, empty_string, "Windows NT mouse", winnt_init, polling_exit, NULL, polling_timer_poll, int33_position, int33_set_range, int33_set_speed, int33_get_mickeys, NULL, NULL, NULL }; /* this driver is a wrapper for the mickeys driver */ static int win2k_init(void); MOUSE_DRIVER mousedrv_win2k = { MOUSEDRV_MICKEYS, empty_string, empty_string, "Windows 2000 mouse", win2k_init, mick_exit, NULL, NULL, mick_position, mick_set_range, mick_set_speed, mick_get_mickeys, NULL, NULL, NULL }; /* list the available drivers */ _DRIVER_INFO _mouse_driver_list[] = { { MOUSEDRV_MICKEYS, &mousedrv_mickeys, TRUE }, { MOUSEDRV_INT33, &mousedrv_int33, TRUE }, { MOUSEDRV_POLLING, &mousedrv_polling, TRUE }, { MOUSEDRV_WINNT, &mousedrv_winnt, TRUE }, { MOUSEDRV_WIN2K, &mousedrv_win2k, TRUE }, { MOUSEDRV_NONE, &mousedrv_none, TRUE }, { 0, NULL, 0 } }; /* init_mouse: * Helper for initialising the int 0x33 driver and installing an RMCB. */ static int init_mouse(void (*handler)(__dpmi_regs *r)) { __dpmi_regs r; int num_buttons; /* initialise the int 0x33 driver */ r.x.ax = 0; __dpmi_int(0x33, &r); if (r.x.ax == 0) return -1; num_buttons = r.x.bx; if (num_buttons == 0xFFFF) num_buttons = 2; /* create and activate a real mode callback */ if (handler) { LOCK_VARIABLE(mouse_regs); #ifdef ALLEGRO_DJGPP /* djgpp version uses libc routines to set up the RMCB */ { LOCK_VARIABLE(mouse_seginfo); mouse_seginfo.pm_offset = (int)handler; mouse_seginfo.pm_selector = _my_cs(); if (_go32_dpmi_allocate_real_mode_callback_retf(&mouse_seginfo, &mouse_regs) != 0) return -1; r.x.ax = 0x0C; r.x.cx = 0x7F; r.x.dx = mouse_seginfo.rm_offset; r.x.es = mouse_seginfo.rm_segment; __dpmi_int(0x33, &r); } #elif defined ALLEGRO_WATCOM /* Watcom version relies on the DOS extender to do it for us */ { struct SREGS sregs; union REGS inregs, outregs; inregs.w.ax = 0x0C; inregs.w.cx = 0x7F; inregs.x.edx = _allocate_real_mode_callback(handler, &mouse_regs); segread(&sregs); sregs.es = _my_cs(); int386x(0x33, &inregs, &outregs, &sregs); } #else #error unknown platform #endif } return num_buttons; } /* mick_handler: * Movement callback for mickey-mode driver. */ static void mick_handler(__dpmi_regs *r) { int x = (signed short)r->x.si; int y = (signed short)r->x.di; _mouse_b = r->x.bx; mymickey_x += x - mymickey_ox; mymickey_y += y - mymickey_oy; mymickey_ox = x; mymickey_oy = y; _mouse_x = MICKEY_TO_COORD_X(mouse_mx + x); _mouse_y = MICKEY_TO_COORD_Y(mouse_my + y); if ((_mouse_x < mouse_minx) || (_mouse_x > mouse_maxx) || (_mouse_y < mouse_miny) || (_mouse_y > mouse_maxy)) { _mouse_x = MID(mouse_minx, _mouse_x, mouse_maxx); _mouse_y = MID(mouse_miny, _mouse_y, mouse_maxy); mouse_mx = COORD_TO_MICKEY_X(_mouse_x); mouse_my = COORD_TO_MICKEY_Y(_mouse_y); CLEAR_MICKEYS(); } _handle_mouse_input(); } END_OF_STATIC_FUNCTION(mick_handler); /* mick_position: * Sets the position of the mickey-mode mouse. */ static void mick_position(int x, int y) { DISABLE(); _mouse_x = x; _mouse_y = y; mouse_mx = COORD_TO_MICKEY_X(x); mouse_my = COORD_TO_MICKEY_Y(y); CLEAR_MICKEYS(); mymickey_x = mymickey_y = 0; ENABLE(); } /* mick_set_range: * Sets the range of the mickey-mode mouse. */ static void mick_set_range(int x1, int y1, int x2, int y2) { mouse_minx = x1; mouse_miny = y1; mouse_maxx = x2; mouse_maxy = y2; DISABLE(); _mouse_x = MID(mouse_minx, _mouse_x, mouse_maxx); _mouse_y = MID(mouse_miny, _mouse_y, mouse_maxy); mouse_mx = COORD_TO_MICKEY_X(_mouse_x); mouse_my = COORD_TO_MICKEY_Y(_mouse_y); CLEAR_MICKEYS(); ENABLE(); } /* mick_set_speed: * Sets the speed of the mickey-mode mouse. */ static void mick_set_speed(int xspeed, int yspeed) { DISABLE(); mouse_sx = MAX(1, xspeed); mouse_sy = MAX(1, yspeed); mouse_mx = COORD_TO_MICKEY_X(_mouse_x); mouse_my = COORD_TO_MICKEY_Y(_mouse_y); CLEAR_MICKEYS(); ENABLE(); } /* mick_get_mickeys: * Reads the mickey-mode count. */ static void mick_get_mickeys(int *mickeyx, int *mickeyy) { int temp_x = mymickey_x; int temp_y = mymickey_y; mymickey_x -= temp_x; mymickey_y -= temp_y; *mickeyx = temp_x; *mickeyy = temp_y; } /* mick_lock: * Locks the mickeys stuff. */ static void mick_lock(void) { LOCK_VARIABLE(mousedrv_mickeys); LOCK_VARIABLE(mouse_mx); LOCK_VARIABLE(mouse_my); LOCK_VARIABLE(mouse_sx); LOCK_VARIABLE(mouse_sy); LOCK_VARIABLE(mouse_minx); LOCK_VARIABLE(mouse_miny); LOCK_VARIABLE(mouse_maxx); LOCK_VARIABLE(mouse_maxy); LOCK_VARIABLE(mymickey_x); LOCK_VARIABLE(mymickey_y); LOCK_VARIABLE(mymickey_ox); LOCK_VARIABLE(mymickey_oy); LOCK_FUNCTION(mick_handler); } /* mick_init: * Initialises the mickey-mode driver. */ static int mick_init(void) { if (os_type == OSTYPE_WINNT) return -1; mick_lock(); return init_mouse(mick_handler); } /* win2k_init: * Initialises the win2k driver. */ static int win2k_init(void) { /* only for use under Win2k */ if (os_type != OSTYPE_WINNT) return -1; mick_lock(); return init_mouse(mick_handler); } /* mick_exit: * Shuts down the mickey-mode driver. */ static void mick_exit(void) { __dpmi_regs r; r.x.ax = 0x0C; /* install NULL callback */ r.x.cx = 0; r.x.dx = 0; r.x.es = 0; __dpmi_int(0x33, &r); #ifdef ALLEGRO_DJGPP _go32_dpmi_free_real_mode_callback(&mouse_seginfo); #endif } /* int33_handler: * Movement callback for the int 0x33 driver. */ static void int33_handler(__dpmi_regs *r) { _mouse_x = r->x.cx / 8; _mouse_y = r->x.dx / 8; _mouse_b = r->x.bx; _handle_mouse_input(); } END_OF_STATIC_FUNCTION(int33_handler); /* int33_position: * Sets the int 0x33 cursor position. */ static void int33_position(int x, int y) { __dpmi_regs r; _mouse_x = x; _mouse_y = y; r.x.ax = 4; r.x.cx = x * 8; r.x.dx = y * 8; __dpmi_int(0x33, &r); r.x.ax = 11; __dpmi_int(0x33, &r); } /* int33_set_range: * Sets the int 0x33 movement range. */ static void int33_set_range(int x1, int y1, int x2, int y2) { __dpmi_regs r; r.x.ax = 7; /* set horizontal range */ r.x.cx = x1 * 8; r.x.dx = x2 * 8; __dpmi_int(0x33, &r); r.x.ax = 8; /* set vertical range */ r.x.cx = y1 * 8; r.x.dx = y2 * 8; __dpmi_int(0x33, &r); r.x.ax = 3; /* check the position */ __dpmi_int(0x33, &r); _mouse_x = r.x.cx / 8; _mouse_y = r.x.dx / 8; } /* int33_set_speed: * Sets the int 0x33 movement speed. */ static void int33_set_speed(int xspeed, int yspeed) { __dpmi_regs r; r.x.ax = 15; r.x.cx = xspeed; r.x.dx = yspeed; __dpmi_int(0x33, &r); } /* int33_get_mickeys: * Reads the int 0x33 mickey count. */ static void int33_get_mickeys(int *mickeyx, int *mickeyy) { __dpmi_regs r; r.x.ax = 11; __dpmi_int(0x33, &r); *mickeyx = (signed short)r.x.cx; *mickeyy = (signed short)r.x.dx; } /* int33_init: * Initialises the int 0x33 driver. */ static int int33_init(void) { if (os_type == OSTYPE_WINNT) return -1; LOCK_VARIABLE(mousedrv_int33); LOCK_FUNCTION(int33_handler); return init_mouse(int33_handler); } /* int33_exit: * Shuts down the int 0x33 driver. */ static void int33_exit(void) { __dpmi_regs r; r.x.ax = 0x0C; /* install NULL callback */ r.x.cx = 0; r.x.dx = 0; r.x.es = 0; __dpmi_int(0x33, &r); r.x.ax = 15; /* reset sensitivity */ r.x.cx = 8; r.x.dx = 16; __dpmi_int(0x33, &r); #ifdef ALLEGRO_DJGPP _go32_dpmi_free_real_mode_callback(&mouse_seginfo); #endif } /* polling_timer_poll: * Handler for the periodic timer polling mode. */ static void polling_timer_poll(void) { __dpmi_regs r; r.x.ax = 3; __dpmi_int(0x33, &r); _mouse_b = r.x.bx; _mouse_x = r.x.cx / 8; _mouse_y = r.x.dx / 8; } END_OF_STATIC_FUNCTION(polling_timer_poll); /* polling_init: * Initialises the periodic timer driver. */ static int polling_init(void) { if (os_type == OSTYPE_WINNT) return -1; LOCK_VARIABLE(mousedrv_polling); LOCK_FUNCTION(polling_timer_poll); return init_mouse(NULL); } /* winnt_init: * Initialises the WinNT driver. */ static int winnt_init(void) { /* only for use under WinNT */ if (os_type != OSTYPE_WINNT) return -1; LOCK_VARIABLE(mousedrv_polling); LOCK_FUNCTION(polling_timer_poll); return init_mouse(NULL); } /* polling_exit: * Shuts down the periodic timer driver. */ static void polling_exit(void) { __dpmi_regs r; r.x.ax = 15; /* reset sensitivity */ r.x.cx = 8; r.x.dx = 16; __dpmi_int(0x33, &r); }