(* Copyright (C) Doom 2D: Forever Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} unit g_touch; interface uses SDL2; var g_touch_enabled: Boolean; g_touch_size: Single; g_touch_offset: Single; g_touch_fire: Boolean; g_touch_alt: Boolean; procedure g_Touch_Init; procedure g_Touch_ShowKeyboard(yes: Boolean); procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent); procedure g_Touch_Draw; implementation uses SysUtils, e_log, e_graphics, e_input, g_options, g_game, g_main, g_weapons, g_console; const VS_KEYBOARD = 60000; var angleFire: Boolean; keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer; procedure GetKeyRect(key: Integer; out x, y, w, h: Integer; out founded: Boolean); var sw, sh, sz: Integer; dpi: Single; begin if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then dpi := 96; founded := true; sz := Trunc(g_touch_size * dpi); sw := gScreenWidth; sh := gScreenHeight; if g_touch_alt then begin w := sz div 2; h := sz div 2; case key of VK_CONSOLE: begin x := 0; y := 0 end; VK_ESCAPE: begin x := sw - 1*w - 1; y := 0 end; VS_KEYBOARD:begin x := sw - 2*w - 1; y := 0 end; VK_CHAT: begin x := sw div 2 - w div 2 - w; y := 0 end; VK_STATUS: begin x := sw div 2 - w div 2 + 0; y := 0 end; VK_TEAM: begin x := sw div 2 - w div 2 + w; y := 0 end; VK_PREV: begin x := 0; y := sh - 4*sz - 1; w := sz end; VK_NEXT: begin x := sw - sz - 1; y := sh - 4*sz - 1; w := sz end; else w := sz; h := sz * 3; case key of VK_LEFT: begin x := 0; y := sh - h - 1 end; VK_RIGHT: begin x := w; y := sh - h - 1 end; else w := sz; h := sz; case key of VK_UP: begin x := sw - 2*w - 1; y := sh - 3*h - 1 end; VK_FIRE: begin x := sw - 2*w - 1; y := sh - 2*h - 1 end; VK_DOWN: begin x := sw - 2*w - 1; y := sh - 1*h - 1 end; VK_OPEN: begin x := sw - 1*w - 1; y := sh - 1*h - h div 2 - 1 end; VK_JUMP: begin x := sw - 1*w - 1; y := sh - 2*h - h div 2 - 1 end; else founded := false end end end end else begin x := 0; y := Round(sh * g_touch_offset / 100); w := sz; h := sz; case key of VK_ESCAPE: begin x := 0; y := y - 3*h div 2; w := w; h := h div 2 end; VK_LSTRAFE: begin x := 0; y := y - h div 2; w := w div 2 end; VK_LEFT: begin x := w div 2; y := y - h div 2 end; VK_RIGHT: begin x := w div 2 + 1*w; y := y - h div 2 end; VK_RSTRAFE: begin x := w div 2 + 2*w; y := y - h div 2; w := w div 2 end; VK_UP: begin x := sw - w - 1; y := y - h div 2 - h end; VK_FIRE: begin x := sw - 1*w - 1; y := y - h div 2 end; VK_DOWN: begin x := sw - w - 1; y := y - h div 2 + h end; VK_NEXT: begin x := sw - 2*w - 1; y := y - h div 2 - h end; VK_JUMP: begin x := sw - 2*w - 1; y := y - h div 2 end; VK_PREV: begin x := sw - 3*w - 1; y := y - h div 2 - h end; VK_OPEN: begin x := sw - 3*w - 1; y := y - h div 2 end; else x := 0; y := 0; w := sz div 2; h := sz div 2; case key of VK_0: begin x := sw div 2 - w div 2 - 5*w - 1; y := sh - 1*h - 1 end; VK_1: begin x := sw div 2 - w div 2 - 4*w - 1; y := sh - 1*h - 1 end; VK_2: begin x := sw div 2 - w div 2 - 3*w - 1; y := sh - 1*h - 1 end; VK_3: begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 1*h - 1 end; VK_4: begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 1*h - 1 end; VK_5: begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 1*h - 1 end; VK_6: begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 1*h - 1 end; VK_7: begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 1*h - 1 end; VK_8: begin x := sw div 2 - w div 2 + 3*w - 1; y := sh - 1*h - 1 end; VK_9: begin x := sw div 2 - w div 2 + 4*w - 1; y := sh - 1*h - 1 end; VK_A: begin x := sw div 2 - w div 2 + 5*w - 1; y := sh - 1*h - 1 end; VK_CHAT: begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 2*h - 1 end; VK_CONSOLE: begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 2*h - 1 end; VK_STATUS: begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 2*h - 1 end; VK_TEAM: begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 2*h - 1 end; VS_KEYBOARD:begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 2*h - 1 end; else founded := false end end end end; function GetKeyName(key: Integer): String; begin case key of VS_KEYBOARD: result := 'KBD'; VK_LEFT: result := 'LEFT'; VK_RIGHT: result := 'RIGHT'; VK_UP: result := 'UP'; VK_DOWN: result := 'DOWN'; VK_FIRE: result := 'FIRE'; VK_OPEN: result := 'OPEN'; VK_JUMP: result := 'JUMP'; VK_CHAT: result := 'CHAT'; VK_ESCAPE: result := 'ESC'; VK_0: result := '0'; VK_1: result := '1'; VK_2: result := '2'; VK_3: result := '3'; VK_4: result := '4'; VK_5: result := '5'; VK_6: result := '6'; VK_7: result := '7'; VK_8: result := '8'; VK_9: result := '9'; VK_A: result := '10'; VK_B: result := '11'; VK_C: result := '12'; VK_D: result := '13'; VK_E: result := '14'; VK_F: result := '15'; VK_CONSOLE: result := 'CON'; VK_STATUS: result := 'STAT'; VK_TEAM: result := 'TEAM'; VK_PREV: result := ' 0) and (key < e_MaxInputKeys) then result := e_KeyNames[key] else result := '<' + IntToStr(key) + '>' end end; function IntersectControl(ctl, xx, yy: Integer): Boolean; var x, y, w, h: Integer; founded: Boolean; begin GetKeyRect(ctl, x, y, w, h, founded); result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h); end; procedure g_Touch_Init; begin {$IFNDEF HEADLESS} g_touch_enabled := SDL_GetNumTouchDevices() > 0 {$ENDIF} end; procedure g_Touch_ShowKeyboard(yes: Boolean); begin {$IFNDEF HEADLESS} if not g_touch_enabled then Exit; if yes then SDL_StartTextInput else SDL_StopTextInput {$ENDIF} end; procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent); var x, y, i, finger: Integer; begin if not g_touch_enabled then Exit; if SDL_IsTextInputActive() = SDL_True then Exit; finger := ev.fingerId + 2; x := Trunc(ev.x * gScreenWidth); y := Trunc(ev.y * gScreenHeight); for i := VK_FIRSTKEY to VK_LASTKEY do begin if IntersectControl(i, x, y) then begin if ev.type_ = SDL_FINGERUP then keyFinger[i] := 0 else if ev.type_ = SDL_FINGERMOTION then keyFinger[i] := finger else if ev.type_ = SDL_FINGERDOWN then begin KeyPress(i); // Menu events keyFinger[i] := finger; end end else if keyFinger[i] = finger then begin if ev.type_ = SDL_FINGERUP then keyFinger[i] := 0 else if ev.type_ = SDL_FINGERMOTION then keyFinger[i] := 0 end; e_KeyUpDown(i, keyFinger[i] <> 0); end; if IntersectControl(VS_KEYBOARD, x, y) then g_Touch_ShowKeyboard(true); (* emulate up+fire / donw+fire *) if g_touch_fire and (gGameSettings.GameType <> GT_NONE) then begin if keyFinger[VK_UP] <> 0 then begin angleFire := true; keyFinger[VK_FIRE] := keyFinger[VK_UP]; e_KeyUpDown(VK_FIRE, true); end else if keyFinger[VK_DOWN] <> 0 then begin angleFire := true; keyFinger[VK_FIRE] := keyFinger[VK_DOWN]; e_KeyUpDown(VK_FIRE, true); end else if angleFire then begin angleFire := false; keyFinger[VK_FIRE] := 0; e_KeyUpDown(VK_FIRE, false); end end; (* left/right strafe *) if gGameSettings.GameType <> GT_NONE then begin if keyFinger[VK_LSTRAFE] <> 0 then begin keyFinger[VK_LEFT] := finger; keyFinger[VK_RIGHT] := 0; keyFinger[VK_STRAFE] := finger; e_KeyUpDown(VK_LEFT, true); e_KeyUpDown(VK_RIGHT, false); e_KeyUpDown(VK_STRAFE, true); end else if keyFinger[VK_RSTRAFE] <> 0 then begin keyFinger[VK_LEFT] := 0; keyFinger[VK_RIGHT] := finger; keyFinger[VK_STRAFE] := finger; e_KeyUpDown(VK_LEFT, false); e_KeyUpDown(VK_RIGHT, true); e_KeyUpDown(VK_STRAFE, true); end else begin keyFinger[VK_STRAFE] := 0; e_KeyUpDown(VK_STRAFE, false); end end; end; procedure g_Touch_Draw; var i: Integer; procedure Draw (i: Integer); var x, y, w, h: Integer; founded: Boolean; begin GetKeyRect(i, x, y, w, h, founded); if founded then begin e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31); e_TextureFontPrintEx(x, y, GetKeyName(i), gStdFont, 255, 255, 255, 1, True) end; end; begin {$IFNDEF HEADLESS} if not g_touch_enabled then Exit; if SDL_IsTextInputActive() = SDL_True then Exit; for i := VK_FIRSTKEY to VK_LASTKEY do Draw(i); Draw(VS_KEYBOARD); {$ENDIF} end; initialization conRegVar('touch_enable', @g_touch_enabled, 'enable/disable virtual buttons', 'draw buttons'); conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down'); conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size'); conRegVar('touch_offset', @g_touch_offset, 0, 100, '', ''); conRegVar('touch_alt', @g_touch_alt, 'althernative virtual buttons layout', 'althernative layout'); end.