Форум русскоязычного сообщества Ubuntu


Следите за новостями русскоязычного сообщества Ubuntu в Twitter-ленте @ubuntu_ru_loco

Автор Тема: Имитация нажатия клавиши  (Прочитано 11186 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Peter_I

  • Автор темы
  • Старожил
  • *
  • Сообщений: 3026
    • Просмотр профиля
Имитация нажатия клавиши
« : 12 Января 2016, 09:38:01 »
Здравствуйте!

Как средствами самой системы, без всяких сред типа ncurses или Qt, симитировать нажатие клавиши клавиатуры?
Как-то послать системе event, или через какую-нибудь ioctl?
Т.е. какие надо применять для этого средства и где это описано?
Пётр.

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6017
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #1 : 12 Января 2016, 12:08:41 »
Знаю xdotool, а вот системными средствами…
В Линукс можно сделать ВСЁ что угодно, достаточно знать КАК !

shura1

  • Гость
Re: Имитация нажатия клавиши
« Ответ #2 : 12 Января 2016, 13:02:53 »
На каком уровне системы? На уровне ядра, на уровне Х, на уровне DE? Тут же клавиша, пока до приложения доберется через с три-четыре уровня пройдет.

Подозреваю, что что-то типа xbindkeys нужно.

Оффлайн Peter_I

  • Автор темы
  • Старожил
  • *
  • Сообщений: 3026
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #3 : 12 Января 2016, 13:09:11 »
Благодарю за варианты, а я имел в виду на уровне ядра или с помоьщю каких-нибудь системных вызовов, без X-ов.
Пётр.

shura1

  • Гость
Re: Имитация нажатия клавиши
« Ответ #4 : 12 Января 2016, 13:33:06 »
На уровне ядра? Наверное вот, что надо

https://github.com/tuomasjjrasanen/python-uinput

Ну или то же самое на уровне С

http://thiemonge.org/getting-started-with-uinput

(То есть простого решения, по-видимому, нет).

Оффлайн Peter_I

  • Автор темы
  • Старожил
  • *
  • Сообщений: 3026
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #5 : 12 Января 2016, 15:00:48 »
Благодарю, посмотрю.
Многие ссылки тоже рекомендуют xdotool. Ещё есть программа xvkbd, я ещё уже попробовал, она входит в Ubuntu:
Ещё есть crikey, но её не пробовал:
http://www.shallowsky.com/software/crikey/
Вот ещё ссылки, по одной из них много других.
www.linuxjournal.com/article/1080?page=0
www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html
sohu.io/questions/5455069/how-to-simulate-a-unicode-key-press-under-linux
tolinked.com/questions/467930/simulate-keypress-in-a-linux-c-console-application
« Последнее редактирование: 23 Января 2016, 12:02:34 от Peter_I »
Пётр.

Оффлайн Cxms

  • Активист
  • *
  • Сообщений: 407
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #6 : 23 Января 2016, 00:32:33 »
Почему xdotool не печатает слеш?
xdotool type "/path/to/file"выдает:
|path|to|file

adawdp

  • Гость
Re: Имитация нажатия клавиши
« Ответ #7 : 23 Января 2016, 01:51:23 »
2016 Jan 22; 05:50 PM; Oakville, ON, Canada.

— Я пробовал и xdotool и xvkbd, почему-то xdotool лучше и вроде проще. Но иногда нужно добавить sleep… Не успевает срабатывать что-то…
Код: (bash) [Выделить]
xdotool key Ctrl+Alt+t; sleep 0.2s; xdotool click 1— В этом примере из терминала откроет ещё один терминал сделает окно активным и сразу к примеру можно вставить из буфера какую-то команду. (Просто для примера).
— Использую во многих скриптах работает безотказно.
— Команды типа:
Код: (bash) [Выделить]

xdotool key KP_Enter              # ну это ввод…
xdotool key Shift+Insert          # ну это тоже что Ctrl+v…
— Окнам с её помощью можно задать размер, кнопки мыши нажимать, окна по экрану расставить и менять местами и так далее.
 

Пользователь решил продолжить мысль 23 Января 2016, 02:19:45:
2016 Jan 22; 06:19 PM

— Да, Cxms, действительно и у меня тоже так :(… Я ещё раньше это когда-то заметил, подумал что это что-то у меня неправильно с программами или системой…
« Последнее редактирование: 23 Января 2016, 02:19:46 от adawdp »

Оффлайн Cxms

  • Активист
  • *
  • Сообщений: 407
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #8 : 23 Января 2016, 02:23:58 »
adawdp,
Да это все понятно,
(Нажмите, чтобы показать/скрыть)
я не пойму только как заставить его печатать слеш,
перепробывал по разному, но все равно пишет "|" вместо "/".

adawdp

  • Гость
Re: Имитация нажатия клавиши
« Ответ #9 : 23 Января 2016, 03:47:30 »
Cxms, на англоязычных ресурсах часто пишется что это bug : “Xdotool type slash problem or bug”, — если покороче спросить, но объяснения пока не нашёл, что-то всё коды клавишей приводят…
 

Оффлайн Cxms

  • Активист
  • *
  • Сообщений: 407
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #10 : 23 Января 2016, 04:37:44 »
Спасибо, но странно это, слеш ведь используется для путей, и это не исправили...
А код слеша - 2f
echo -e "\x2f"-> /
xdotool type "$(echo -e "\x2f")"-> |
все таже, НО если изменить расладку на русскую, то слеш печатается! но все буквы русские:
xdotool type "/path/to/file"-> /зфер/ещ/ашду
« Последнее редактирование: 23 Января 2016, 04:39:24 от Cxms »

Оффлайн Peter_I

  • Автор темы
  • Старожил
  • *
  • Сообщений: 3026
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #11 : 23 Января 2016, 12:00:53 »
Я потом нашёл два варианта, один через Xlib, другой через ядро с помощью ioctl.
Сейчас посмотрел, в обоих случаях "/" есть, с Xlib это XK_slash,
через ioctl это KEY_SLASH.
Вот вариант с Xlib, он периодически посылает Enter и сделан демоном.
В Ubuntu <sys/param.h> подключает <signal.h> и его можно закомментировать.
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
//#include <sys/types.h>
#include <signal.h>

int main(int argc,char **argv){

int fd,n=256;
pid_t id;
struct rlimit flim;
  if(argc>1)n=atoi(argv[1]);
  if (getppid() != 1){ signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);
  signal(SIGTSTP,SIG_IGN); id=fork(); if(id != 0){ fprintf(stdout,
  "daemon is running, %d %d\n",(int)id,n);fflush(stdout);exit(0);} setsid();}
  getrlimit(RLIMIT_NOFILE,&flim); for(fd=0;fd<flim.rlim_max;fd++)close(fd);
  fd=chdir("/");
  if(fd != 0){ fprintf(stdout,"We a not in \"/\"!,%d\n",fd);fflush(stdout);}
Display *display;
unsigned int keycode;
display = XOpenDisplay(NULL);
keycode = XKeysymToKeycode(display, XK_Return);
  while(1){
XTestFakeKeyEvent(display, keycode, True, 0);
XTestFakeKeyEvent(display, keycode, False, 0);
  sleep(n);
XFlush(display);
  }
  XCloseDisplay(display);
  return 0;
}
Вот вариант с ioctl, он делает то же самое.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pos_gnu.h>
#include <signal.h>
void print_errno(int,FILE *);

//KEY_SPACE instead of KEY_ENTER !!!

int main(int argc,char **argv){
int n=256,nr,fd;
pid_t id;
struct uinput_user_dev uidev;
struct input_event ev;
struct rlimit flim;
FILE *fout;

  if(argc>1)n=atoi(argv[1]);
  if (getppid() != 1){ signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);
  signal(SIGTSTP,SIG_IGN); id=fork(); if(id != 0){ fprintf(stdout,
  "daemon is running, %d %d\n",(int)id,n);fflush(stdout);exit(0);} setsid();}
  getrlimit(RLIMIT_NOFILE,&flim); for(fd=0;fd<flim.rlim_max;fd++)close(fd);
  nr=chdir("/"); fout=fopen("/home/operator0/uinput_daemon_cr_out","w");
  if(nr != 0){ fprintf(fout,"We a not in \"/\"!,%d\n",nr);fflush(fout);}

  fd=open("/dev/uinput", O_WRONLY | O_NONBLOCK);if(fd<0)print_errno(errno,fout);
  fprintf(fout,"period=%d fd=%d\n",n,fd);fflush(fout);
  nr=ioctl(fd, UI_SET_EVBIT, EV_KEY);if(nr<0)print_errno(errno,fout);
  nr=ioctl(fd, UI_SET_EVBIT, EV_SYN);if(nr<0)print_errno(errno,fout);
//  nr=ioctl(fd, UI_SET_KEYBIT, KEY_D);if(nr<0)print_errno(errno,fout);
  nr=ioctl(fd, UI_SET_KEYBIT, KEY_ENTER);if(nr<0)print_errno(errno,fout);

  memset(&uidev, 0, sizeof(uidev));
  snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput_cr");
  uidev.id.bustype = BUS_USB;
  uidev.id.vendor  = 0x1; uidev.id.product = 0x1; uidev.id.version = 1;

  nr=write(fd, &uidev, sizeof(uidev));if(nr<0)print_errno(errno,fout);
  nr=ioctl(fd, UI_DEV_CREATE);if(nr<0)print_errno(errno,fout);

while(1) {
/*
  memset(&ev, 0, sizeof(struct input_event));
  ev.type = EV_KEY; ev.code = KEY_D; ev.value = 1;
  nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
  memset(&ev, 0, sizeof(struct input_event));
  ev.type = EV_KEY; ev.code = KEY_D; ev.value = 0;
  nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
*/

  memset(&ev, 0, sizeof(struct input_event));
  ev.type = EV_KEY; ev.code = KEY_ENTER; ev.value = 1;
  nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);

  memset(&ev, 0, sizeof(struct input_event));
  ev.type = EV_KEY; ev.code = KEY_ENTER; ev.value = 0;
  nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);

  memset(&ev, 0, sizeof(struct input_event));
  ev.type = EV_SYN; ev.code = 0; ev.value = 0;
  nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
  sleep(n);
}
  sleep(2);

  nr=ioctl(fd, UI_DEV_DESTROY);if(nr<0)print_errno(errno,fout);
  close(fd);fclose(fout);
  return 0;
}

void print_errno(int ne,FILE *f){
int n;
char buf[160];
#if ispos
  n=strerror_r(ne,buf+80,80);strcpy(buf,buf+80);
#else
  strcpy(buf,strerror_r(ne,buf+80,80));
#endif
  fprintf(f,"%d %s\n",ne,buf);fflush(f);
}
pos_gnu.h - это мой файл, он у меня в /usr/local/include:
#ifndef POS_GNU_H
#define POS_GNU_H 1

#ifndef _POSIX_C_SOURCE
#define isnp 0
#else
# if ( _POSIX_C_SOURCE >= 200112L )
#define isnp 1
#endif
#endif

#ifndef _XOPEN_SOURCE
#define isnx 0
#else
# if ( _XOPEN_SOURCE >= 600 )
#define isnx 1
#endif
#endif

#ifdef _GNU_SOURCE
#define isng 1
#else
#define isng 0
#endif

#if ( ( isnp || isnx ) && ! isng )
#define ispos 1
#else
#define ispos 0
#endif

#endif
Пример с ioctl взят отсюда:
http://thiemonge.org/getting-started-with-uinputмне эту ссылку приводили здесь выше.
« Последнее редактирование: 23 Января 2016, 12:39:36 от Peter_I »
Пётр.

Оффлайн Cxms

  • Активист
  • *
  • Сообщений: 407
    • Просмотр профиля
Re: Имитация нажатия клавиши
« Ответ #12 : 23 Января 2016, 18:21:39 »
ну хоть xvkbd печатает:)
xvkbd -text "/path/to/file" &>/dev/null
Cделал чтобы в открывшемся терминале (по вызову из файл-менеджера) напечаталась строка запуска скрипта, но без выполнения.
FILE="/path/to/script_file.sh"; ( xdotool key --clearmodifiers Ctrl+Alt+t; sleep 2; ACT_WINDOW=$(xdotool getactivewindow); xvkbd -window $ACT_WINDOW -text "bash \"$FILE\"" ) &>/dev/null

adawdp

  • Гость
Re: Имитация нажатия клавиши
« Ответ #13 : 23 Января 2016, 21:10:46 »
2016 Jan 23; 01:10 PM; Oakville, ON, Canada.

— А я вот такое сочинил, (специалистам смотреть в розовых очках :)), Вы, Cxms, кстати мне дважды дельно подсказали, за что спасибо, естественно!!!
Код: (bash) [Выделить]

pkill -15 diodon; xsel -c              # отключить диодон, очистить буфер…
sleep 0.3; xdotool key Ctrl+l          # включить адресную строку в nautilus…
sleep 0.3; xdotool key Ctrl+Alt+Down   # переместиться на другое рабочее место…
sleep 0.3; xdotool key Ctrl+Alt+t      # включить терминал…
sleep 0.3; xdotool click 1             # активировать окно терминала…
sleep 0.3; CBD=$(xsel)                 # в переменную данные буфера…
TEXT="cd '$CBD';ls"                    # формирование команды…
echo -n "$TEXT" | xsel -b -i           # переместить сформированную команду в буфер…
echo -n "$TEXT" | xsel                 # переместить сформированную команду в буфер…
sleep 0.3; xdotool key Shift+Insert    # вставить команду…
sleep 0.3; xdotool key KP_Enter        # выполнить команду…
diodon                                 # запустить ранее закрытый диодон…

— В общем эта уродливая композиция при открытом окне nautilus по hotkey открывает терминал на другом рабочем столе и запускает там команду по типу скрипта nautilus „открыть в терминале“.
— Если в nautilus положим „/media/fjf/MYCOP/2016JanDecApxuBbl“ в терминале выполниться команда „cd '/media/fjf/MYCOP/2016JanDecApxuBbl';ls

 

Страница сгенерирована за 0.066 секунд. Запросов: 25.