{$mode objfpc}{$H+}

{
    Send Enter key to pointed by mouse window.
    For GNU/Linux 64 bit version.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    Used https://chat.deepseek.com/
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

uses X, XLib, XKBlib, XUtil,KeySym;

// Добавляем объявления функций из XTest
function XTestFakeKeyEvent(display: PDisplay; keycode: Cardinal; is_press: Boolean; delay: Cardinal): Integer; cdecl; external 'Xtst';
function XTestFakeButtonEvent(display: PDisplay; button: Cardinal; is_press: Boolean; delay: Cardinal): Integer; cdecl; external 'Xtst';
function XTestGrabControl(display: PDisplay; impervious: Boolean): Integer; cdecl; external 'Xtst';

var
  d: PDisplay;
  root: TWindow;
  win: TWindow;
  root_x, root_y, win_x, win_y: Integer;
  mask: Cardinal;
  keycode: Word;
  event: TXEvent;

begin
  // Открываем соединение с X-сервером
  d := XOpenDisplay(nil);
  if d = nil then
  begin
    Writeln('Не удалось подключиться к X-серверу');
    Halt(1);
  end;

  try
    // Инициализируем XTest
    XTestGrabControl(d, True);

    root := XDefaultRootWindow(d);
    Writeln('Нажмите на окно, куда нужно отправить Enter...');

    // Получаем окно под курсором мыши
    XGrabPointer(d, root, False, ButtonPressMask, GrabModeAsync, 
                GrabModeAsync, None, None, CurrentTime);
    
    // Ждём клика мышью
    XSelectInput(d, root, ButtonPressMask);
    while True do
    begin
      XNextEvent(d, @event);
      
      if event._type = ButtonPress then
      begin
        win := event.xbutton.subwindow;
        if win = None then
          win := root;
        
        // Получаем координаты для проверки
        XQueryPointer(d, win, @root, @win, @root_x, @root_y, @win_x, @win_y, @mask);
        Break;
      end;
    end;
    
    XUngrabPointer(d, CurrentTime);

    if win = None then
    begin
      Writeln('Окно не выбрано');
      Halt(1);
    end;

    Writeln('Отправляем Enter в окно ', win);
    
    // Получаем keycode для Enter
    keycode := XKeysymToKeycode(d, XK_Return);

    // Фокусируемся на окне
    XSetInputFocus(d, win, RevertToParent, CurrentTime);
    XFlush(d);
    
    // Имитируем нажатие Enter
    XTestFakeKeyEvent(d, keycode, True, 0);   // KeyPress
    XFlush(d);
    XTestFakeKeyEvent(d, keycode, False, 0);  // KeyRelease
    XFlush(d);
    
    Writeln('Enter отправлен!');
    
  finally
    XCloseDisplay(d);
  end;
end.