DEADSOFTWARE

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