DEADSOFTWARE

menu: optionally disable menu in client
[d2df-sdl.git] / src / game / sdl2 / 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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_touch;
18 interface
20 uses
21 SDL2;
23 var
24 g_touch_enabled: Boolean = False;
25 g_touch_size: Single = 1.0;
26 g_touch_offset: Single = 50.0;
27 g_touch_fire: Boolean = True;
28 g_touch_alt: Boolean = False;
30 procedure g_Touch_Init;
31 procedure g_Touch_ShowKeyboard(yes: Boolean);
32 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
33 procedure g_Touch_Draw;
35 implementation
37 uses
38 {$IFDEF ENABLE_MENU}
39 g_gui,
40 {$ENDIF}
41 SysUtils,
42 e_log, r_graphics, r_game, e_input, g_options, g_game, g_weapons, g_console
43 ;
45 var
46 angleFire: Boolean;
47 keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer;
49 procedure GetKeyRect(key: Integer; out x, y, w, h: Integer; out founded: Boolean);
50 var
51 sw, sh, sz: Integer;
52 dpi: Single;
54 procedure S (xx, yy, ww, hh: Single);
55 begin
56 x := Trunc(xx);
57 y := Trunc(yy);
58 w := Trunc(ww);
59 h := Trunc(hh);
60 founded := true;
61 end;
63 begin
64 founded := false;
65 {$IFNDEF SDL2_NODPI}
66 if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
67 dpi := 96;
68 {$ELSE}
69 dpi := 96;
70 {$ENDIF}
72 sz := Trunc(g_touch_size * dpi); sw := gWinSizeX; sh := gWinSizeY;
73 x := 0; y := Round(sh * g_touch_offset / 100);
74 w := sz; h := sz;
76 if SDL_IsTextInputActive() = SDL_True then
77 case key of
78 VK_HIDEKBD: S(sw - (sz/2), 0, sz / 2, sz / 2);
79 end
80 else if g_touch_alt then
81 case key of
82 (* top ------- x ------------------------------- y w ----- h -- *)
83 VK_CONSOLE: S(0, 0, sz / 2, sz / 2);
84 VK_ESCAPE: S(sw - 1*(sz/2) - 1, 0, sz / 2, sz / 2);
85 VK_SHOWKBD: S(sw - 2*(sz/2) - 1, 0, sz / 2, sz / 2);
86 VK_CHAT: S(sw / 2 - (sz/2) / 2 - (sz/2) - 1, 0, sz / 2, sz / 2);
87 VK_STATUS: S(sw / 2 - (sz/2) / 2 - 1, 0, sz / 2, sz / 2);
88 VK_TEAM: S(sw / 2 - (sz/2) / 2 + (sz/2) - 1, 0, sz / 2, sz / 2);
89 (* left --- x - y -------------- w - h --- *)
90 VK_PREV: S(0, sh - 3.0*sz - 1, sz, sz / 2);
91 VK_LEFT: S(0, sh - 2.0*sz - 1, sz, sz * 2);
92 VK_RIGHT: S(sz, sh - 2.0*sz - 1, sz, sz * 2);
93 (* right - x ------------ y -------------- w - h -- *)
94 VK_NEXT: S(sw - 1*sz - 1, sh - 3.0*sz - 1, sz, sz / 2);
95 VK_UP: S(sw - 2*sz - 1, sh - 2.0*sz - 1, sz, sz / 2);
96 VK_FIRE: S(sw - 2*sz - 1, sh - 1.5*sz - 1, sz, sz);
97 VK_DOWN: S(sw - 2*sz - 1, sh - 0.5*sz - 1, sz, sz / 2);
98 VK_JUMP: S(sw - 1*sz - 1, sh - 2.0*sz - 1, sz, sz);
99 VK_OPEN: S(sw - 1*sz - 1, sh - 1.0*sz - 1, sz, sz);
100 end
101 else
102 case key of
103 (* left ----- x ----- y -------------- w ----- h -- *)
104 VK_ESCAPE: S(0.0*sz, y - 1*sz - sz/2, sz, sz / 2);
105 VK_LSTRAFE: S(0.0*sz, y - 0*sz - sz/2, sz / 2, sz);
106 VK_LEFT: S(0.5*sz, y - 0*sz - sz/2, sz, sz);
107 VK_RIGHT: S(1.5*sz, y - 0*sz - sz/2, sz, sz);
108 VK_RSTRAFE: S(2.5*sz, y - 0*sz - sz/2, sz / 2, sz);
109 (* right - x ------------ y --------------- w - h *)
110 VK_UP: S(sw - 1*sz - 1, y - 1*sz - sz/2, sz, sz);
111 VK_FIRE: S(sw - 1*sz - 1, y - 0*sz - sz/2, sz, sz);
112 VK_DOWN: S(sw - 1*sz - 1, y - -1*sz - sz/2, sz, sz);
113 VK_NEXT: S(sw - 2*sz - 1, y - 1*sz - sz/2, sz, sz);
114 VK_JUMP: S(sw - 2*sz - 1, y - 0*sz - sz/2, sz, sz);
115 VK_PREV: S(sw - 3*sz - 1, y - 1*sz - sz/2, sz, sz);
116 VK_OPEN: S(sw - 3*sz - 1, y - 0*sz - sz/2, sz, sz);
117 (* bottom ---- x -------------------------- y ---------------- w ----- h -- *)
118 VK_CHAT: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
119 VK_CONSOLE: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
120 VK_STATUS: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
121 VK_TEAM: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
122 VK_SHOWKBD: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
123 VK_0: S(sw/2 - sz/4 - 5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
124 VK_1: S(sw/2 - sz/4 - 4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
125 VK_2: S(sw/2 - sz/4 - 3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
126 VK_3: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
127 VK_4: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
128 VK_5: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
129 VK_6: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
130 VK_7: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
131 VK_8: S(sw/2 - sz/4 - -3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
132 VK_9: S(sw/2 - sz/4 - -4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
133 VK_A: S(sw/2 - sz/4 - -5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
134 end
135 end;
137 function GetKeyName(key: Integer): String;
138 begin
139 case key of
140 VK_SHOWKBD: result := 'KBD';
141 VK_HIDEKBD: result := 'KBD';
142 VK_LEFT: result := 'LEFT';
143 VK_RIGHT: result := 'RIGHT';
144 VK_UP: result := 'UP';
145 VK_DOWN: result := 'DOWN';
146 VK_FIRE: result := 'FIRE';
147 VK_OPEN: result := 'OPEN';
148 VK_JUMP: result := 'JUMP';
149 VK_CHAT: result := 'CHAT';
150 VK_ESCAPE: result := 'ESC';
151 VK_0: result := '0';
152 VK_1: result := '1';
153 VK_2: result := '2';
154 VK_3: result := '3';
155 VK_4: result := '4';
156 VK_5: result := '5';
157 VK_6: result := '6';
158 VK_7: result := '7';
159 VK_8: result := '8';
160 VK_9: result := '9';
161 VK_A: result := '10';
162 VK_B: result := '11';
163 VK_C: result := '12';
164 VK_D: result := '13';
165 VK_E: result := '14';
166 VK_F: result := '15';
167 VK_CONSOLE: result := 'CON';
168 VK_STATUS: result := 'STAT';
169 VK_TEAM: result := 'TEAM';
170 VK_PREV: result := '<PREW';
171 VK_NEXT: result := 'NEXT>';
172 VK_LSTRAFE: result := '<';
173 VK_RSTRAFE: result := '>';
174 else
175 if (key > 0) and (key < e_MaxInputKeys) then
176 result := e_KeyNames[key]
177 else
178 result := '<' + IntToStr(key) + '>'
179 end
180 end;
182 function IntersectControl(ctl, xx, yy: Integer): Boolean;
183 var
184 x, y, w, h: Integer;
185 founded: Boolean;
186 begin
187 GetKeyRect(ctl, x, y, w, h, founded);
188 result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h);
189 end;
191 procedure g_Touch_Init;
192 begin
193 {$IFNDEF HEADLESS}
194 g_Touch_ShowKeyboard(FALSE);
195 g_touch_enabled := SDL_GetNumTouchDevices() > 0
196 {$ENDIF}
197 end;
199 procedure g_Touch_ShowKeyboard(yes: Boolean);
200 begin
201 {$IFNDEF HEADLESS}
202 if g_dbg_input then
203 e_LogWritefln('g_Touch_ShowKeyboard(%s)', [yes]);
204 (* on desktop we always receive text (needed for cheats) *)
205 if yes or (SDL_HasScreenKeyboardSupport() = SDL_FALSE) then
206 SDL_StartTextInput
207 else
208 SDL_StopTextInput
209 {$ENDIF}
210 end;
212 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
213 var
214 x, y, i, finger: Integer;
216 procedure KeyUp (finger, i: Integer);
217 begin
218 if g_dbg_input then
219 e_LogWritefln('Input Debug: g_touch.KeyUp, finger=%s, key=%s', [finger, i]);
221 keyFinger[i] := 0;
222 e_KeyUpDown(i, False);
223 g_Console_ProcessBind(i, False);
225 (* up/down + fire hack *)
226 {$IFDEF ENABLE_MENU}
227 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) and angleFire then
228 {$ELSE}
229 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and angleFire then
230 {$ENDIF}
231 begin
232 if (i = VK_UP) or (i = VK_DOWN) then
233 begin
234 angleFire := False;
235 keyFinger[VK_FIRE] := 0;
236 e_KeyUpDown(VK_FIRE, False);
237 g_Console_ProcessBind(VK_FIRE, False)
238 end
239 end
240 end;
242 procedure KeyDown (finger, i: Integer);
243 begin
244 if g_dbg_input then
245 e_LogWritefln('Input Debug: g_touch.KeyDown, finger=%s, key=%s', [finger, i]);
247 keyFinger[i] := finger;
248 e_KeyUpDown(i, True);
249 g_Console_ProcessBind(i, True);
251 (* up/down + fire hack *)
252 {$IFDEF ENABLE_MENU}
253 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) then
254 {$ELSE}
255 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) then
256 {$ENDIF}
257 begin
258 if i = VK_UP then
259 begin
260 angleFire := True;
261 keyFinger[VK_FIRE] := -1;
262 e_KeyUpDown(VK_FIRE, True);
263 g_Console_ProcessBind(VK_FIRE, True)
264 end
265 else if i = VK_DOWN then
266 begin
267 angleFire := True;
268 keyFinger[VK_FIRE] := -1;
269 e_KeyUpDown(VK_FIRE, True);
270 g_Console_ProcessBind(VK_FIRE, True)
271 end
272 end
273 end;
275 procedure KeyMotion (finger, i: Integer);
276 begin
277 if keyFinger[i] <> finger then
278 begin
279 KeyUp(finger, i);
280 KeyDown(finger, i)
281 end
282 end;
284 begin
285 if not g_touch_enabled then
286 Exit;
288 finger := ev.fingerId + 2;
289 x := Trunc(ev.x * gWinSizeX);
290 y := Trunc(ev.y * gWinSizeY);
292 for i := VK_FIRSTKEY to VK_LASTKEY do
293 begin
294 if IntersectControl(i, x, y) then
295 begin
296 if ev.type_ = SDL_FINGERUP then
297 KeyUp(finger, i)
298 else if ev.type_ = SDL_FINGERMOTION then
299 KeyMotion(finger, i)
300 else if ev.type_ = SDL_FINGERDOWN then
301 keyDown(finger, i)
302 end
303 else if keyFinger[i] = finger then
304 begin
305 if ev.type_ = SDL_FINGERUP then
306 KeyUp(finger, i)
307 else if ev.type_ = SDL_FINGERMOTION then
308 KeyUp(finger, i)
309 end
310 end
311 end;
313 procedure g_Touch_Draw;
314 var i, x, y, w, h: Integer; founded: Boolean;
315 begin
316 {$IFNDEF HEADLESS}
317 if not g_touch_enabled then
318 Exit;
320 for i := VK_FIRSTKEY to VK_LASTKEY do
321 begin
322 GetKeyRect(i, x, y, w, h, founded);
323 if founded then
324 begin
325 e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31);
326 e_TextureFontPrintEx(x, y, GetKeyName(i), gStdFont, 255, 255, 255, 1, True)
327 end
328 end
329 {$ENDIF}
330 end;
332 initialization
333 conRegVar('touch_enable', @g_touch_enabled, 'enable/disable virtual buttons', 'draw buttons');
334 conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down');
335 conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size');
336 conRegVar('touch_offset', @g_touch_offset, 0, 100, '', '');
337 conRegVar('touch_alt', @g_touch_alt, 'althernative virtual buttons layout', 'althernative layout');
338 end.