Created an ACM IMA ADPCM codec.
[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 <stdlib.h>
22 #include <string.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "miscemu.h"
29 #include "dosexe.h"
30 #include "vga.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(int);
34
35 static struct
36 {
37   DWORD x, y, but;
38   WORD lbcount, rbcount, rlastx, rlasty, llastx, llasty;
39   FARPROC16 callback;
40   WORD callmask;
41   WORD VMPratio, HMPratio, oldx, oldy;
42 } mouse_info;
43
44 /**********************************************************************
45  *          DOSVM_Int33Handler
46  *
47  * Handler for int 33h (MS MOUSE).
48  */
49 void WINAPI DOSVM_Int33Handler( CONTEXT86 *context )
50 {
51   switch (LOWORD(context->Eax)) {
52   case 0x00:
53     TRACE("Reset mouse driver and request status\n");
54     AX_reg(context) = 0xFFFF; /* installed */
55     BX_reg(context) = 3;      /* # of buttons */
56     memset( &mouse_info, 0, sizeof(mouse_info) );
57     /* Set the default mickey/pixel ratio */
58     mouse_info.HMPratio = 8;
59     mouse_info.VMPratio = 16;
60     break;
61   case 0x01:
62     FIXME("Show mouse cursor\n");
63     break;
64   case 0x02:
65     FIXME("Hide mouse cursor\n");
66     break;
67   case 0x03:
68     TRACE("Return mouse position and button status: (%ld,%ld) and %ld\n",
69          mouse_info.x, mouse_info.y, mouse_info.but);
70     BX_reg(context) = mouse_info.but;
71     CX_reg(context) = mouse_info.x;
72     DX_reg(context) = mouse_info.y;
73     break;
74   case 0x04:
75     FIXME("Position mouse cursor\n");
76     break;
77   case 0x05:
78     TRACE("Return Mouse button press Information for %s mouse button\n",
79           BX_reg(context) ? "right" : "left");
80     if (BX_reg(context)) {
81       BX_reg(context) = mouse_info.rbcount;
82       mouse_info.rbcount = 0;
83       CX_reg(context) = mouse_info.rlastx;
84       DX_reg(context) = mouse_info.rlasty;
85     } else {
86       BX_reg(context) = mouse_info.lbcount;
87       mouse_info.lbcount = 0;
88       CX_reg(context) = mouse_info.llastx;
89       DX_reg(context) = mouse_info.llasty;
90     }
91     AX_reg(context) = mouse_info.but;
92     break;
93   case 0x07:
94     FIXME("Define horizontal mouse cursor range\n");
95     break;
96   case 0x08:
97     FIXME("Define vertical mouse cursor range\n");
98     break;
99   case 0x09:
100     FIXME("Define graphics mouse cursor\n");
101     break;
102   case 0x0A:
103     FIXME("Define text mouse cursor\n");
104     break;
105   case 0x0B:
106     TRACE("Read Mouse motion counters\n");
107     CX_reg(context) = (mouse_info.x - mouse_info.oldx) * (mouse_info.HMPratio / 8);
108     DX_reg(context) = (mouse_info.y - mouse_info.oldy) * (mouse_info.VMPratio / 8);
109     mouse_info.oldx = mouse_info.x;
110     mouse_info.oldy = mouse_info.y;
111     break;
112   case 0x0C:
113     TRACE("Define mouse interrupt subroutine\n");
114     mouse_info.callmask = CX_reg(context);
115     mouse_info.callback = (FARPROC16)MAKESEGPTR(context->SegEs, LOWORD(context->Edx));
116     break;
117   case 0x0F:
118     TRACE("Set mickey/pixel ratio\n");
119     mouse_info.HMPratio = CX_reg(context);
120     mouse_info.VMPratio = DX_reg(context);
121     break;
122   case 0x10:
123     FIXME("Define screen region for update\n");
124     break;
125   default:
126     INT_BARF(context,0x33);
127   }
128 }
129
130 typedef struct {
131   FARPROC16 proc;
132   WORD mask,but,x,y,mx,my;
133 } MCALLDATA;
134
135 static void MouseRelay(CONTEXT86 *context,void *mdata)
136 {
137   MCALLDATA *data = (MCALLDATA *)mdata;
138   CONTEXT86 ctx = *context;
139
140   ctx.Eax   = data->mask;
141   ctx.Ebx   = data->but;
142   ctx.Ecx   = data->x;
143   ctx.Edx   = data->y;
144   ctx.Esi   = data->mx;
145   ctx.Edi   = data->my;
146   ctx.SegCs = SELECTOROF(data->proc);
147   ctx.Eip   = OFFSETOF(data->proc);
148   free(data);
149   DPMI_CallRMProc(&ctx, NULL, 0, 0);
150 }
151
152 static void QueueMouseRelay(DWORD mx, DWORD my, WORD mask)
153 {
154   mouse_info.x = mx;
155   mouse_info.y = my;
156
157   /* Left button down */
158   if(mask & 0x02) {
159     mouse_info.but |= 0x01;
160     mouse_info.llastx = mx;
161     mouse_info.llasty = my;
162     mouse_info.lbcount++;
163   }
164
165   /* Left button up */
166   if(mask & 0x04) {
167     mouse_info.but &= ~0x01;
168   }
169
170   /* Right button down */
171   if(mask & 0x08) {
172     mouse_info.but |= 0x02;
173     mouse_info.rlastx = mx;
174     mouse_info.rlasty = my;
175     mouse_info.rbcount++;
176   }
177
178   /* Right button up */
179   if(mask & 0x10) {
180     mouse_info.but &= ~0x02;
181   }
182
183   /* Middle button down */
184   if(mask & 0x20) {
185     mouse_info.but |= 0x04;
186   }
187
188   /* Middle button up */
189   if(mask & 0x40) {
190     mouse_info.but &= ~0x04;
191   }
192
193   if ((mask & mouse_info.callmask) && mouse_info.callback) {
194     MCALLDATA *data = calloc(1,sizeof(MCALLDATA));
195     data->proc = mouse_info.callback;
196     data->mask = mask & mouse_info.callmask;
197     data->but = mouse_info.but;
198     data->x = mouse_info.x;
199     data->y = mouse_info.y;
200     DOSVM_QueueEvent(-1, DOS_PRIORITY_MOUSE, MouseRelay, data);
201   }
202 }
203
204 void WINAPI DOSVM_Int33Message(UINT message,WPARAM wParam,LPARAM lParam)
205 {
206   WORD mask = 0;
207   unsigned Height, Width, SX=1, SY=1;
208
209   if (!VGA_GetMode(&Height,&Width,NULL)) {
210     /* may need to do some coordinate scaling */
211     if (Width) 
212       SX = 640/Width;
213     if (!SX) SX=1;
214   }
215
216   switch (message) {
217   case WM_MOUSEMOVE:
218     mask |= 0x01;
219     break;
220   case WM_LBUTTONDOWN:
221   case WM_LBUTTONDBLCLK:
222     mask |= 0x02;
223     break;
224   case WM_LBUTTONUP:
225     mask |= 0x04;
226     break;
227   case WM_RBUTTONDOWN:
228   case WM_RBUTTONDBLCLK:
229     mask |= 0x08;
230     break;
231   case WM_RBUTTONUP:
232     mask |= 0x10;
233     break;
234   case WM_MBUTTONDOWN:
235   case WM_MBUTTONDBLCLK:
236     mask |= 0x20;
237     break;
238   case WM_MBUTTONUP:
239     mask |= 0x40;
240     break;
241   }
242
243   QueueMouseRelay(LOWORD(lParam) * SX,
244                  HIWORD(lParam) * SY,
245                  mask);
246 }
247
248 void WINAPI DOSVM_Int33Console(MOUSE_EVENT_RECORD *record)
249 {
250   unsigned Height, Width;
251   WORD mask = 0;
252   BOOL newLeftButton = record->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED;
253   BOOL oldLeftButton = mouse_info.but & 0x01;
254   BOOL newRightButton = record->dwButtonState & RIGHTMOST_BUTTON_PRESSED;
255   BOOL oldRightButton = mouse_info.but & 0x02;
256   BOOL newMiddleButton = record->dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED;
257   BOOL oldMiddleButton = mouse_info.but & 0x04;
258
259   if(newLeftButton && !oldLeftButton)
260     mask |= 0x02;
261   else if(!newLeftButton && oldLeftButton)
262     mask |= 0x04;
263
264   if(newRightButton && !oldRightButton)
265     mask |= 0x08;
266   else if(!newRightButton && oldRightButton)
267     mask |= 0x10;
268
269   if(newMiddleButton && !oldMiddleButton)
270     mask |= 0x20;
271   else if(!newMiddleButton && oldMiddleButton)
272     mask |= 0x40;
273  
274   VGA_GetAlphaMode(&Width, &Height);
275
276   QueueMouseRelay(640 / Width * record->dwMousePosition.X,
277                  200 / Height * record->dwMousePosition.Y,
278                  mask);
279 }