Allow specifying multiple graphics drivers and use the first one that
[wine] / dlls / winedos / int33.c
1 /*
2  * DOS interrupt 33h handler
3  *
4  * Copyright 1999 Ove Kåven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "miscemu.h"
30 #include "dosexe.h"
31 #include "vga.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(int);
35
36 static struct
37 {
38     WORD x, y, but;
39     WORD lbcount, rbcount, rlastx, rlasty, llastx, llasty;
40     FARPROC16 callback;
41     WORD callmask;
42     WORD VMPratio, HMPratio, oldx, oldy;
43 } mouse_info;
44
45
46 /**********************************************************************
47  *          INT33_ResetMouse
48  *
49  * Handler for:
50  * - subfunction 0x00 (reset mouse)
51  * - subfunction 0x21 (software reset)
52  */
53 static void INT33_ResetMouse( CONTEXT86 *context )
54 {
55     memset( &mouse_info, 0, sizeof(mouse_info) );
56     
57     /* Set the default mickey/pixel ratio */
58     mouse_info.HMPratio = 8;
59     mouse_info.VMPratio = 16;
60
61     if (context)
62     {
63         SET_AX( context, 0xFFFF ); /* driver installed */
64         SET_BX( context, 3 );      /* number of buttons */
65     }
66 }
67
68
69 /**********************************************************************
70  *          DOSVM_Int33Handler (WINEDOS16.151)
71  *
72  * Handler for int 33h (MS MOUSE).
73  */
74 void WINAPI DOSVM_Int33Handler( CONTEXT86 *context )
75 {
76     switch (AX_reg(context))
77     {
78     case 0x0000:
79         TRACE("Reset mouse driver and request status\n");
80         INT33_ResetMouse( context );
81         break;
82
83     case 0x0001:
84         FIXME("Show mouse cursor\n");
85         break;
86
87     case 0x0002:
88         FIXME("Hide mouse cursor\n");
89         break;
90
91     case 0x0003:
92         TRACE("Return mouse position and button status: (%d,%d) and %d\n",
93               mouse_info.x, mouse_info.y, mouse_info.but);
94         SET_BX( context, mouse_info.but );
95         SET_CX( context, mouse_info.x );
96         SET_DX( context, mouse_info.y );
97         break;
98
99     case 0x0004:
100         FIXME("Position mouse cursor\n");
101         break;
102
103     case 0x0005:
104         TRACE("Return Mouse button press Information for %s mouse button\n",
105               BX_reg(context) ? "right" : "left");
106         if (BX_reg(context)) 
107         {
108             SET_BX( context, mouse_info.rbcount );
109             mouse_info.rbcount = 0;
110             SET_CX( context, mouse_info.rlastx );
111             SET_DX( context, mouse_info.rlasty );
112         } 
113         else 
114         {
115             SET_BX( context, mouse_info.lbcount );
116             mouse_info.lbcount = 0;
117             SET_CX( context, mouse_info.llastx );
118             SET_DX( context, mouse_info.llasty );
119         }
120         SET_AX( context, mouse_info.but );
121         break;
122
123     case 0x0007:
124         FIXME("Define horizontal mouse cursor range %d..%d\n",
125               CX_reg(context), DX_reg(context));
126         break;
127
128     case 0x0008:
129         FIXME("Define vertical mouse cursor range %d..%d\n",
130               CX_reg(context), DX_reg(context));
131         break;
132
133     case 0x0009:
134         FIXME("Define graphics mouse cursor\n");
135         break;
136
137     case 0x000A:
138         FIXME("Define text mouse cursor\n");
139         break;
140
141     case 0x000B:
142         TRACE("Read Mouse motion counters\n");
143         {
144             int dx = ((int)mouse_info.x - (int)mouse_info.oldx)
145                 * (mouse_info.HMPratio / 8);
146             int dy = ((int)mouse_info.y - (int)mouse_info.oldy)
147                 * (mouse_info.VMPratio / 8);
148
149             SET_CX( context, (WORD)dx );
150             SET_DX( context, (WORD)dy );
151
152             mouse_info.oldx = mouse_info.x;
153             mouse_info.oldy = mouse_info.y;
154         }
155         break;
156
157     case 0x000C:
158         TRACE("Define mouse interrupt subroutine\n");
159         mouse_info.callmask = CX_reg(context);
160         mouse_info.callback = (FARPROC16)MAKESEGPTR(context->SegEs, 
161                                                     DX_reg(context));
162         break;
163
164     case 0x000F:
165         TRACE("Set mickey/pixel ratio\n");
166         mouse_info.HMPratio = CX_reg(context);
167         mouse_info.VMPratio = DX_reg(context);
168         break;
169
170     case 0x0010:
171         FIXME("Define screen region for update\n");
172         break;
173
174     case 0x0021:
175         TRACE("Software reset\n");
176         INT33_ResetMouse( context );
177         break;
178
179     default:
180         INT_BARF(context,0x33);
181     }
182 }
183
184 typedef struct {
185   FARPROC16 proc;
186   WORD mask,but,x,y,mx,my;
187 } MCALLDATA;
188
189 static void MouseRelay(CONTEXT86 *context,void *mdata)
190 {
191   MCALLDATA *data = (MCALLDATA *)mdata;
192   CONTEXT86 ctx = *context;
193
194   if (!ISV86(&ctx))
195   {
196       ctx.EFlags |= V86_FLAG;
197       ctx.SegSs = 0; /* Allocate new stack. */
198   }
199
200   ctx.Eax   = data->mask;
201   ctx.Ebx   = data->but;
202   ctx.Ecx   = data->x;
203   ctx.Edx   = data->y;
204   ctx.Esi   = data->mx;
205   ctx.Edi   = data->my;
206   ctx.SegCs = SELECTOROF(data->proc);
207   ctx.Eip   = OFFSETOF(data->proc);
208   free(data);
209   DPMI_CallRMProc(&ctx, NULL, 0, 0);
210 }
211
212 static void QueueMouseRelay(DWORD mx, DWORD my, WORD mask)
213 {
214   mouse_info.x = mx;
215   mouse_info.y = my;
216
217   /* Left button down */
218   if(mask & 0x02) {
219     mouse_info.but |= 0x01;
220     mouse_info.llastx = mx;
221     mouse_info.llasty = my;
222     mouse_info.lbcount++;
223   }
224
225   /* Left button up */
226   if(mask & 0x04) {
227     mouse_info.but &= ~0x01;
228   }
229
230   /* Right button down */
231   if(mask & 0x08) {
232     mouse_info.but |= 0x02;
233     mouse_info.rlastx = mx;
234     mouse_info.rlasty = my;
235     mouse_info.rbcount++;
236   }
237
238   /* Right button up */
239   if(mask & 0x10) {
240     mouse_info.but &= ~0x02;
241   }
242
243   /* Middle button down */
244   if(mask & 0x20) {
245     mouse_info.but |= 0x04;
246   }
247
248   /* Middle button up */
249   if(mask & 0x40) {
250     mouse_info.but &= ~0x04;
251   }
252
253   if ((mask & mouse_info.callmask) && mouse_info.callback) {
254     MCALLDATA *data = calloc(1,sizeof(MCALLDATA));
255     data->proc = mouse_info.callback;
256     data->mask = mask & mouse_info.callmask;
257     data->but = mouse_info.but;
258     data->x = mouse_info.x;
259     data->y = mouse_info.y;
260
261     /*
262      * Fake mickeys. 
263      *
264      * FIXME: This is not entirely correct. If mouse if moved to the edge
265      *        of the screen, mouse will stop moving and mickeys won't
266      *        be updated even though they should be.
267      */
268     data->mx = mouse_info.x * (mouse_info.HMPratio / 8);
269     data->my = mouse_info.y * (mouse_info.VMPratio / 8);
270
271     DOSVM_QueueEvent(-1, DOS_PRIORITY_MOUSE, MouseRelay, data);
272   }
273 }
274
275 void WINAPI DOSVM_Int33Message(UINT message,WPARAM wParam,LPARAM lParam)
276 {
277   WORD mask = 0;
278   unsigned Height, Width, SX=1, SY=1;
279
280   if (!VGA_GetMode(&Height,&Width,NULL)) {
281     /* may need to do some coordinate scaling */
282     if (Width)
283       SX = 640/Width;
284     if (!SX) SX=1;
285   }
286
287   switch (message) {
288   case WM_MOUSEMOVE:
289     mask |= 0x01;
290     break;
291   case WM_LBUTTONDOWN:
292   case WM_LBUTTONDBLCLK:
293     mask |= 0x02;
294     break;
295   case WM_LBUTTONUP:
296     mask |= 0x04;
297     break;
298   case WM_RBUTTONDOWN:
299   case WM_RBUTTONDBLCLK:
300     mask |= 0x08;
301     break;
302   case WM_RBUTTONUP:
303     mask |= 0x10;
304     break;
305   case WM_MBUTTONDOWN:
306   case WM_MBUTTONDBLCLK:
307     mask |= 0x20;
308     break;
309   case WM_MBUTTONUP:
310     mask |= 0x40;
311     break;
312   }
313
314   QueueMouseRelay(LOWORD(lParam) * SX,
315                  HIWORD(lParam) * SY,
316                  mask);
317 }
318
319 void WINAPI DOSVM_Int33Console(MOUSE_EVENT_RECORD *record)
320 {
321   unsigned Height, Width;
322   WORD mask = 0;
323   BOOL newLeftButton = record->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED;
324   BOOL oldLeftButton = mouse_info.but & 0x01;
325   BOOL newRightButton = record->dwButtonState & RIGHTMOST_BUTTON_PRESSED;
326   BOOL oldRightButton = mouse_info.but & 0x02;
327   BOOL newMiddleButton = record->dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED;
328   BOOL oldMiddleButton = mouse_info.but & 0x04;
329
330   if(newLeftButton && !oldLeftButton)
331     mask |= 0x02;
332   else if(!newLeftButton && oldLeftButton)
333     mask |= 0x04;
334
335   if(newRightButton && !oldRightButton)
336     mask |= 0x08;
337   else if(!newRightButton && oldRightButton)
338     mask |= 0x10;
339
340   if(newMiddleButton && !oldMiddleButton)
341     mask |= 0x20;
342   else if(!newMiddleButton && oldMiddleButton)
343     mask |= 0x40;
344   
345   if (VGA_GetAlphaMode(&Width, &Height))
346     QueueMouseRelay( 640 / Width * record->dwMousePosition.X,
347                      200 / Height * record->dwMousePosition.Y,
348                      mask );
349 }