ページ

2021年2月22日月曜日

Linux でGUI を自動操作するツール【自作】

GUI の自動ツールとしては,xdotool などが有名だが,そういったツールを使用できない場合は自作するのもひとつの手段.

マウスポインターを指定した座標に動かして,クリックするだけのプログラムならば,数行のコードで実現できる.

click.c
--------------------------------------------------------------------------------
#include <stdlib.h>
#include <X11/extensions/XTest.h>

int main ( int argc, char ** argv )
{
  // Arguments 1 is Point of X, Argument 2 is Point of Y
  int position[2] = {atoi ( argv[1] ), atoi ( argv[2] ) };

  // Open Default Display
  Display * display = XOpenDisplay ( NULL );

  if ( display != NULL )
  {
    // Open 'Virtual core XTEST pointer'
    XDevice * device = XOpenDevice ( display, 4 );

    if ( device != NULL )
    {
      // Move Poitner
      XTestFakeDeviceMotionEvent ( display, device, False, 0, position, 2, 0 );

      // Press & Release Left Button
      XTestFakeDeviceButtonEvent ( display, device, Button1, True, NULL, 0, 0 );
      XTestFakeDeviceButtonEvent ( display, device, Button1, False, NULL, 0, 0 );

      XCloseDevice ( display, device );
    }

    XCloseDisplay ( display );
  }

  return 0;
}


 $ gcc -lX11 -lXi -lXtst click.c -o click
 $ ./click 100 500


DISPLAYや,デバイスIDを引数で指定できるようにすると,こんな感じ.
click2.c
--------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <X11/extensions/XTest.h>

struct Arguments
{
  char * DisplayName;
  XID DeviceID;
  int Position[2];
};

int getOptions ( int, char **, struct Arguments * );

int main ( int argc, char ** argv )
{
  struct Arguments args;
  args.DisplayName = NULL;
  args.DeviceID = 4;
  args.Position[0] = 0;
  args.Position[1] = 0;

  if ( getOptions ( argc, argv, &args ) != 0 )
  {
    return 1;
  }

  Display * display = XOpenDisplay ( args.DisplayName );

  if ( display != NULL )
  {
    XDevice * device = XOpenDevice ( display, args.DeviceID );

    if ( device != NULL )
    {
      // Move Poitner
      XTestFakeDeviceMotionEvent ( display, device, False, 0, args.Position, 2, 0 );

      // Press & Release Left Button
      XTestFakeDeviceButtonEvent ( display, device, Button1, True, NULL, 0, 0 );
      XTestFakeDeviceButtonEvent ( display, device, Button1, False, NULL, 0, 0 );

      XCloseDevice ( display, device );
    }

    XCloseDisplay ( display );
  }

  return 0;
}

int getOptions ( int argc, char ** argv, struct Arguments * args )
{
  for ( int i = 0; i < argc; i++ )
  {
    int option = getopt ( argc, argv, "d:i:" );

    if ( option == -1 )
    {
      break;
    }

    switch ( option )
    {
      case 'd':
        memcpy ( & ( args->DisplayName ), &optarg, sizeof ( optarg ) );
        break;

      case 'i':
        args->DeviceID = atoi ( optarg );
        break;

      default:
        puts ( "Option Error!" );
        return -1;
    }
  }

  if ( argc < optind + 2 )
  {
    puts ( "Too few arguments" );
    return -1;
  }

  for ( int i = 0; i < 2; i++ )
  {
    args->Position[i] = atoi ( argv[i + optind] );
  }

  if ( args->DisplayName != NULL )
  {
    printf ( "Display Name : %s\n", args->DisplayName );
  }

  printf ( "Device ID : %d\n", ( int ) args->DeviceID );
  printf ( "Position : %d, %d\n", args->Position[0], args->Position[1] );

  return 0;
}


DISPLAYは-dオプションで指定,デバイスIDは-iオプションで指定する.
 $ gcc -lX11 -lXi -lXtst click2.c -o click2
 $ ./click2 -d localhost:0.0 -i 4 100 500
 Display Name : localhost:0.0
 Device ID : 4
 Position : 400, 500

0 件のコメント:

コメントを投稿