1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 //
15 // MOUSELIBW32.CPP
16 //
17 // Library of mouse functions for graphics and text mode
18 //
19 // (c) 1994 Chris Jones
20 // Win32 (allegro) update (c) 1999 Chris Jones
21 //
22 //=============================================================================
23
24 #if defined (WINDOWS_VERSION)
25 #include <dos.h>
26 #include <conio.h>
27 #include <process.h>
28 #endif
29
30 #include <stdio.h>
31
32 #include "util/wgt2allg.h"
33
34 #ifndef TRUE
35 #define TRUE 1
36 #define FALSE 0
37 #endif
38
39 #include "ac/gamestate.h"
40 #include "debug/out.h"
41 #include "device/mousew32.h"
42 #include "gfx/bitmap.h"
43 #include "gfx/gfx_util.h"
44 #include "main/graphics_mode.h"
45 #include "platform/base/agsplatformdriver.h"
46 #include "util/math.h"
47 #if defined(MAC_VERSION)
48 #include "ac/global_game.h" // j for IsKeyPressed
49 #endif
50
51 using namespace AGS::Common;
52 using namespace AGS::Engine;
53
54
55 extern char lib_file_name[13];
56
57 char *mouselibcopyr = "MouseLib32 (c) 1994, 1998 Chris Jones";
58 const int NONE = -1, LEFT = 0, RIGHT = 1, MIDDLE = 2;
59 char currentcursor = 0;
60 // virtual mouse cursor coordinates
61 int mousex = 0, mousey = 0, numcurso = -1, hotx = 0, hoty = 0;
62 // real mouse coordinates and bounds
63 int real_mouse_x = 0, real_mouse_y = 0;
64 int boundx1 = 0, boundx2 = 99999, boundy1 = 0, boundy2 = 99999;
65 int disable_mgetgraphpos = 0;
66 char ignore_bounds = 0;
67 extern char alpha_blend_cursor ;
68 Bitmap *mousecurs[MAXCURSORS];
69 extern color palette[256];
70 extern volatile bool switched_away;
71
72 namespace Mouse
73 {
74 // Tells whether mouse was locked to the game window
75 bool LockedToWindow = false;
76
77 // Screen rectangle, in which the mouse movement is controlled by engine
78 Rect ControlRect;
79 // Mouse control enabled flag
80 bool ControlEnabled = false;
81 // Flag that tells whether the mouse must be forced to stay inside control rect
82 bool ConfineInCtrlRect = false;
83 // Mouse speed value provided by user
84 float SpeedVal = 1.f;
85 // Mouse speed unit
86 float SpeedUnit = 1.f;
87 // Actual speed factor (cached)
88 float Speed = 1.f;
89
90
91 void AdjustPosition(int &x, int &y);
92 }
93
mgraphconfine(int x1,int y1,int x2,int y2)94 void mgraphconfine(int x1, int y1, int x2, int y2)
95 {
96 Mouse::ControlRect = Rect(x1, y1, x2, y2);
97 set_mouse_range(Mouse::ControlRect.Left, Mouse::ControlRect.Top, Mouse::ControlRect.Right, Mouse::ControlRect.Bottom);
98 Debug::Printf("Mouse confined: (%d,%d)-(%d,%d) (%dx%d)",
99 Mouse::ControlRect.Left, Mouse::ControlRect.Top, Mouse::ControlRect.Right, Mouse::ControlRect.Bottom,
100 Mouse::ControlRect.GetWidth(), Mouse::ControlRect.GetHeight());
101 }
102
mgetgraphpos()103 void mgetgraphpos()
104 {
105 poll_mouse();
106 if (disable_mgetgraphpos)
107 {
108 // The cursor coordinates are provided from alternate source;
109 // in this case we completely ignore actual cursor movement.
110 if (!ignore_bounds &&
111 (mousex < boundx1 || mousey < boundy1 || mousex > boundx2 || mousey > boundy2))
112 {
113 mousex = Math::Clamp(boundx1, boundx2, mousex);
114 mousey = Math::Clamp(boundy1, boundy2, mousey);
115 msetgraphpos(mousex, mousey);
116 }
117 return;
118 }
119
120 if (!switched_away && Mouse::ControlEnabled)
121 {
122 // Control mouse movement by querying mouse mickeys (movement deltas)
123 // and applying them to saved mouse coordinates.
124 int mickey_x, mickey_y;
125 get_mouse_mickeys(&mickey_x, &mickey_y);
126
127 // Apply mouse speed
128 int dx = Mouse::Speed * mickey_x;
129 int dy = Mouse::Speed * mickey_y;
130
131 //
132 // Perform actual cursor update
133 //---------------------------------------------------------------------
134 // If the real cursor is inside the control rectangle (read - game window),
135 // then apply sensitivity factors and adjust real cursor position
136 if (Mouse::ControlRect.IsInside(real_mouse_x + dx, real_mouse_y + dy))
137 {
138 real_mouse_x += dx;
139 real_mouse_y += dy;
140 position_mouse(real_mouse_x, real_mouse_y);
141 }
142 // Otherwise, if real cursor was moved outside the control rect, yet we
143 // are required to confine cursor inside one, then adjust cursor position
144 // to stay inside the rect's bounds.
145 else if (Mouse::ConfineInCtrlRect)
146 {
147 real_mouse_x = Math::Clamp(Mouse::ControlRect.Left, Mouse::ControlRect.Right, real_mouse_x + dx);
148 real_mouse_y = Math::Clamp(Mouse::ControlRect.Top, Mouse::ControlRect.Bottom, real_mouse_y + dy);
149 position_mouse(real_mouse_x, real_mouse_y);
150 }
151 // Lastly, if the real cursor is out of the control rect, simply add
152 // actual movement to keep up with the system cursor coordinates.
153 else
154 {
155 real_mouse_x += mickey_x;
156 real_mouse_y += mickey_y;
157 }
158
159 // Do not update the game cursor if the real cursor is beyond the control rect
160 if (!Mouse::ControlRect.IsInside(real_mouse_x, real_mouse_y))
161 return;
162 }
163 else
164 {
165 // Save real cursor coordinates provided by system
166 real_mouse_x = mouse_x;
167 real_mouse_y = mouse_y;
168 }
169
170 // Set new in-game cursor position
171 mousex = real_mouse_x;
172 mousey = real_mouse_y;
173
174 if (!ignore_bounds &&
175 (mousex < boundx1 || mousey < boundy1 || mousex > boundx2 || mousey > boundy2))
176 {
177 mousex = Math::Clamp(boundx1, boundx2, mousex);
178 mousey = Math::Clamp(boundy1, boundy2, mousey);
179 msetgraphpos(mousex, mousey);
180 }
181
182 // Convert to virtual coordinates
183 Mouse::AdjustPosition(mousex, mousey);
184 }
185
msetcursorlimit(int x1,int y1,int x2,int y2)186 void msetcursorlimit(int x1, int y1, int x2, int y2)
187 {
188 boundx1 = x1;
189 boundy1 = y1;
190 boundx2 = x2;
191 boundy2 = y2;
192 }
193
194 int hotxwas = 0, hotywas = 0;
domouse(int str)195 void domouse(int str)
196 {
197 /*
198 TO USE THIS ROUTINE YOU MUST LOAD A MOUSE CURSOR USING mloadcursor.
199 YOU MUST ALSO REMEMBER TO CALL mfreemem AT THE END OF THE PROGRAM.
200 */
201 int poow = mousecurs[currentcursor]->GetWidth();
202 int pooh = mousecurs[currentcursor]->GetHeight();
203 int smx = mousex - hotxwas, smy = mousey - hotywas;
204
205 mgetgraphpos();
206 mousex -= hotx;
207 mousey -= hoty;
208
209 if (mousex + poow >= play.viewport.GetWidth())
210 poow = play.viewport.GetWidth() - mousex;
211
212 if (mousey + pooh >= play.viewport.GetHeight())
213 pooh = play.viewport.GetHeight() - mousey;
214
215 mousex += hotx;
216 mousey += hoty;
217 hotxwas = hotx;
218 hotywas = hoty;
219 }
220
ismouseinbox(int lf,int tp,int rt,int bt)221 int ismouseinbox(int lf, int tp, int rt, int bt)
222 {
223 if ((mousex >= lf) & (mousex <= rt) & (mousey >= tp) & (mousey <= bt))
224 return TRUE;
225 else
226 return FALSE;
227 }
228
mfreemem()229 void mfreemem()
230 {
231 for (int re = 0; re < numcurso; re++) {
232 delete mousecurs[re];
233 }
234 }
235
mnewcursor(char cursno)236 void mnewcursor(char cursno)
237 {
238 domouse(2);
239 currentcursor = cursno;
240 domouse(1);
241 }
242
243
mloadwcursor(char * namm)244 void mloadwcursor(char *namm)
245 {
246 color dummypal[256];
247 if (wloadsprites(&dummypal[0], namm, mousecurs, 0, MAXCURSORS)) {
248 //printf("C_Load_wCursor: Error reading mouse cursor file\n");
249 exit(1);
250 }
251 }
252
253 int butwas = 0;
mgetbutton()254 int mgetbutton()
255 {
256 int toret = NONE;
257 poll_mouse();
258 int butis = mouse_b;
259
260 if ((butis > 0) & (butwas > 0))
261 return NONE; // don't allow holding button down
262
263 if (butis & 1)
264 {
265 toret = LEFT;
266 #if defined(MAC_VERSION)
267 // j Ctrl-left click should be right-click
268 if (IsKeyPressed(405) || IsKeyPressed(406))
269 {
270 toret = RIGHT;
271 }
272 #endif
273 }
274 else if (butis & 2)
275 toret = RIGHT;
276 else if (butis & 4)
277 toret = MIDDLE;
278
279 butwas = butis;
280 return toret;
281 }
282
283 const int MB_ARRAY[3] = { 1, 2, 4 };
misbuttondown(int buno)284 int misbuttondown(int buno)
285 {
286 poll_mouse();
287 if (mouse_b & MB_ARRAY[buno])
288 return TRUE;
289 return FALSE;
290 }
291
msetgraphpos(int xa,int ya)292 void msetgraphpos(int xa, int ya)
293 {
294 real_mouse_x = xa;
295 real_mouse_y = ya;
296 position_mouse(real_mouse_x, real_mouse_y);
297 }
298
msethotspot(int xx,int yy)299 void msethotspot(int xx, int yy)
300 {
301 hotx = xx; // mousex -= hotx; mousey -= hoty;
302 hoty = yy; // mousex += hotx; mousey += hoty;
303 }
304
minstalled()305 int minstalled()
306 {
307 return install_mouse();
308 }
309
AdjustPosition(int & x,int & y)310 void Mouse::AdjustPosition(int &x, int &y)
311 {
312 x = GameScaling.X.UnScalePt(x) - play.viewport.Left;
313 y = GameScaling.Y.UnScalePt(y) - play.viewport.Top;
314 }
315
SetGraphicArea()316 void Mouse::SetGraphicArea()
317 {
318 Rect dst_r = GameScaling.ScaleRange(play.viewport);
319 mgraphconfine(dst_r.Left, dst_r.Top, dst_r.Right, dst_r.Bottom);
320 }
321
SetMoveLimit(const Rect & r)322 void Mouse::SetMoveLimit(const Rect &r)
323 {
324 Rect src_r = OffsetRect(r, play.viewport.GetLT());
325 Rect dst_r = GameScaling.ScaleRange(src_r);
326 msetcursorlimit(dst_r.Left, dst_r.Top, dst_r.Right, dst_r.Bottom);
327 }
328
SetPosition(const Point p)329 void Mouse::SetPosition(const Point p)
330 {
331 msetgraphpos(GameScaling.X.ScalePt(p.X + play.viewport.Left), GameScaling.Y.ScalePt(p.Y + play.viewport.Top));
332 }
333
IsLockedToWindow()334 bool Mouse::IsLockedToWindow()
335 {
336 return LockedToWindow;
337 }
338
TryLockToWindow()339 bool Mouse::TryLockToWindow()
340 {
341 if (!LockedToWindow)
342 LockedToWindow = platform->LockMouseToWindow();
343 return LockedToWindow;
344 }
345
UnlockFromWindow()346 void Mouse::UnlockFromWindow()
347 {
348 platform->UnlockMouse();
349 LockedToWindow = false;
350 }
351
EnableControl(bool confine)352 void Mouse::EnableControl(bool confine)
353 {
354 ControlEnabled = true;
355 ConfineInCtrlRect = confine;
356 }
357
DisableControl()358 void Mouse::DisableControl()
359 {
360 ControlEnabled = false;
361 ConfineInCtrlRect = false;
362 }
363
IsControlEnabled()364 bool Mouse::IsControlEnabled()
365 {
366 return ControlEnabled;
367 }
368
SetSpeedUnit(float f)369 void Mouse::SetSpeedUnit(float f)
370 {
371 SpeedUnit = f;
372 Speed = SpeedVal / SpeedUnit;
373 }
374
GetSpeedUnit()375 float Mouse::GetSpeedUnit()
376 {
377 return SpeedUnit;
378 }
379
SetSpeed(float speed)380 void Mouse::SetSpeed(float speed)
381 {
382 SpeedVal = Math::Max(0.f, speed);
383 Speed = SpeedUnit * SpeedVal;
384 }
385
GetSpeed()386 float Mouse::GetSpeed()
387 {
388 return SpeedVal;
389 }
390