- In MZ_DoLoadImage if an environment segment is specified in the
[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     WORD hide_count;
44 } mouse_info;
45
46
47 /**********************************************************************
48  *          INT33_ResetMouse
49  *
50  * Handler for:
51  * - subfunction 0x00 (reset mouse)
52  * - subfunction 0x21 (software reset)
53  */
54 static void INT33_ResetMouse( CONTEXT86 *context )
55 {
56     memset( &mouse_info, 0, sizeof(mouse_info) );
57     
58     /* Set the default mickey/pixel ratio */
59     mouse_info.HMPratio = 8;
60     mouse_info.VMPratio = 16;
61
62     /* Hide the mouse cursor */
63     mouse_info.hide_count = 1;
64     VGA_ShowMouse( FALSE );    
65
66     if (context)
67     {
68         SET_AX( context, 0xFFFF ); /* driver installed */
69         SET_BX( context, 3 );      /* number of buttons */
70     }
71 }
72
73
74 /**********************************************************************
75  *          DOSVM_Int33Handler (WINEDOS16.151)
76  *
77  * Handler for int 33h (MS MOUSE).
78  */
79 void WINAPI DOSVM_Int33Handler( CONTEXT86 *context )
80 {
81     switch (AX_reg(context))
82     {
83     case 0x0000:
84         TRACE("Reset mouse driver and request status\n");
85         INT33_ResetMouse( context );
86         break;
87
88     case 0x0001:
89         TRACE("Show mouse cursor, old hide count: %d\n",
90               mouse_info.hide_count);
91         if (mouse_info.hide_count >= 1)
92             mouse_info.hide_count--;
93         if (!mouse_info.hide_count)
94             VGA_ShowMouse( TRUE );
95         break;
96
97     case 0x0002:
98         TRACE("Hide mouse cursor, old hide count: %d\n",
99               mouse_info.hide_count);
100         if(!mouse_info.hide_count)
101             VGA_ShowMouse( FALSE );            
102         mouse_info.hide_count++;
103         break;
104
105     case 0x0003:
106         TRACE("Return mouse position and button status: (%d,%d) and %d\n",
107               mouse_info.x, mouse_info.y, mouse_info.but);
108         SET_BX( context, mouse_info.but );
109         SET_CX( context, mouse_info.x );
110         SET_DX( context, mouse_info.y );
111         break;
112
113     case 0x0004:
114         FIXME("Position mouse cursor\n");
115         break;
116
117     case 0x0005:
118         TRACE("Return Mouse button press Information for %s mouse button\n",
119               BX_reg(context) ? "right" : "left");
120         if (BX_reg(context)) 
121         {
122             SET_BX( context, mouse_info.rbcount );
123             mouse_info.rbcount = 0;
124             SET_CX( context, mouse_info.rlastx );
125             SET_DX( context, mouse_info.rlasty );
126         } 
127         else 
128         {
129             SET_BX( context, mouse_info.lbcount );
130             mouse_info.lbcount = 0;
131             SET_CX( context, mouse_info.llastx );
132             SET_DX( context, mouse_info.llasty );
133         }
134         SET_AX( context, mouse_info.but );
135         break;
136
137     case 0x0007:
138         FIXME("Define horizontal mouse cursor range %d..%d\n",
139               CX_reg(context), DX_reg(context));
140         break;
141
142     case 0x0008:
143         FIXME("Define vertical mouse cursor range %d..%d\n",
144               CX_reg(context), DX_reg(context));
145         break;
146
147     case 0x0009:
148         FIXME("Define graphics mouse cursor\n");
149         break;
150
151     case 0x000A:
152         FIXME("Define text mouse cursor\n");
153         break;
154
155     case 0x000B:
156         TRACE("Read Mouse motion counters\n");
157         {
158             int dx = ((int)mouse_info.x - (int)mouse_info.oldx)
159                 * (mouse_info.HMPratio / 8);
160             int dy = ((int)mouse_info.y - (int)mouse_info.oldy)
161                 * (mouse_info.VMPratio / 8);
162
163             SET_CX( context, (WORD)dx );
164             SET_DX( context, (WORD)dy );
165
166             mouse_info.oldx = mouse_info.x;
167             mouse_info.oldy = mouse_info.y;
168         }
169         break;
170
171     case 0x000C:
172         TRACE("Define mouse interrupt subroutine\n");
173         mouse_info.callmask = CX_reg(context);
174         mouse_info.callback = (FARPROC16)MAKESEGPTR(context->SegEs, 
175                                                     DX_reg(context));
176         break;
177
178     case 0x000F:
179         TRACE("Set mickey/pixel ratio\n");
180         mouse_info.HMPratio = CX_reg(context);
181         mouse_info.VMPratio = DX_reg(context);
182         break;
183
184     case 0x0010:
185         FIXME("Define screen region for update\n");
186         break;
187
188     case 0x0021:
189         TRACE("Software reset\n");
190         INT33_ResetMouse( context );
191         break;
192
193     default:
194         INT_BARF(context,0x33);
195     }
196 }
197
198 typedef struct {
199   FARPROC16 proc;
200   WORD mask,but,x,y,mx,my;
201 } MCALLDATA;
202
203 static void MouseRelay(CONTEXT86 *context,void *mdata)
204 {
205   MCALLDATA *data = (MCALLDATA *)mdata;
206   CONTEXT86 ctx = *context;
207
208   if (!ISV86(&ctx))
209   {
210       ctx.EFlags |= V86_FLAG;
211       ctx.SegSs = 0; /* Allocate new stack. */
212   }
213
214   ctx.Eax   = data->mask;
215   ctx.Ebx   = data->but;
216   ctx.Ecx   = data->x;
217   ctx.Edx   = data->y;
218   ctx.Esi   = data->mx;
219   ctx.Edi   = data->my;
220   ctx.SegCs = SELECTOROF(data->proc);
221   ctx.Eip   = OFFSETOF(data->proc);
222   free(data);
223   DPMI_CallRMProc(&ctx, NULL, 0, 0);
224 }
225
226 static void QueueMouseRelay(DWORD mx, DWORD my, WORD mask)
227 {
228   mouse_info.x = mx;
229   mouse_info.y = my;
230
231   /* Left button down */
232   if(mask & 0x02) {
233     mouse_info.but |= 0x01;
234     mouse_info.llastx = mx;
235     mouse_info.llasty = my;
236     mouse_info.lbcount++;
237   }
238
239   /* Left button up */
240   if(mask & 0x04) {
241     mouse_info.but &= ~0x01;
242   }
243
244   /* Right button down */
245   if(mask & 0x08) {
246     mouse_info.but |= 0x02;
247     mouse_info.rlastx = mx;
248     mouse_info.rlasty = my;
249     mouse_info.rbcount++;
250   }
251
252   /* Right button up */
253   if(mask & 0x10) {
254     mouse_info.but &= ~0x02;
255   }
256
257   /* Middle button down */
258   if(mask & 0x20) {
259     mouse_info.but |= 0x04;
260   }
261
262   /* Middle button up */
263   if(mask & 0x40) {
264     mouse_info.but &= ~0x04;
265   }
266
267   if ((mask & mouse_info.callmask) && mouse_info.callback) {
268     MCALLDATA *data = calloc(1,sizeof(MCALLDATA));
269     data->proc = mouse_info.callback;
270     data->mask = mask & mouse_info.callmask;
271     data->but = mouse_info.but;
272     data->x = mouse_info.x;
273     data->y = mouse_info.y;
274
275     /*
276      * Fake mickeys. 
277      *
278      * FIXME: This is not entirely correct. If mouse if moved to the edge
279      *        of the screen, mouse will stop moving and mickeys won't
280      *        be updated even though they should be.
281      */
282     data->mx = mouse_info.x * (mouse_info.HMPratio / 8);
283     data->my = mouse_info.y * (mouse_info.VMPratio / 8);
284
285     DOSVM_QueueEvent(-1, DOS_PRIORITY_MOUSE, MouseRelay, data);
286   }
287 }
288
289 void WINAPI DOSVM_Int33Message(UINT message,WPARAM wParam,LPARAM lParam)
290 {
291   WORD mask = 0;
292   unsigned Height, Width, SX=1, SY=1;
293
294   if (!VGA_GetMode(&Height,&Width,NULL)) {
295     /* may need to do some coordinate scaling */
296     if (Width)
297       SX = 640/Width;
298     if (!SX) SX=1;
299   }
300
301   switch (message) {
302   case WM_MOUSEMOVE:
303     mask |= 0x01;
304     break;
305   case WM_LBUTTONDOWN:
306   case WM_LBUTTONDBLCLK:
307     mask |= 0x02;
308     break;
309   case WM_LBUTTONUP:
310     mask |= 0x04;
311     break;
312   case WM_RBUTTONDOWN:
313   case WM_RBUTTONDBLCLK:
314     mask |= 0x08;
315     break;
316   case WM_RBUTTONUP:
317     mask |= 0x10;
318     break;
319   case WM_MBUTTONDOWN:
320   case WM_MBUTTONDBLCLK:
321     mask |= 0x20;
322     break;
323   case WM_MBUTTONUP:
324     mask |= 0x40;
325     break;
326   }
327
328   QueueMouseRelay(LOWORD(lParam) * SX,
329                  HIWORD(lParam) * SY,
330                  mask);
331 }
332
333 void WINAPI DOSVM_Int33Console(MOUSE_EVENT_RECORD *record)
334 {
335   unsigned Height, Width;
336   WORD mask = 0;
337   BOOL newLeftButton = record->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED;
338   BOOL oldLeftButton = mouse_info.but & 0x01;
339   BOOL newRightButton = record->dwButtonState & RIGHTMOST_BUTTON_PRESSED;
340   BOOL oldRightButton = mouse_info.but & 0x02;
341   BOOL newMiddleButton = record->dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED;
342   BOOL oldMiddleButton = mouse_info.but & 0x04;
343
344   if(newLeftButton && !oldLeftButton)
345     mask |= 0x02;
346   else if(!newLeftButton && oldLeftButton)
347     mask |= 0x04;
348
349   if(newRightButton && !oldRightButton)
350     mask |= 0x08;
351   else if(!newRightButton && oldRightButton)
352     mask |= 0x10;
353
354   if(newMiddleButton && !oldMiddleButton)
355     mask |= 0x20;
356   else if(!newMiddleButton && oldMiddleButton)
357     mask |= 0x40;
358   
359   if (VGA_GetAlphaMode(&Width, &Height))
360     QueueMouseRelay( 640 / Width * record->dwMousePosition.X,
361                      200 / Height * record->dwMousePosition.Y,
362                      mask );
363 }