1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program 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
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 */
21
22 /*
23 * mouse_sdl.cpp - Mouse handling, SDL specific implementation
24 *
25 * May 16, 2002 (Woody Zenfell):
26 * Configurable mouse sensitivity
27 * Semi-hacky scheme to let mouse buttons simulate keypresses
28 */
29
30 #include "cseries.h"
31 #include <math.h>
32
33 #include "mouse.h"
34 #include "player.h"
35 #include "shell.h"
36 #include "preferences.h"
37 #include "screen.h"
38
39 #ifdef __APPLE__
40 #include "mouse_cocoa.h"
41 #endif
42
43
44 // Global variables
45 static bool mouse_active = false;
46 static uint8 button_mask = 0; // Mask of enabled buttons
47 static fixed_yaw_pitch mouselook_delta = {0, 0};
48 static _fixed snapshot_delta_scrollwheel;
49 static int snapshot_delta_x, snapshot_delta_y;
50
51
52 /*
53 * Initialize in-game mouse handling
54 */
55
enter_mouse(short type)56 void enter_mouse(short type)
57 {
58 if (type != _keyboard_or_game_pad) {
59 #ifdef __APPLE__
60 if (input_preferences->raw_mouse_input)
61 OSX_Mouse_Init();
62 #endif
63 SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, input_preferences->raw_mouse_input ? "0" : "1");
64 SDL_SetRelativeMouseMode(SDL_TRUE);
65 mouse_active = true;
66 mouselook_delta = {0, 0};
67 snapshot_delta_scrollwheel = 0;
68 snapshot_delta_x = snapshot_delta_y = 0;
69 button_mask = 0; // Disable all buttons (so a shot won't be fired if we enter the game with a mouse button down from clicking a GUI widget)
70 recenter_mouse();
71 }
72 }
73
74
75 /*
76 * Shutdown in-game mouse handling
77 */
78
exit_mouse(short type)79 void exit_mouse(short type)
80 {
81 if (type != _keyboard_or_game_pad) {
82 SDL_SetRelativeMouseMode(SDL_FALSE);
83 mouse_active = false;
84 #ifdef __APPLE__
85 OSX_Mouse_Shutdown();
86 #endif
87 }
88 }
89
90
91 /*
92 * Calculate new center mouse position when screen size has changed
93 */
94
recenter_mouse(void)95 void recenter_mouse(void)
96 {
97 if (mouse_active) {
98 MainScreenCenterMouse();
99 }
100 }
101
MIX(float start,float end,float factor)102 static inline float MIX(float start, float end, float factor)
103 {
104 return (start * (1.f - factor)) + (end * factor);
105 }
106
107 /*
108 * Take a snapshot of the current mouse state
109 */
110
mouse_idle(short type)111 void mouse_idle(short type)
112 {
113 if (mouse_active) {
114 #ifdef __APPLE__
115 // In raw mode, get unaccelerated deltas from HID system
116 if (input_preferences->raw_mouse_input)
117 OSX_Mouse_GetMouseMovement(&snapshot_delta_x, &snapshot_delta_y);
118 #endif
119
120 // Calculate axis deltas
121 float dx = snapshot_delta_x;
122 float dy = -snapshot_delta_y;
123 snapshot_delta_x = 0;
124 snapshot_delta_y = 0;
125
126 // Mouse inversion
127 if (TEST_FLAG(input_preferences->modifiers, _inputmod_invert_mouse))
128 dy = -dy;
129
130 // Delta sensitivities
131 const float angle_per_scaled_delta = 128/66.f; // assuming _mouse_accel_none
132 float sx = angle_per_scaled_delta * (input_preferences->sens_horizontal / float{FIXED_ONE});
133 float sy = angle_per_scaled_delta * (input_preferences->sens_vertical / float{FIXED_ONE}) * (input_preferences->classic_vertical_aim ? 0.25f : 1.f);
134 switch (input_preferences->mouse_accel_type)
135 {
136 case _mouse_accel_classic:
137 sx *= MIX(1.f, (1/32.f) * fabs(dx * sx), input_preferences->mouse_accel_scale);
138 sy *= MIX(1.f, (1/(input_preferences->classic_vertical_aim ? 8.f : 32.f)) * fabs(dy * sy), input_preferences->mouse_accel_scale);
139 break;
140 case _mouse_accel_none:
141 default:
142 break;
143 }
144
145 // Angular deltas
146 const fixed_angle dyaw = static_cast<fixed_angle>(sx * dx * FIXED_ONE);
147 const fixed_angle dpitch = static_cast<fixed_angle>(sy * dy * FIXED_ONE);
148
149 // Push mouselook delta
150 mouselook_delta = {dyaw, dpitch};
151 }
152 }
153
pull_mouselook_delta()154 fixed_yaw_pitch pull_mouselook_delta()
155 {
156 auto delta = mouselook_delta;
157 mouselook_delta = {0, 0};
158 return delta;
159 }
160
161
162 void
mouse_buttons_become_keypresses(Uint8 * ioKeyMap)163 mouse_buttons_become_keypresses(Uint8* ioKeyMap)
164 {
165 uint8 buttons = SDL_GetMouseState(NULL, NULL);
166 uint8 orig_buttons = buttons;
167 buttons &= button_mask; // Mask out disabled buttons
168
169 for(int i = 0; i < NUM_SDL_REAL_MOUSE_BUTTONS; i++) {
170 ioKeyMap[AO_SCANCODE_BASE_MOUSE_BUTTON + i] =
171 (buttons & SDL_BUTTON(i+1)) ? SDL_PRESSED : SDL_RELEASED;
172 }
173 ioKeyMap[AO_SCANCODE_MOUSESCROLL_UP] = (snapshot_delta_scrollwheel > 0) ? SDL_PRESSED : SDL_RELEASED;
174 ioKeyMap[AO_SCANCODE_MOUSESCROLL_DOWN] = (snapshot_delta_scrollwheel < 0) ? SDL_PRESSED : SDL_RELEASED;
175 snapshot_delta_scrollwheel = 0;
176
177 button_mask |= ~orig_buttons; // A button must be released at least once to become enabled
178 }
179
180 /*
181 * Hide/show mouse pointer
182 */
183
hide_cursor(void)184 void hide_cursor(void)
185 {
186 SDL_ShowCursor(0);
187 }
188
show_cursor(void)189 void show_cursor(void)
190 {
191 SDL_ShowCursor(1);
192 }
193
194
mouse_scroll(bool up)195 void mouse_scroll(bool up)
196 {
197 if (up)
198 snapshot_delta_scrollwheel += 1;
199 else
200 snapshot_delta_scrollwheel -= 1;
201 }
202
mouse_moved(int delta_x,int delta_y)203 void mouse_moved(int delta_x, int delta_y)
204 {
205 snapshot_delta_x += delta_x;
206 snapshot_delta_y += delta_y;
207 }
208