DEADSOFTWARE

15ecb11f6c5d84b74de96133d5d6715a476ca538
[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_enabled: Boolean;
26 g_touch_size: Single;
27 g_touch_offset: Single;
28 g_touch_fire: Boolean;
29 g_touch_alt: Boolean;
31 procedure g_Touch_Init;
32 procedure g_Touch_ShowKeyboard(yes: Boolean);
33 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
34 procedure g_Touch_Draw;
36 implementation
38 uses
39 SysUtils,
40 e_log, e_graphics, e_input, g_options, g_game, g_main, g_weapons, g_console;
42 const
43 VS_KEYBOARD = 60000;
44 VS_HIDEKEYBOARD = 60001;
46 var
47 angleFire: Boolean;
48 keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer;
50 procedure GetKeyRect(key: Integer; out x, y, w, h: Integer; out founded: Boolean);
51 var
52 sw, sh, sz: Integer;
53 dpi: Single;
55 procedure S (xx, yy, ww, hh: Single);
56 begin
57 x := Trunc(xx);
58 y := Trunc(yy);
59 w := Trunc(ww);
60 h := Trunc(hh);
61 founded := true;
62 end;
64 begin
65 founded := false;
66 if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
67 dpi := 96;
69 sz := Trunc(g_touch_size * dpi); sw := gScreenWidth; sh := gScreenHeight;
70 x := 0; y := Round(sh * g_touch_offset / 100);
71 w := sz; h := sz;
73 if SDL_IsTextInputActive() = SDL_True then
74 case key of
75 VS_HIDEKEYBOARD: S(sw - (sz/2), 0, sz / 2, sz / 2);
76 end
77 else if g_touch_alt then
78 case key of
79 (* top ------- x ------------------------------- y w ----- h -- *)
80 VK_CONSOLE: S(0, 0, sz / 2, sz / 2);
81 VK_ESCAPE: S(sw - 1*(sz/2) - 1, 0, sz / 2, sz / 2);
82 VS_KEYBOARD: S(sw - 2*(sz/2) - 1, 0, sz / 2, sz / 2);
83 VK_CHAT: S(sw / 2 - (sz/2) / 2 - (sz/2) - 1, 0, sz / 2, sz / 2);
84 VK_STATUS: S(sw / 2 - (sz/2) / 2 - 1, 0, sz / 2, sz / 2);
85 VK_TEAM: S(sw / 2 - (sz/2) / 2 + (sz/2) - 1, 0, sz / 2, sz / 2);
86 (* left --- x - y -------------- w - h --- *)
87 VK_PREV: S(0, sh - 3.0*sz - 1, sz, sz / 2);
88 VK_LEFT: S(0, sh - 2.0*sz - 1, sz, sz * 2);
89 VK_RIGHT: S(sz, sh - 2.0*sz - 1, sz, sz * 2);
90 (* right - x ------------ y -------------- w - h -- *)
91 VK_NEXT: S(sw - 1*sz - 1, sh - 3.0*sz - 1, sz, sz / 2);
92 VK_UP: S(sw - 2*sz - 1, sh - 2.0*sz - 1, sz, sz / 2);
93 VK_FIRE: S(sw - 2*sz - 1, sh - 1.5*sz - 1, sz, sz);
94 VK_DOWN: S(sw - 2*sz - 1, sh - 0.5*sz - 1, sz, sz / 2);
95 VK_JUMP: S(sw - 1*sz - 1, sh - 2.0*sz - 1, sz, sz);
96 VK_OPEN: S(sw - 1*sz - 1, sh - 1.0*sz - 1, sz, sz);
97 end
98 else
99 case key of
100 (* left ----- x ----- y -------------- w ----- h -- *)
101 VK_ESCAPE: S(0.0*sz, y - 1*sz - sz/2, sz, sz / 2);
102 VK_LSTRAFE: S(0.0*sz, y - 0*sz - sz/2, sz / 2, sz);
103 VK_LEFT: S(0.5*sz, y - 0*sz - sz/2, sz, sz);
104 VK_RIGHT: S(1.5*sz, y - 0*sz - sz/2, sz, sz);
105 VK_RSTRAFE: S(2.5*sz, y - 0*sz - sz/2, sz / 2, sz);
106 (* right - x ------------ y --------------- w - h *)
107 VK_UP: S(sw - 1*sz - 1, y - 1*sz - sz/2, sz, sz);
108 VK_FIRE: S(sw - 1*sz - 1, y - 0*sz - sz/2, sz, sz);
109 VK_DOWN: S(sw - 1*sz - 1, y - -1*sz - sz/2, sz, sz);
110 VK_NEXT: S(sw - 2*sz - 1, y - 1*sz - sz/2, sz, sz);
111 VK_JUMP: S(sw - 2*sz - 1, y - 0*sz - sz/2, sz, sz);
112 VK_PREV: S(sw - 3*sz - 1, y - 1*sz - sz/2, sz, sz);
113 VK_OPEN: S(sw - 3*sz - 1, y - 0*sz - sz/2, sz, sz);
114 (* bottom ---- x -------------------------- y ---------------- w ----- h -- *)
115 VK_CHAT: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
116 VK_CONSOLE: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
117 VK_STATUS: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
118 VK_TEAM: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
119 VS_KEYBOARD: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
120 VK_0: S(sw/2 - sz/4 - 5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
121 VK_1: S(sw/2 - sz/4 - 4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
122 VK_2: S(sw/2 - sz/4 - 3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
123 VK_3: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
124 VK_4: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
125 VK_5: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
126 VK_6: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
127 VK_7: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
128 VK_8: S(sw/2 - sz/4 - -3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
129 VK_9: S(sw/2 - sz/4 - -4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
130 VK_A: S(sw/2 - sz/4 - -5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
131 end
132 end;
134 function GetKeyName(key: Integer): String;
135 begin
136 case key of
137 VS_KEYBOARD: result := 'KBD';
138 VS_HIDEKEYBOARD: result := 'KBD';
139 VK_LEFT: result := 'LEFT';
140 VK_RIGHT: result := 'RIGHT';
141 VK_UP: result := 'UP';
142 VK_DOWN: result := 'DOWN';
143 VK_FIRE: result := 'FIRE';
144 VK_OPEN: result := 'OPEN';
145 VK_JUMP: result := 'JUMP';
146 VK_CHAT: result := 'CHAT';
147 VK_ESCAPE: result := 'ESC';
148 VK_0: result := '0';
149 VK_1: result := '1';
150 VK_2: result := '2';
151 VK_3: result := '3';
152 VK_4: result := '4';
153 VK_5: result := '5';
154 VK_6: result := '6';
155 VK_7: result := '7';
156 VK_8: result := '8';
157 VK_9: result := '9';
158 VK_A: result := '10';
159 VK_B: result := '11';
160 VK_C: result := '12';
161 VK_D: result := '13';
162 VK_E: result := '14';
163 VK_F: result := '15';
164 VK_CONSOLE: result := 'CON';
165 VK_STATUS: result := 'STAT';
166 VK_TEAM: result := 'TEAM';
167 VK_PREV: result := '<PREW';
168 VK_NEXT: result := 'NEXT>';
169 VK_LSTRAFE: result := '<';
170 VK_RSTRAFE: result := '>';
171 else
172 if (key > 0) and (key < e_MaxInputKeys) then
173 result := e_KeyNames[key]
174 else
175 result := '<' + IntToStr(key) + '>'
176 end
177 end;
179 function IntersectControl(ctl, xx, yy: Integer): Boolean;
180 var
181 x, y, w, h: Integer;
182 founded: Boolean;
183 begin
184 GetKeyRect(ctl, x, y, w, h, founded);
185 result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h);
186 end;
188 procedure g_Touch_Init;
189 begin
190 {$IFNDEF HEADLESS}
191 g_touch_enabled := SDL_GetNumTouchDevices() > 0
192 {$ENDIF}
193 end;
195 procedure g_Touch_ShowKeyboard(yes: Boolean);
196 begin
197 {$IFNDEF HEADLESS}
198 if not g_touch_enabled then
199 Exit;
201 if yes then
202 SDL_StartTextInput
203 else
204 SDL_StopTextInput
205 {$ENDIF}
206 end;
208 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
209 var
210 x, y, i, finger: Integer;
211 begin
212 if not g_touch_enabled then
213 Exit;
215 finger := ev.fingerId + 2;
216 x := Trunc(ev.x * gScreenWidth);
217 y := Trunc(ev.y * gScreenHeight);
219 for i := VK_FIRSTKEY to VK_LASTKEY do
220 begin
221 if IntersectControl(i, x, y) then
222 begin
223 if ev.type_ = SDL_FINGERUP then
224 keyFinger[i] := 0
225 else if ev.type_ = SDL_FINGERMOTION then
226 keyFinger[i] := finger
227 else if ev.type_ = SDL_FINGERDOWN then
228 begin
229 KeyPress(i); // Menu events
230 keyFinger[i] := finger;
231 end
232 end
233 else if keyFinger[i] = finger then
234 begin
235 if ev.type_ = SDL_FINGERUP then
236 keyFinger[i] := 0
237 else if ev.type_ = SDL_FINGERMOTION then
238 keyFinger[i] := 0
239 end;
241 e_KeyUpDown(i, keyFinger[i] <> 0);
242 end;
244 if IntersectControl(VS_KEYBOARD, x, y) then
245 g_Touch_ShowKeyboard(true);
246 if IntersectControl(VS_HIDEKEYBOARD, x, y) then
247 g_Touch_ShowKeyboard(false);
249 (* emulate up+fire / donw+fire *)
250 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) then
251 begin
252 if keyFinger[VK_UP] <> 0 then
253 begin
254 angleFire := true;
255 keyFinger[VK_FIRE] := keyFinger[VK_UP];
256 e_KeyUpDown(VK_FIRE, true);
257 end
258 else if keyFinger[VK_DOWN] <> 0 then
259 begin
260 angleFire := true;
261 keyFinger[VK_FIRE] := keyFinger[VK_DOWN];
262 e_KeyUpDown(VK_FIRE, true);
263 end
264 else if angleFire then
265 begin
266 angleFire := false;
267 keyFinger[VK_FIRE] := 0;
268 e_KeyUpDown(VK_FIRE, false);
269 end
270 end;
272 (* left/right strafe *)
273 if gGameSettings.GameType <> GT_NONE then
274 begin
275 if keyFinger[VK_LSTRAFE] <> 0 then
276 begin
277 keyFinger[VK_LEFT] := finger;
278 keyFinger[VK_RIGHT] := 0;
279 keyFinger[VK_STRAFE] := finger;
280 e_KeyUpDown(VK_LEFT, true);
281 e_KeyUpDown(VK_RIGHT, false);
282 e_KeyUpDown(VK_STRAFE, true);
283 end
284 else if keyFinger[VK_RSTRAFE] <> 0 then
285 begin
286 keyFinger[VK_LEFT] := 0;
287 keyFinger[VK_RIGHT] := finger;
288 keyFinger[VK_STRAFE] := finger;
289 e_KeyUpDown(VK_LEFT, false);
290 e_KeyUpDown(VK_RIGHT, true);
291 e_KeyUpDown(VK_STRAFE, true);
292 end
293 else
294 begin
295 keyFinger[VK_STRAFE] := 0;
296 e_KeyUpDown(VK_STRAFE, false);
297 end
299 end;
300 end;
302 procedure g_Touch_Draw;
303 var i: Integer;
305 procedure Draw (i: Integer);
306 var x, y, w, h: Integer; founded: Boolean;
307 begin
308 GetKeyRect(i, x, y, w, h, founded);
309 if founded then
310 begin
311 e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31);
312 e_TextureFontPrintEx(x, y, GetKeyName(i), gStdFont, 255, 255, 255, 1, True)
313 end;
314 end;
316 begin
317 {$IFNDEF HEADLESS}
318 if not g_touch_enabled then
319 Exit;
321 for i := VK_FIRSTKEY to VK_LASTKEY do
322 Draw(i);
324 Draw(VS_KEYBOARD);
325 Draw(VS_HIDEKEYBOARD);
326 {$ENDIF}
327 end;
329 initialization
330 conRegVar('touch_enable', @g_touch_enabled, 'enable/disable virtual buttons', 'draw buttons');
331 conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down');
332 conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size');
333 conRegVar('touch_offset', @g_touch_offset, 0, 100, '', '');
334 conRegVar('touch_alt', @g_touch_alt, 'althernative virtual buttons layout', 'althernative layout');
335 end.