1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/util.h"
24 #include "ags/engine/device/mouse_w32.h"
25 #include "ags/engine/ac/game_state.h"
26 #include "ags/engine/ac/sys_events.h"
27 #include "ags/shared/debugging/out.h"
28 #include "ags/shared/gfx/bitmap.h"
29 #include "ags/engine/main/graphics_mode.h"
30 #include "ags/engine/platform/base/ags_platform_driver.h"
31 #include "ags/engine/platform/base/sys_main.h"
32 #include "ags/globals.h"
33 
34 namespace AGS3 {
35 
36 using namespace AGS::Shared;
37 using namespace AGS::Engine;
38 
39 enum {
40 	NONE = -1, LEFT = 0, RIGHT = 1, MIDDLE = 2
41 };
42 
43 // static const int MB_ARRAY[3] = { 1, 2, 4 };
44 
mgetgraphpos()45 void mgetgraphpos() {
46 	// TODO: review and possibly rewrite whole thing;
47 	// research what disable_mgetgraphpos does, and is this still necessary?
48 	// disable or update mouse speed control to sdl
49 	// (does sdl support mouse cursor speed? is it even necessary anymore?);
50 
51 	// TODO: [sonneveld] find out where mgetgraphpos is needed, are events polled before that?
52 	sys_evt_process_pending();
53 
54 	if (_G(disable_mgetgraphpos)) {
55 		// The cursor coordinates are provided from alternate source;
56 		// in this case we completely ignore actual cursor movement.
57 		if (!_G(ignore_bounds) &&
58 			// When applying script bounds we only do so while cursor is inside game viewport
59 			_GP(mouse).ControlRect.IsInside(_G(mousex), _G(mousey)) &&
60 			(_G(mousex) < _G(boundx1) || _G(mousey) < _G(boundy1) || _G(mousex) > _G(boundx2) || _G(mousey) > _G(boundy2))) {
61 			_G(mousex) = CLIP(_G(mousex), _G(boundx1), _G(boundx2));
62 			_G(mousey) = CLIP(_G(mousey), _G(boundy1), _G(boundy2));
63 			msetgraphpos(_G(mousex), _G(mousey));
64 		}
65 		return;
66 	}
67 
68 	if (!_G(switched_away) && _GP(mouse).ControlEnabled) {
69 		// Use relative mouse movement; speed factor should already be applied by SDL in this mode
70 		int rel_x, rel_y;
71 		ags_mouse_get_relxy(rel_x, rel_y);
72 		_G(real_mouse_x) = CLIP(_G(real_mouse_x) + rel_x, _GP(mouse).ControlRect.Left, _GP(mouse).ControlRect.Right);
73 		_G(real_mouse_y) = CLIP(_G(real_mouse_y) + rel_y, _GP(mouse).ControlRect.Top, _GP(mouse).ControlRect.Bottom);
74 	} else {
75 		// Save real cursor coordinates provided by system
76 		_G(real_mouse_x) = _G(sys_mouse_x);
77 		_G(real_mouse_y) = _G(sys_mouse_y);
78 	}
79 
80 	// Set new in-game cursor position
81 	_G(mousex) = _G(real_mouse_x);
82 	_G(mousey) = _G(real_mouse_y);
83 
84 	if (!_G(ignore_bounds) &&
85 		// When applying script bounds we only do so while cursor is inside game viewport
86 		_GP(mouse).ControlRect.IsInside(_G(mousex), _G(mousey)) &&
87 		(_G(mousex) < _G(boundx1) || _G(mousey) < _G(boundy1) || _G(mousex) > _G(boundx2) || _G(mousey) > _G(boundy2))) {
88 		_G(mousex) = Math::Clamp(_G(mousex), _G(boundx1), _G(boundx2));
89 		_G(mousey) = Math::Clamp(_G(mousey), _G(boundy1), _G(boundy2));
90 		msetgraphpos(_G(mousex), _G(mousey));
91 	}
92 
93 	// Convert to virtual coordinates
94 	_GP(mouse).WindowToGame(_G(mousex), _G(mousey));
95 }
96 
msetcursorlimit(int x1,int y1,int x2,int y2)97 void msetcursorlimit(int x1, int y1, int x2, int y2) {
98 	_G(boundx1) = x1;
99 	_G(boundy1) = y1;
100 	_G(boundx2) = x2;
101 	_G(boundy2) = y2;
102 }
103 
domouse(int str)104 void domouse(int str) {
105 	int poow = _G(mousecurs)[(int)_G(currentcursor)]->GetWidth();
106 	int pooh = _G(mousecurs)[(int)_G(currentcursor)]->GetHeight();
107 	//int smx = _G(mousex) - _G(hotxwas), smy = _G(mousey) - _G(hotywas);
108 	const Rect &viewport = _GP(play).GetMainViewport();
109 
110 	mgetgraphpos();
111 	_G(mousex) -= _G(hotx);
112 	_G(mousey) -= _G(hoty);
113 
114 	if (_G(mousex) + poow >= viewport.GetWidth())
115 		poow = viewport.GetWidth() - _G(mousex);
116 
117 	if (_G(mousey) + pooh >= viewport.GetHeight())
118 		pooh = viewport.GetHeight() - _G(mousey);
119 
120 	_G(mousex) += _G(hotx);
121 	_G(mousey) += _G(hoty);
122 	_G(hotxwas) = _G(hotx);
123 	_G(hotywas) = _G(hoty);
124 }
125 
msetgraphpos(int xa,int ya)126 void msetgraphpos(int xa, int ya) {
127 	_G(real_mouse_x) = xa;
128 	_G(real_mouse_y) = ya;
129 	sys_window_set_mouse(_G(real_mouse_x), _G(real_mouse_y));
130 }
131 
msethotspot(int xx,int yy)132 void msethotspot(int xx, int yy) {
133 	_G(hotx) = xx;  // _G(mousex) -= _G(hotx); _G(mousey) -= _G(hoty);
134 	_G(hoty) = yy;  // _G(mousex) += _G(hotx); _G(mousey) += _G(hoty);
135 }
136 
minstalled()137 int minstalled() {
138 	// Number of buttons supported
139 	return 3;
140 }
141 
WindowToGame(int & x,int & y)142 void Mouse::WindowToGame(int &x, int &y) {
143 	x = _GP(GameScaling).X.UnScalePt(x) - _GP(play).GetMainViewport().Left;
144 	y = _GP(GameScaling).Y.UnScalePt(y) - _GP(play).GetMainViewport().Top;
145 }
146 
SetMoveLimit(const Rect & r)147 void Mouse::SetMoveLimit(const Rect &r) {
148 	Rect src_r = OffsetRect(r, _GP(play).GetMainViewport().GetLT());
149 	Rect dst_r = _GP(GameScaling).ScaleRange(src_r);
150 	msetcursorlimit(dst_r.Left, dst_r.Top, dst_r.Right, dst_r.Bottom);
151 }
152 
SetPosition(const Point p)153 void Mouse::SetPosition(const Point p) {
154 	msetgraphpos(_GP(GameScaling).X.ScalePt(p.X + _GP(play).GetMainViewport().Left), _GP(GameScaling).Y.ScalePt(p.Y + _GP(play).GetMainViewport().Top));
155 }
156 
IsLockedToWindow()157 bool Mouse::IsLockedToWindow() {
158 	return LockedToWindow;
159 }
160 
TryLockToWindow()161 bool Mouse::TryLockToWindow() {
162 	if (!LockedToWindow)
163 		LockedToWindow = _G(platform)->LockMouseToWindow();
164 	return LockedToWindow;
165 }
166 
UnlockFromWindow()167 void Mouse::UnlockFromWindow() {
168 	_G(platform)->UnlockMouse();
169 	LockedToWindow = false;
170 }
171 
SetSpeedUnit(float f)172 void Mouse::SetSpeedUnit(float f) {
173 	SpeedUnit = f;
174 	Speed = SpeedVal / SpeedUnit;
175 }
176 
IsControlEnabled() const177 bool Mouse::IsControlEnabled() const {
178 	return ControlEnabled;
179 }
180 
GetSpeedUnit()181 float Mouse::GetSpeedUnit() {
182 	return SpeedUnit;
183 }
184 
SetSpeed(float speed)185 void Mouse::SetSpeed(float speed) {
186 	SpeedVal = Math::Max(0.f, speed);
187 	Speed = SpeedUnit * SpeedVal;
188 }
189 
GetSpeed()190 float Mouse::GetSpeed() {
191 	return SpeedVal;
192 }
193 
UpdateGraphicArea()194 void Mouse::UpdateGraphicArea() {
195 	Mouse::ControlRect = _GP(GameScaling).ScaleRange(_GP(play).GetMainViewport());
196 	Debug::Printf("Mouse cursor graphic area: (%d,%d)-(%d,%d) (%dx%d)",
197 		Mouse::ControlRect.Left, Mouse::ControlRect.Top, Mouse::ControlRect.Right, Mouse::ControlRect.Bottom,
198 		Mouse::ControlRect.GetWidth(), Mouse::ControlRect.GetHeight());
199 }
200 
SetMovementControl(bool flag)201 void Mouse::SetMovementControl(bool flag) {
202 	ControlEnabled = false;
203 	warning("movement control not supported, mouse control can't be enabled");
204 	ags_clear_mouse_movement();
205 }
206 
207 } // namespace AGS3
208