DEADSOFTWARE

fix chat/console input
[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 = False;
26 g_touch_size: Single = 1.0;
27 g_touch_offset: Single = 50.0;
28 g_touch_fire: Boolean = True;
29 g_touch_alt: Boolean = False;
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_gui, g_weapons, g_console, g_window;
42 var
43 angleFire: Boolean;
44 keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer;
46 procedure GetKeyRect(key: Integer; out x, y, w, h: Integer; out founded: Boolean);
47 var
48 sw, sh, sz: Integer;
49 dpi: Single;
51 procedure S (xx, yy, ww, hh: Single);
52 begin
53 x := Trunc(xx);
54 y := Trunc(yy);
55 w := Trunc(ww);
56 h := Trunc(hh);
57 founded := true;
58 end;
60 begin
61 founded := false;
62 if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
63 dpi := 96;
65 sz := Trunc(g_touch_size * dpi); sw := gScreenWidth; sh := gScreenHeight;
66 x := 0; y := Round(sh * g_touch_offset / 100);
67 w := sz; h := sz;
69 if SDL_IsTextInputActive() = SDL_True then
70 case key of
71 VK_HIDEKBD: S(sw - (sz/2), 0, sz / 2, sz / 2);
72 end
73 else if g_touch_alt then
74 case key of
75 (* top ------- x ------------------------------- y w ----- h -- *)
76 VK_CONSOLE: S(0, 0, sz / 2, sz / 2);
77 VK_ESCAPE: S(sw - 1*(sz/2) - 1, 0, sz / 2, sz / 2);
78 VK_SHOWKBD: S(sw - 2*(sz/2) - 1, 0, sz / 2, sz / 2);
79 VK_CHAT: S(sw / 2 - (sz/2) / 2 - (sz/2) - 1, 0, sz / 2, sz / 2);
80 VK_STATUS: S(sw / 2 - (sz/2) / 2 - 1, 0, sz / 2, sz / 2);
81 VK_TEAM: S(sw / 2 - (sz/2) / 2 + (sz/2) - 1, 0, sz / 2, sz / 2);
82 (* left --- x - y -------------- w - h --- *)
83 VK_PREV: S(0, sh - 3.0*sz - 1, sz, sz / 2);
84 VK_LEFT: S(0, sh - 2.0*sz - 1, sz, sz * 2);
85 VK_RIGHT: S(sz, sh - 2.0*sz - 1, sz, sz * 2);
86 (* right - x ------------ y -------------- w - h -- *)
87 VK_NEXT: S(sw - 1*sz - 1, sh - 3.0*sz - 1, sz, sz / 2);
88 VK_UP: S(sw - 2*sz - 1, sh - 2.0*sz - 1, sz, sz / 2);
89 VK_FIRE: S(sw - 2*sz - 1, sh - 1.5*sz - 1, sz, sz);
90 VK_DOWN: S(sw - 2*sz - 1, sh - 0.5*sz - 1, sz, sz / 2);
91 VK_JUMP: S(sw - 1*sz - 1, sh - 2.0*sz - 1, sz, sz);
92 VK_OPEN: S(sw - 1*sz - 1, sh - 1.0*sz - 1, sz, sz);
93 end
94 else
95 case key of
96 (* left ----- x ----- y -------------- w ----- h -- *)
97 VK_ESCAPE: S(0.0*sz, y - 1*sz - sz/2, sz, sz / 2);
98 VK_LSTRAFE: S(0.0*sz, y - 0*sz - sz/2, sz / 2, sz);
99 VK_LEFT: S(0.5*sz, y - 0*sz - sz/2, sz, sz);
100 VK_RIGHT: S(1.5*sz, y - 0*sz - sz/2, sz, sz);
101 VK_RSTRAFE: S(2.5*sz, y - 0*sz - sz/2, sz / 2, sz);
102 (* right - x ------------ y --------------- w - h *)
103 VK_UP: S(sw - 1*sz - 1, y - 1*sz - sz/2, sz, sz);
104 VK_FIRE: S(sw - 1*sz - 1, y - 0*sz - sz/2, sz, sz);
105 VK_DOWN: S(sw - 1*sz - 1, y - -1*sz - sz/2, sz, sz);
106 VK_NEXT: S(sw - 2*sz - 1, y - 1*sz - sz/2, sz, sz);
107 VK_JUMP: S(sw - 2*sz - 1, y - 0*sz - sz/2, sz, sz);
108 VK_PREV: S(sw - 3*sz - 1, y - 1*sz - sz/2, sz, sz);
109 VK_OPEN: S(sw - 3*sz - 1, y - 0*sz - sz/2, sz, sz);
110 (* bottom ---- x -------------------------- y ---------------- w ----- h -- *)
111 VK_CHAT: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
112 VK_CONSOLE: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
113 VK_STATUS: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
114 VK_TEAM: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
115 VK_SHOWKBD: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
116 VK_0: S(sw/2 - sz/4 - 5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
117 VK_1: S(sw/2 - sz/4 - 4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
118 VK_2: S(sw/2 - sz/4 - 3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
119 VK_3: S(sw/2 - sz/4 - 2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
120 VK_4: S(sw/2 - sz/4 - 1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
121 VK_5: S(sw/2 - sz/4 - 0*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
122 VK_6: S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
123 VK_7: S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
124 VK_8: S(sw/2 - sz/4 - -3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
125 VK_9: S(sw/2 - sz/4 - -4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
126 VK_A: S(sw/2 - sz/4 - -5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
127 end
128 end;
130 function GetKeyName(key: Integer): String;
131 begin
132 case key of
133 VK_SHOWKBD: result := 'KBD';
134 VK_HIDEKBD: result := 'KBD';
135 VK_LEFT: result := 'LEFT';
136 VK_RIGHT: result := 'RIGHT';
137 VK_UP: result := 'UP';
138 VK_DOWN: result := 'DOWN';
139 VK_FIRE: result := 'FIRE';
140 VK_OPEN: result := 'OPEN';
141 VK_JUMP: result := 'JUMP';
142 VK_CHAT: result := 'CHAT';
143 VK_ESCAPE: result := 'ESC';
144 VK_0: result := '0';
145 VK_1: result := '1';
146 VK_2: result := '2';
147 VK_3: result := '3';
148 VK_4: result := '4';
149 VK_5: result := '5';
150 VK_6: result := '6';
151 VK_7: result := '7';
152 VK_8: result := '8';
153 VK_9: result := '9';
154 VK_A: result := '10';
155 VK_B: result := '11';
156 VK_C: result := '12';
157 VK_D: result := '13';
158 VK_E: result := '14';
159 VK_F: result := '15';
160 VK_CONSOLE: result := 'CON';
161 VK_STATUS: result := 'STAT';
162 VK_TEAM: result := 'TEAM';
163 VK_PREV: result := '<PREW';
164 VK_NEXT: result := 'NEXT>';
165 VK_LSTRAFE: result := '<';
166 VK_RSTRAFE: result := '>';
167 else
168 if (key > 0) and (key < e_MaxInputKeys) then
169 result := e_KeyNames[key]
170 else
171 result := '<' + IntToStr(key) + '>'
172 end
173 end;
175 function IntersectControl(ctl, xx, yy: Integer): Boolean;
176 var
177 x, y, w, h: Integer;
178 founded: Boolean;
179 begin
180 GetKeyRect(ctl, x, y, w, h, founded);
181 result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h);
182 end;
184 procedure g_Touch_Init;
185 begin
186 {$IFNDEF HEADLESS}
187 g_Touch_ShowKeyboard(FALSE);
188 g_touch_enabled := SDL_GetNumTouchDevices() > 0
189 {$ENDIF}
190 end;
192 procedure g_Touch_ShowKeyboard(yes: Boolean);
193 begin
194 {$IFNDEF HEADLESS}
195 if g_dbg_input then
196 e_LogWritefln('g_Touch_ShowKeyboard(%s)', [yes]);
197 (* on desktop we always receive text (needed for cheats) *)
198 if yes or (SDL_HasScreenKeyboardSupport() = SDL_FALSE) then
199 SDL_StartTextInput
200 else
201 SDL_StopTextInput
202 {$ENDIF}
203 end;
205 procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
206 var
207 x, y, i, finger: Integer;
209 procedure KeyUp (finger, i: Integer);
210 begin
211 if g_dbg_input then
212 e_LogWritefln('Input Debug: g_touch.KeyUp, finger=%s, key=%s', [finger, i]);
214 keyFinger[i] := 0;
215 e_KeyUpDown(i, False);
216 g_Console_ProcessBind(i, False);
218 (* up/down + fire hack *)
219 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) and angleFire then
220 begin
221 if (i = VK_UP) or (i = VK_DOWN) then
222 begin
223 angleFire := False;
224 keyFinger[VK_FIRE] := 0;
225 e_KeyUpDown(VK_FIRE, False);
226 g_Console_ProcessBind(VK_FIRE, False)
227 end
228 end
229 end;
231 procedure KeyDown (finger, i: Integer);
232 begin
233 if g_dbg_input then
234 e_LogWritefln('Input Debug: g_touch.KeyDown, finger=%s, key=%s', [finger, i]);
236 keyFinger[i] := finger;
237 e_KeyUpDown(i, True);
238 g_Console_ProcessBind(i, True);
240 (* up/down + fire hack *)
241 if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) then
242 begin
243 if i = VK_UP then
244 begin
245 angleFire := True;
246 keyFinger[VK_FIRE] := -1;
247 e_KeyUpDown(VK_FIRE, True);
248 g_Console_ProcessBind(VK_FIRE, True)
249 end
250 else if i = VK_DOWN then
251 begin
252 angleFire := True;
253 keyFinger[VK_FIRE] := -1;
254 e_KeyUpDown(VK_FIRE, True);
255 g_Console_ProcessBind(VK_FIRE, True)
256 end
257 end
258 end;
260 procedure KeyMotion (finger, i: Integer);
261 begin
262 if keyFinger[i] <> finger then
263 begin
264 KeyUp(finger, i);
265 KeyDown(finger, i)
266 end
267 end;
269 begin
270 if not g_touch_enabled then
271 Exit;
273 finger := ev.fingerId + 2;
274 x := Trunc(ev.x * gScreenWidth);
275 y := Trunc(ev.y * gScreenHeight);
277 for i := VK_FIRSTKEY to VK_LASTKEY do
278 begin
279 if IntersectControl(i, x, y) then
280 begin
281 if ev.type_ = SDL_FINGERUP then
282 KeyUp(finger, i)
283 else if ev.type_ = SDL_FINGERMOTION then
284 KeyMotion(finger, i)
285 else if ev.type_ = SDL_FINGERDOWN then
286 keyDown(finger, i)
287 end
288 else if keyFinger[i] = finger then
289 begin
290 if ev.type_ = SDL_FINGERUP then
291 KeyUp(finger, i)
292 else if ev.type_ = SDL_FINGERMOTION then
293 KeyUp(finger, i)
294 end
295 end
296 end;
298 procedure g_Touch_Draw;
299 var i, x, y, w, h: Integer; founded: Boolean;
300 begin
301 {$IFNDEF HEADLESS}
302 if not g_touch_enabled then
303 Exit;
305 for i := VK_FIRSTKEY to VK_LASTKEY do
306 begin
307 GetKeyRect(i, x, y, w, h, founded);
308 if founded then
309 begin
310 e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31);
311 e_TextureFontPrintEx(x, y, GetKeyName(i), gStdFont, 255, 255, 255, 1, True)
312 end
313 end
314 {$ENDIF}
315 end;
317 initialization
318 conRegVar('touch_enable', @g_touch_enabled, 'enable/disable virtual buttons', 'draw buttons');
319 conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down');
320 conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size');
321 conRegVar('touch_offset', @g_touch_offset, 0, 100, '', '');
322 conRegVar('touch_alt', @g_touch_alt, 'althernative virtual buttons layout', 'althernative layout');
323 end.