DEADSOFTWARE

Added touchscreen settings
[d2df-sdl.git] / src / game / g_touch.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_touch;
19 interface
21 uses
22 SDL2;
24 var
25 g_touch_size: Single;
26 g_touch_fire: Boolean;
28 procedure g_Touch_Init;
29 procedure g_Touch_ShowKeyboard(yes: Boolean);
30 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
31 procedure g_Touch_Draw;
33 implementation
35 uses
36 SysUtils,
37 e_log, e_graphics, e_input, g_options, g_game, g_main, g_weapons, g_console;
39 var
40 jab: Boolean;
41 enabled: Boolean;
42 angleFire: Boolean;
43 keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer;
45 procedure GetKeyRect(key: Word; out x, y, w, h: Integer; out founded: Boolean);
46 var
47 sw, sh, sz: Integer;
48 dpi: Single;
49 begin
50 if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
51 dpi := 96;
53 founded := true;
54 sz := Trunc(g_touch_size * dpi);
55 sw := gScreenWidth; sh := gScreenHeight;
56 if jab then
57 begin
58 w := sz div 2; h := sz div 3;
59 case key of
60 VK_CONSOLE: begin x := 0; y := 0 end;
61 VK_ESCAPE: begin x := sw - w - 1; y := 0 end;
62 VK_CHAT: begin x := sw div 2 - w - 4; y := 0 end;
63 VK_TEAM: begin x := sw div 2 + 0 + 4; y := 0 end;
64 else
65 w := sz; h := sz * 2;
66 case key of
67 VK_LEFT: begin x := 0; y := sh - h - 1 end;
68 VK_RIGHT: begin x := w; y := sh - h - 1 end;
69 else
70 w := sz; h := sz;
71 case key of
72 VK_OPEN: begin h := sz; x := sw - 1*w - 1; y := sh - 1*h - 1 end;
73 VK_JUMP: begin h := sz; x := sw - 1*w - 1; y := sh - 2*h - 1 end;
74 VK_UP: begin h := sz div 2; x := sw - 2*w - 1; y := sh - 2*sz - 1 end;
75 VK_FIRE: begin h := sz; x := sw - 2*w - 1; y := sh - sz div 2 - sz - 1 end;
76 VK_DOWN: begin h := sz div 2; x := sw - 2*w - 1; y := sh - sz div 2 - 1 end;
77 VK_PREV: begin h := sz div 2; x := 0; y := sh - 3*sz - 1 end;
78 VK_NEXT: begin h := sz div 2; x := sw - w - 1; y := sh - 3*sz - 1 end;
79 else
80 founded := false
81 end
82 end
83 end
84 end
85 else
86 begin
87 x := 0; y := 0; w := sz; h := sz;
88 case key of
89 VK_LSTRAFE: begin x := 0; y := sh div 2 - h div 2; w := w div 2 end;
90 VK_LEFT: begin x := w div 2; y := sh div 2 - h div 2 end;
91 VK_RIGHT: begin x := w div 2 + 1*w;y := sh div 2 - h div 2 end;
92 VK_RSTRAFE: begin x := w div 2 + 2*w;y := sh div 2 - h div 2; w := w div 2 end;
93 VK_UP: begin x := sw - w - 1; y := sh div 2 - h div 2 - h end;
94 VK_FIRE: begin x := sw - 1*w - 1; y := sh div 2 - h div 2 end;
95 VK_DOWN: begin x := sw - w - 1; y := sh div 2 - h div 2 + h end;
96 VK_NEXT: begin x := sw - 2*w - 1; y := sh div 2 - h div 2 - h end;
97 VK_JUMP: begin x := sw - 2*w - 1; y := sh div 2 - h div 2 end;
98 VK_PREV: begin x := sw - 3*w - 1; y := sh div 2 - h div 2 - h end;
99 VK_OPEN: begin x := sw - 3*w - 1; y := sh div 2 - h div 2 end;
100 else
101 w := sz div 2; h := sz div 2;
102 case key of
103 VK_0: begin x := sw div 2 - w div 2 - 5*w - 1; y := sh - 1*h - 1 end;
104 VK_1: begin x := sw div 2 - w div 2 - 4*w - 1; y := sh - 1*h - 1 end;
105 VK_2: begin x := sw div 2 - w div 2 - 3*w - 1; y := sh - 1*h - 1 end;
106 VK_3: begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 1*h - 1 end;
107 VK_4: begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 1*h - 1 end;
108 VK_5: begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 1*h - 1 end;
109 VK_6: begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 1*h - 1 end;
110 VK_7: begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 1*h - 1 end;
111 VK_8: begin x := sw div 2 - w div 2 + 3*w - 1; y := sh - 1*h - 1 end;
112 VK_9: begin x := sw div 2 - w div 2 + 4*w - 1; y := sh - 1*h - 1 end;
113 VK_A: begin x := sw div 2 - w div 2 + 5*w - 1; y := sh - 1*h - 1 end;
114 VK_CHAT: begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 2*h - 1 end;
115 VK_ESCAPE: begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 2*h - 1 end;
116 VK_CONSOLE: begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 2*h - 1 end;
117 VK_STATUS: begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 2*h - 1 end;
118 VK_TEAM: begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 2*h - 1 end;
119 else
120 founded := false
121 end
122 end
123 end
124 end;
126 function GetKeyName(key: Word): String;
127 begin
128 case key of
129 VK_LEFT: result := 'LEFT';
130 VK_RIGHT: result := 'RIGHT';
131 VK_UP: result := 'UP';
132 VK_DOWN: result := 'DOWN';
133 VK_FIRE: result := 'FIRE';
134 VK_OPEN: result := 'OPEN';
135 VK_JUMP: result := 'JUMP';
136 VK_CHAT: result := 'CHAT';
137 VK_ESCAPE: result := 'ESC';
138 VK_0: result := '0';
139 VK_1: result := '1';
140 VK_2: result := '2';
141 VK_3: result := '3';
142 VK_4: result := '4';
143 VK_5: result := '5';
144 VK_6: result := '6';
145 VK_7: result := '7';
146 VK_8: result := '8';
147 VK_9: result := '9';
148 VK_A: result := '10';
149 VK_B: result := '11';
150 VK_C: result := '12';
151 VK_D: result := '13';
152 VK_E: result := '14';
153 VK_F: result := '15';
154 VK_CONSOLE: result := 'CON';
155 VK_STATUS: result := 'STAT';
156 VK_TEAM: result := 'TEAM';
157 VK_PREV: result := '<PREW';
158 VK_NEXT: result := 'NEXT>';
159 VK_LSTRAFE: result := '<';
160 VK_RSTRAFE: result := '>';
161 else
162 if (key > 0) and (key < e_MaxInputKeys) then
163 result := e_KeyNames[key]
164 else
165 result := '<' + IntToStr(key) + '>'
166 end
167 end;
169 procedure DrawRect(x, y, w, h: Integer);
170 begin
171 e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31);
172 end;
174 function IntersectControl(ctl, xx, yy: Integer): Boolean;
175 var
176 x, y, w, h: Integer;
177 founded: Boolean;
178 begin
179 GetKeyRect(ctl, x, y, w, h, founded);
180 result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h);
181 end;
183 procedure g_Touch_Init;
184 begin
185 {$IFNDEF HEADLESS}
186 enabled := SDL_GetNumTouchDevices() > 0
187 {$ENDIF}
188 end;
190 procedure g_Touch_ShowKeyboard(yes: Boolean);
191 begin
192 {$IFNDEF HEADLESS}
193 if not enabled then
194 Exit;
196 if yes then
197 SDL_StartTextInput
198 else
199 SDL_StopTextInput
200 {$ENDIF}
201 end;
203 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
204 var
205 x, y, i, finger: Integer;
206 begin
207 if not enabled then
208 Exit;
209 if SDL_IsTextInputActive() = SDL_True then
210 Exit;
212 finger := ev.fingerId + 2;
213 x := Trunc(ev.x * gScreenWidth);
214 y := Trunc(ev.y * gScreenHeight);
216 for i := VK_FIRSTKEY to VK_LASTKEY do
217 begin
218 if IntersectControl(i, x, y) then
219 begin
220 if ev.type_ = SDL_FINGERUP then
221 keyFinger[i] := 0
222 else if ev.type_ = SDL_FINGERMOTION then
223 keyFinger[i] := finger
224 else if ev.type_ = SDL_FINGERDOWN then
225 begin
226 KeyPress(i); // Menu events
227 keyFinger[i] := finger;
228 end
229 end
230 else if keyFinger[i] = finger then
231 begin
232 if ev.type_ = SDL_FINGERUP then
233 keyFinger[i] := 0
234 else if ev.type_ = SDL_FINGERMOTION then
235 keyFinger[i] := 0
236 end;
238 e_KeyUpDown(i, keyFinger[i] <> 0);
239 end;
241 (* emulate up+fire / donw+fire *)
242 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) then
243 begin
244 if keyFinger[VK_UP] <> 0 then
245 begin
246 angleFire := true;
247 keyFinger[VK_FIRE] := keyFinger[VK_UP];
248 e_KeyUpDown(VK_FIRE, true);
249 end
250 else if keyFinger[VK_DOWN] <> 0 then
251 begin
252 angleFire := true;
253 keyFinger[VK_FIRE] := keyFinger[VK_DOWN];
254 e_KeyUpDown(VK_FIRE, true);
255 end
256 else if angleFire then
257 begin
258 angleFire := false;
259 keyFinger[VK_FIRE] := 0;
260 e_KeyUpDown(VK_FIRE, false);
261 end
262 end;
264 (* left/right strafe *)
265 if gGameSettings.GameType <> GT_NONE then
266 begin
267 if keyFinger[VK_LSTRAFE] <> 0 then
268 begin
269 keyFinger[VK_LEFT] := finger;
270 keyFinger[VK_RIGHT] := 0;
271 keyFinger[VK_STRAFE] := finger;
272 e_KeyUpDown(VK_LEFT, true);
273 e_KeyUpDown(VK_RIGHT, false);
274 e_KeyUpDown(VK_STRAFE, true);
275 end
276 else if keyFinger[VK_RSTRAFE] <> 0 then
277 begin
278 keyFinger[VK_LEFT] := 0;
279 keyFinger[VK_RIGHT] := finger;
280 keyFinger[VK_STRAFE] := finger;
281 e_KeyUpDown(VK_LEFT, false);
282 e_KeyUpDown(VK_RIGHT, true);
283 e_KeyUpDown(VK_STRAFE, true);
284 end
285 else
286 begin
287 keyFinger[VK_STRAFE] := 0;
288 e_KeyUpDown(VK_STRAFE, false);
289 end
290 end;
291 end;
293 procedure g_Touch_Draw;
294 var
295 i, x, y, w, h: Integer;
296 founded: Boolean;
297 begin
298 {$IFNDEF HEADLESS}
299 if not enabled then
300 Exit;
301 if SDL_IsTextInputActive() = SDL_True then
302 Exit;
304 for i := VK_FIRSTKEY to VK_LASTKEY do
305 begin
306 GetKeyRect(i, x, y, w, h, founded);
307 if founded then
308 begin
309 DrawRect(x, y, w, h);
310 e_TextureFontPrint(x, y, GetKeyName(i), gStdFont)
311 end;
312 end;
313 {$ENDIF}
314 end;
316 initialization
317 conRegVar('touch_enable', @enabled, 'enable/disable virtual buttons', 'draw buttons');
318 conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down');
319 conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size');
320 conRegVar('touch_alt', @jab, 'althernative virtual buttons layout', 'althernative layout');
321 end.