操作input子系统,用模拟按键输入解锁ubuntu锁屏

在使用ubuntu24.04作为我工作的主系统,有时有远程操作办公的需求,ubuntu提供了与windows兼容的不错的方案,在设置-》系统-》远程桌面,进行配置就可以使用远程桌面连接进行远程操作;与windwos的远程桌面工具兼容,操作一致。

但是也有不完善的地方,让这个功能有时就是鸡肋。由于该功能要在登陆后才可以用,而且不可以锁屏状态下连接,所以在你需要要远程使用时,基本用不了(不可能设置不锁屏,不安全;也不可能把密码告诉同事让帮忙登陆或解锁屏幕,更不安全)

但是远程操作又是时常的需求,所以我想用给系统发按键事件的方式,让系统锁屏界面像用户输入密码一样,解锁屏幕。

源码实现如下:

cpp 复制代码
#include <iostream>

#include <linux/input.h>
#include <fcntl.h>        // 修复 O_RDWR 未定义问题
#include <stdio.h>        // 用于 printf
#include <sys/time.h>     // 用于 gettimeofday
#include <unistd.h>       // 用于 write 和 open

#include <unordered_map>


#define KEYDOWN(fd_kb,event,key)  \
        do          \
        {           \            
            event.code = key;     \
            event.type = EV_KEY;            \
            event.value = 1;                \
            gettimeofday(&event.time, NULL);\
            if (write(fd_kb, &event, sizeof(event)) != sizeof(event))\
            {\
                printf("write /dev/input/event0 failed\n");\
            }\
        } while (0);

#define KEYUP(fd_kb,event,key)  \
        do          \
        {           \            
            event.code = key;     \
            event.type = EV_KEY;            \
            event.value = 0;                \
            gettimeofday(&event.time, NULL);\
            if (write(fd_kb, &event, sizeof(event)) != sizeof(event))\
            {\
                printf("write /dev/input/event0 failed\n");\
            }\
        } while (0);

#define KEYSYNC(fd_kb,event)  \
        do          \
        {           \            
            event.code = EV_SYN;     \
            event.type = SYN_REPORT;            \
            event.value = 0;                \
            gettimeofday(&event.time, NULL);\
            if (write(fd_kb, &event, sizeof(event)) != sizeof(event))\
            {\
                printf("write /dev/input/event0 failed\n");\
            }\
        } while (0);

// struct input_event g_event;
// int keyDown(int fd_kb, __u16 key)
// {

//     // struct input_event event;

//     g_event.code = key;
//     g_event.type = EV_KEY;
//     g_event.value = 1;                 //1表示按下,0表示释放,2表示长按
//     gettimeofday(&g_event.time, NULL);
    
//     if (write(fd_kb, &g_event, sizeof(g_event)) != sizeof(g_event))
//     {
//         printf("write /dev/input/event0 failed\n");
//     }

// }

// int keyUp(int fd_kb, __u16 key)
// {

//     // struct input_event event;

//     g_event.code = key;
//     g_event.type = EV_KEY;
//     g_event.value = 0;                 //1表示按下,0表示释放,2表示长按
//     gettimeofday(&g_event.time, NULL);
    
//     if (write(fd_kb, &g_event, sizeof(g_event)) != sizeof(g_event))
//     {
//         printf("write /dev/input/event0 failed\n");
//     }

// }

// int keySync(int fd_kb)
// {

//     // struct input_event event;

//     g_event.type = EV_SYN;
//     g_event.code = SYN_REPORT;
//     g_event.value = 0;
//     gettimeofday(&g_event.time, NULL);
//     if (write(fd_kb, &g_event, sizeof(g_event)) != sizeof(g_event)) {
//         printf("写入同步事件失败");
//     }
// }

// ASCII码与KEY定义的对应表
std::unordered_map<int, int> asciiToKeyMap = {
    // 控制字符 (0-31)
    {0, KEY_RESERVED},        // NUL
    {1, KEY_RESERVED},        // SOH
    {2, KEY_RESERVED},        // STX
    {3, KEY_RESERVED},        // ETX
    {4, KEY_RESERVED},        // EOT
    {5, KEY_RESERVED},        // ENQ
    {6, KEY_RESERVED},        // ACK
    {7, KEY_RESERVED},        // BEL
    {8, KEY_BACKSPACE},       // BS
    {9, KEY_TAB},             // TAB
    {10, KEY_ENTER},          // LF (换行)
    {11, KEY_RESERVED},       // VT
    {12, KEY_RESERVED},       // FF
    {13, KEY_ENTER},          // CR (回车)
    {14, KEY_RESERVED},       // SO
    {15, KEY_RESERVED},       // SI
    {16, KEY_RESERVED},       // DLE
    {17, KEY_RESERVED},       // DC1
    {18, KEY_RESERVED},       // DC2
    {19, KEY_RESERVED},       // DC3
    {20, KEY_RESERVED},       // DC4
    {21, KEY_RESERVED},       // NAK
    {22, KEY_RESERVED},       // SYN
    {23, KEY_RESERVED},       // ETB
    {24, KEY_RESERVED},       // CAN
    {25, KEY_RESERVED},       // EM
    {26, KEY_RESERVED},       // SUB
    {27, KEY_ESC},            // ESC
    {28, KEY_RESERVED},       // FS
    {29, KEY_RESERVED},       // GS
    {30, KEY_RESERVED},       // RS
    {31, KEY_RESERVED},       // US
    
    // 空格和标点符号 (32-64)
    {32, KEY_SPACE},          // 空格
    {33, KEY_1},              // ! (需要Shift)
    {34, KEY_APOSTROPHE},     // " (需要Shift)
    {35, KEY_3},              // # (需要Shift)
    {36, KEY_4},              // $ (需要Shift)
    {37, KEY_5},              // % (需要Shift)
    {38, KEY_7},              // & (需要Shift)
    {39, KEY_APOSTROPHE},     // '
    {40, KEY_9},              // ( (需要Shift)
    {41, KEY_0},              // ) (需要Shift)
    {42, KEY_8},              // * (需要Shift)
    {43, KEY_EQUAL},          // + (需要Shift)
    {44, KEY_COMMA},          // ,
    {45, KEY_MINUS},          // -
    {46, KEY_DOT},            // .
    {47, KEY_SLASH},          // /
    
    // 数字 (48-57)
    {48, KEY_0},              // 0
    {49, KEY_1},              // 1
    {50, KEY_2},              // 2
    {51, KEY_3},              // 3
    {52, KEY_4},              // 4
    {53, KEY_5},              // 5
    {54, KEY_6},              // 6
    {55, KEY_7},              // 7
    {56, KEY_8},              // 8
    {57, KEY_9},              // 9
    
    // 标点符号 (58-64)
    {58, KEY_SEMICOLON},      // : (需要Shift)
    {59, KEY_SEMICOLON},      // ;
    {60, KEY_COMMA},          // < (需要Shift)
    {61, KEY_EQUAL},          // =
    {62, KEY_DOT},            // > (需要Shift)
    {63, KEY_SLASH},          // ? (需要Shift)
    {64, KEY_2},              // @ (需要Shift)
    
    // 大写字母 (65-90)
    {65, KEY_A},              // A (需要Shift)
    {66, KEY_B},              // B (需要Shift)
    {67, KEY_C},              // C (需要Shift)
    {68, KEY_D},              // D (需要Shift)
    {69, KEY_E},              // E (需要Shift)
    {70, KEY_F},              // F (需要Shift)
    {71, KEY_G},              // G (需要Shift)
    {72, KEY_H},              // H (需要Shift)
    {73, KEY_I},              // I (需要Shift)
    {74, KEY_J},              // J (需要Shift)
    {75, KEY_K},              // K (需要Shift)
    {76, KEY_L},              // L (需要Shift)
    {77, KEY_M},              // M (需要Shift)
    {78, KEY_N},              // N (需要Shift)
    {79, KEY_O},              // O (需要Shift)
    {80, KEY_P},              // P (需要Shift)
    {81, KEY_Q},              // Q (需要Shift)
    {82, KEY_R},              // R (需要Shift)
    {83, KEY_S},              // S (需要Shift)
    {84, KEY_T},              // T (需要Shift)
    {85, KEY_U},              // U (需要Shift)
    {86, KEY_V},              // V (需要Shift)
    {87, KEY_W},              // W (需要Shift)
    {88, KEY_X},              // X (需要Shift)
    {89, KEY_Y},              // Y (需要Shift)
    {90, KEY_Z},              // Z (需要Shift)
    
    // 标点符号 (91-96)
    {91, KEY_LEFTBRACE},      // [
    {92, KEY_BACKSLASH},      // \
    {93, KEY_RIGHTBRACE},     // ]
    {94, KEY_6},              // ^ (需要Shift)
    {95, KEY_MINUS},          // _ (需要Shift)
    {96, KEY_GRAVE},          // `
    
    // 小写字母 (97-122)
    {97, KEY_A},              // a
    {98, KEY_B},              // b
    {99, KEY_C},              // c
    {100, KEY_D},             // d
    {101, KEY_E},             // e
    {102, KEY_F},             // f
    {103, KEY_G},             // g
    {104, KEY_H},             // h
    {105, KEY_I},             // i
    {106, KEY_J},             // j
    {107, KEY_K},             // k
    {108, KEY_L},             // l
    {109, KEY_M},             // m
    {110, KEY_N},             // n
    {111, KEY_O},             // o
    {112, KEY_P},             // p
    {113, KEY_Q},             // q
    {114, KEY_R},             // r
    {115, KEY_S},             // s
    {116, KEY_T},             // t
    {117, KEY_U},             // u
    {118, KEY_V},             // v
    {119, KEY_W},             // w
    {120, KEY_X},             // x
    {121, KEY_Y},             // y
    {122, KEY_Z},             // z
    
    // 标点符号 (123-126)
    {123, KEY_LEFTBRACE},     // { (需要Shift)
    {124, KEY_BACKSLASH},     // | (需要Shift)
    {125, KEY_RIGHTBRACE},    // } (需要Shift)
    {126, KEY_GRAVE},         // ~ (需要Shift)
    
    // 删除键
    {127, KEY_DELETE}         // DEL
};

// 判断字符是否需要Shift键的函数
bool needsShift(int asciiCode) {
    // 需要Shift键的ASCII字符范围
    if ((asciiCode >= 33 && asciiCode <= 38) ||   // !"#$%&
        (asciiCode >= 40 && asciiCode <= 43) ||   // )*+
        (asciiCode == 58) || (asciiCode == 60) || // :<
        (asciiCode == 62) || (asciiCode == 63) || // >?
        (asciiCode == 64) ||                      // @
        (asciiCode >= 65 && asciiCode <= 90) ||   // A-Z
        (asciiCode == 94) || (asciiCode == 95) || // ^_
        (asciiCode == 123) || (asciiCode == 124) || // {|
        (asciiCode == 125) || (asciiCode == 126)) { // }~
        return true;
    }
    return false;
}

// 根据ASCII码获取对应的KEY定义
int getKeyCode(int asciiCode) {
    auto it = asciiToKeyMap.find(asciiCode);
    if (it != asciiToKeyMap.end()) {
        return it->second;
    }
    return KEY_RESERVED; // 未找到对应的键值
}

// 打印ASCII码与KEY定义的对应表
void printAsciiKeyTable() {
    std::cout << "ASCII码与KEY定义对应表:\n";
    std::cout << "========================================\n";
    std::cout << "ASCII | 字符 | KEY定义 | 需要Shift\n";
    std::cout << "----------------------------------------\n";
    
    for (int i = 0; i <= 127; i++) {
        if (asciiToKeyMap.find(i) != asciiToKeyMap.end()) {
            std::cout << i << "\t| ";
            
            // 显示可打印字符
            if (i >= 32 && i <= 126) {
                std::cout << "'" << (char)i << "'";
            } else {
                std::cout << "控制字符";
            }
            
            std::cout << "\t| KEY_" << asciiToKeyMap[i] << "\t| ";
            std::cout << (needsShift(i) ? "是" : "否") << std::endl;
        }
    }
}

// 使用示例函数:根据字符串模拟按键
void simulateStringInput(int fd_kb, const std::string& text) {
    struct input_event event;
    
    for (char c : text) {
        int asciiCode = (int)c;
        int keyCode = getKeyCode(asciiCode);
        bool shiftNeeded = needsShift(asciiCode);
        
        if (keyCode != KEY_RESERVED) {
            // 如果需要Shift键,先按下Shift
            if (shiftNeeded) {
                KEYDOWN(fd_kb, event, KEY_LEFTSHIFT);
            }
            
            // 按下并释放字符键
            KEYDOWN(fd_kb, event, keyCode);
            KEYSYNC(fd_kb, event);
            usleep(50 * 1000); // 50ms延迟
            
            KEYUP(fd_kb, event, keyCode);
            KEYSYNC(fd_kb, event);
            usleep(50 * 1000);
            
            // 如果需要Shift键,释放Shift
            if (shiftNeeded) {
                KEYUP(fd_kb, event, KEY_LEFTSHIFT);
                KEYSYNC(fd_kb, event);
                usleep(50 * 1000);
            }
        }
    }
}

int main(int argc, char** argv){
    std::cout << "Hello, from kdbunlook!\n";

    if (argc != 3)
    {
        std::cout << "sudo kdbunlook <path-event-kdb> <password>\n";
        return -1;
    }

    std::string userInput = argv[2];
    // std::getline(std::cin, userInput);

    int fd_kb;
    // char *dev_path = "/dev/input/by-path/pci-0000:00:14.0-usb-0:2:1.0-event-kbd";
    // char *dev_path = "/dev/input/by-path/pci-0000:00:14.0-usb-0:6:1.1-event-kbd";
    // char *dev_path = "/dev/input/by-path/pci-0000:00:14.0-usbv2-0:4:1.0-event-kbd";
    char *dev_path = argv[1];

    sleep(5);
    /* open keyboard */
    // fd_kb = open("/dev/input/event5", O_RDWR);
    fd_kb = open(dev_path, O_RDWR | O_SYNC);
    if (fd_kb < 0) {
        printf("Failed to open /dev/input/event0\n");
        return 1;
    }

    simulateStringInput(fd_kb, "\n" + userInput + "\n");


    close(fd_kb);  // 关闭设备描述符
    sleep(1);
    return 0;
}

编译后需要sudo权限执行,因为需要操作设备文件。

当你需要远程桌面连接,先需要解锁屏幕,用ssh连接ubuntu系统,执行编译好的程序,带上键盘输入设备文件路径(可以用ls /dev/input/by-path查看)和密码

sudo kdbunlock /dev/input/by-path/pci-0000:00:14.0-usbv2-0:4:1.0-event-kbd xxxx438

延时几秒后就会解锁屏幕(如果大写键已经锁定,会输入不一样,会失败)

然后就可以开心的远程办公了:)

相关推荐
倔强的石头1062 小时前
【Linux指南】基础IO系列(一)Linux 文件本质揭秘 —— 从 “磁盘文件” 到 “一切皆文件”
linux·运维·服务器
Code小翊2 小时前
re标准库模块一天学完
运维·服务器·网络
2023自学中2 小时前
imx6ull , 4.3寸800*480屏幕,触摸芯片型号 gt9147,显示触摸点的坐标数据
linux·嵌入式硬件
Warren982 小时前
Allure 常用装饰器:实战用法 + 最佳实践(接口自动化)
运维·服务器·git·python·单元测试·自动化·pytest
2501_943695332 小时前
高职大数据运维与管理专业,怎么学习Hadoop的基础操作?
大数据·运维·学习
落羽的落羽2 小时前
【Linux系统】文件IO:理解文件描述符、重定向、缓冲区
linux·服务器·开发语言·数据结构·c++·人工智能·机器学习
xie_pin_an2 小时前
Linux 基础入门:从历史到核心指令全解析
linux·运维·服务器
遇见火星2 小时前
服务器HBA卡与RAID卡:到底有什么区别?
运维·服务器·hba卡·raid卡
DONG9992 小时前
To create a RAM-based block device in Ubuntu.
ubuntu