linux鼠标键盘监控整理

一、监控鼠标键盘设备

#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#include <errno.h>

struct timespec ts1, ts2;

int listen_keyboard(const char *dev, int timeout)
{
    int retval;
    fd_set readfds;
    struct timeval tv;
    struct input_event event;

    int fd = open(dev, O_RDONLY);
    if (fd < 0)
    {
        return errno;
    }

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        tv.tv_sec = timeout;
        tv.tv_usec = 0;
        if((retval = select(fd+1, &readfds, NULL, NULL, &tv)) == 1)
        {
            if (read(fd, &event, sizeof(event)) == sizeof(event))
            {
		    clock_gettime(CLOCK_REALTIME, &ts1);
		    return 0;
            } else {
		    return 0;
	    }
        }
        else
        {
            break;
        }
    }

    close(fd);
    return 0;
}

int listen_mice(const char *dev, int timeout)
{
    char buf[256];
    int n_len;

    int retval;
    fd_set readfds;
    struct timeval tv;

    int fd = open(dev, O_RDONLY);

    if (fd < 0)
    {
        return errno;
    }

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        tv.tv_sec = timeout;
        tv.tv_usec = 0;
        if((retval = select(fd+1, &readfds, NULL, NULL, &tv)) == 1)
        {
            if ((n_len = read(fd, buf, sizeof(buf))) > 0)
            {
                if (n_len == 3)
                {
			clock_gettime(CLOCK_REALTIME, &ts1);
			return 0;
                }
            }
        }
        else
        {
            break;
        }
    }

    close(fd);
    return 0;
}

void * mon_key(void *arg)
{
	int ret;
	char *path = (char *)arg;
	while(1) {
		ret = listen_keyboard(path, 3600);
		if (ret != 0) {
			exit(-1);
		}
	}
}

void * mon_mouse(void *arg)
{
	while(1) {
		listen_mice("/dev/input/mice", 3600);
	}
}

int main(int argc, char **argv)
{
    pthread_t id[10];
    int i;
    char apath[100];
    char *bpath[i];
    FILE *fp;

    clock_gettime(CLOCK_REALTIME, &ts1);
    clock_gettime(CLOCK_REALTIME, &ts2);

    fp = popen("ls /dev/input/by-path |grep kbd", "r");
    if (fp == NULL){
	    printf("popen failed\n");
	    return -1;
    }

    i=0;
    while (fgets(apath, sizeof(apath), fp)) {
	    bpath[i] = malloc(200);

	    apath[strlen(apath) - 1] = '\0';
	    sprintf(bpath[i], "/dev/input/by-path/%s", apath);
	    pthread_create(&id[i], NULL, &mon_key, bpath[i]);
	    i++;
    }
    pclose(fp);
    pthread_create(&id[i++], NULL, &mon_mouse, NULL);

    while(1) {
	    sleep(1);
	    clock_gettime(CLOCK_REALTIME, &ts2);
	    printf("idletime %ld\n", ts2.tv_sec - ts1.tv_sec);
    }

    return 0;
}


二、使用pynput监控鼠标键盘事件

#!/usr/bin/python3
'''
apt install python3-dev
apt install pip
pip3 install pynput
'''

from pynput.keyboard import Key as kbKey, Listener as kbListener
from pynput.mouse import  Listener as msListener
import threading
import time
import datetime
import os

updateDatetime = datetime.datetime.now()
currentDatetime = datetime.datetime.now()

'''
关于键盘的事件回调
'''
#defining function to print when key is pressed
def on_press(key):
    global updateDatetime
    updateDatetime = datetime.datetime.now()
    print('{0} pressed'.format(key))

#defining function to print when key is released
def on_release(key):
    global updateDatetime
    updateDatetime = datetime.datetime.now()
    print('{0} release'.format(key))

'''
关于鼠标及触控的事件回调
'''
def on_move(x, y ):
    global updateDatetime
    updateDatetime = datetime.datetime.now()
    print('Pointer moved to {0}'.format((x,y)))

def on_click(x, y , button, pressed):
    global updateDatetime
    updateDatetime = datetime.datetime.now()
    print('{0} at {1}'.format('Pressed' if pressed else 'Released', (x, y)))

def on_scroll(x, y ,dx, dy):
    global updateDatetime
    updateDatetime = datetime.datetime.now()
    print('scrolled {0} at {1}'.format('down' if dy < 0 else 'up',(x, y)))
 
'''
键盘的事件监控
'''
def toListenerKb(threadName):
    # # Collect events until released
    while True:
        with kbListener(
            on_press=on_press,
            on_release=on_release) as listener:
            listener.join()

'''
鼠标的事件监控
'''
def toListenerMouse(threadName):
    while True:
        with msListener(on_move = on_move,on_click = on_click,on_scroll = on_scroll) as listener:
            listener.join()


if __name__ == '__main__':

    threads = []
    t1 = threading.Thread( target=toListenerKb , args=("Listener keyBoard", ))
    t2 = threading.Thread( target=toListenerMouse , args=("Listener Mouse", ))
    threads.append(t1)
    threads.append(t2)

    for t in threads:
        t.setDaemon(True)
        t.start()

    while True:
        currentDatetime = datetime.datetime.now()
        sub = currentDatetime - updateDatetime
        
        time.sleep(1)
        # 30s 没有操作就杀死远程
        if sub.seconds > 30:
            os.system("ps -ef | grep remmina | grep -v grep; if [ $? -eq 0 ]; then killall -9 remmina; fi")
        print('空闲时间: {0}秒'.format(sub.seconds))


三、使用X11的extensions监控鼠标键盘事件

3.1 使用Python的python3-xlib库进行监控

#!/usr/bin/python3

'''
apt install python3-xlib

Simple demo for the RECORD extension
Not very much unlike the xmacrorec2 program in the xmacro package.
'''
# apt install python3-xlib

# Python 2/3 compatibility.
from __future__ import print_function

import sys
import threading
import time
import datetime
import os

from Xlib import X, XK, display
from Xlib.ext import record
from Xlib.protocol import rq

updateDatetime = datetime.datetime.now()
currentDatetime = datetime.datetime.now()

local_dpy = display.Display()
record_dpy = display.Display()

# Check if the extension is present
if not record_dpy.has_extension("RECORD"):
    print("RECORD extension not found")
    sys.exit(1)
r = record_dpy.record_get_version(0, 0)
print("RECORD extension version %d.%d" % (r.major_version, r.minor_version))

# Create a recording context; we only want key and mouse events
ctx = record_dpy.record_create_context(
    0,
    [record.AllClients],
    [{
        'core_requests': (0, 0),
        'core_replies': (0, 0),
        'ext_requests': (0, 0, 0, 0),
        'ext_replies': (0, 0, 0, 0),
        'delivered_events': (0, 0),
        'device_events': (X.KeyPress, X.MotionNotify),
        'errors': (0, 0),
        'client_started': False,
        'client_died': False,
    }])


def lookup_keysym(keysym):
    for name in dir(XK):
        if name[:3] == "XK_" and getattr(XK, name) == keysym:
            return name[3:]
    return "[%d]" % keysym


def record_callback(reply):
    '''
    回调函数
    '''
    if reply.category != record.FromServer:
        return
    if reply.client_swapped:
        print("* received swapped protocol data, cowardly ignored")
        return
    if not len(reply.data) or reply.data[0] < 2:
        # not an event
        return

    global updateDatetime
    data = reply.data
    while len(data):
        event, data = rq.EventField(None).parse_binary_value(
            data, record_dpy.display, None, None)
        if event.type in [X.KeyPress, X.KeyRelease]:
            updateDatetime = datetime.datetime.now()
            pr = event.type == X.KeyPress and "Press" or "Release"

            keysym = local_dpy.keycode_to_keysym(event.detail, 0)
            if not keysym:
                print("KeyCode%s" % pr, event.detail)
            else:
                print("KeyStr%s" % pr, lookup_keysym(keysym))

            if event.type == X.KeyPress and keysym == XK.XK_Escape:
                local_dpy.record_disable_context(ctx)
                local_dpy.flush()
                return
        elif event.type == X.ButtonPress:
            updateDatetime = datetime.datetime.now()
            print("ButtonPress", event.detail)
        elif event.type == X.ButtonRelease:
            updateDatetime = datetime.datetime.now()
            print("ButtonRelease", event.detail)
        elif event.type == X.MotionNotify:
            updateDatetime = datetime.datetime.now()
            print("MotionNotify", event.root_x, event.root_y)


def monitor(threadName):
    '''
    线程函数
    '''
    # Enable the context; this only returns after a call to record_disable_context,
    # while calling the callback function in the meantime
    record_dpy.record_enable_context(ctx, record_callback)

    # Finally free the context
    record_dpy.record_free_context(ctx)


if __name__ == '__main__':
    t = threading.Thread(target=monitor, args=("Listener", ))
    t.setDaemon(True)
    t.start()

    while True:
        currentDatetime = datetime.datetime.now()
        sub = currentDatetime - updateDatetime
        time.sleep(1)
        print('空闲时间: {0}秒'.format(sub.seconds))


3.2 使用c调用X11的extensions库进行监控

// apt install xorg-dev
// 编译:gcc xrecord_monitor.c -lX11 -lXtst -lpthread -o xrecord_monitor
// sudo apt-get install xorg-dev
// gcc xrecord_monitor.c -lX11 -lXtst -lpthread -o xrecord_monitor
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/extensions/record.h>
#include <time.h>
#include <pthread.h>

time_t updateTime,currentTime;

static void event_cb (XPointer user_data, XRecordInterceptData *hook)
{
    if ( hook->category != XRecordFromServer ) {
        printf ("Data not from server!");
        return;
    }
    
    xEvent * event = (xEvent *)hook->data; 
    switch (event->u.u.type) {
        case KeyPress:
            updateTime = time(NULL);
            printf ("key press event! \n");
            break;
 
        case KeyRelease:
            updateTime = time(NULL);
            printf ("key release event! \n");
            break;
 
        case ButtonPress:
            updateTime = time(NULL);
            printf ("button press event! x = %d, y = %d\n", event->u.keyButtonPointer.rootX, event->u.keyButtonPointer.rootY);
            break;
 
        case ButtonRelease:
            updateTime = time(NULL);
            printf ("button release event! x = %d, y = %d\n", event->u.keyButtonPointer.rootX, event->u.keyButtonPointer.rootY);
            break;
        case MotionNotify:
            updateTime = time(NULL);
            printf ("mouse move event! x = %d, y = %d\n", event->u.keyButtonPointer.rootX, event->u.keyButtonPointer.rootY);
            break;
        default:
            updateTime = time(NULL);
            printf ("other events grab \n");
            /* FIXME: other events grab */
            break;
    }
}

void * monitor(void *arg)
{
    Display *ctrl_disp = XOpenDisplay(NULL);
    Display *data_disp = XOpenDisplay(NULL);
 
    if ( !ctrl_disp || !data_disp ) {
        fprintf (stderr,"Unable to connect to X11 display! \n");
        return NULL;
    }
    int major, minor, dummy;
    if ( !XQueryExtension (ctrl_disp, "XTEST", &major, &minor, &dummy) ) {
        fprintf (stderr,"XTest extension missing! \n");
        return NULL;
    }
    if ( !XRecordQueryVersion (ctrl_disp, &major, &minor) ) {
        fprintf (stderr,"Failed to obtain xrecord version! \n");
        return NULL;
    }
    XSynchronize(ctrl_disp, True);
    XFlush (ctrl_disp);
 
    XRecordRange *range = XRecordAllocRange ();

    /*
     * 设定事件监听的范围
     * 监听 first ~ last 之间的事件
     */
    range->device_events.first = KeyPress;
    range->device_events.last = LASTEvent;
    XRecordClientSpec spec = XRecordAllClients;
    XRecordContext context = XRecordCreateContext (
                                 data_disp, 0, &spec, 1, &range, 1 );
    if ( !context ) {
        fprintf (stderr,"Failed to create context! \n");
        return NULL;
    }
 
    if ( !XRecordEnableContext(data_disp, context, event_cb, NULL) ) {
        fprintf (stderr,"Failed to enable context! \n");
        return NULL;
    }
 
    XRecordDisableContext(data_disp, context);
    XRecordFreeContext (data_disp, context);
    XFree(range);
 
    XCloseDisplay (data_disp);
    XCloseDisplay (ctrl_disp);
    return NULL;
}
 
int main (int argc, char *argv[])
{
    pthread_t tid;
    pthread_create(&tid, NULL, &monitor, NULL);

    while(1) {
	    sleep(1);
	    currentTime = time(NULL);
	    printf("idle time %ld s\n", currentTime - updateTime);
    }
    return 0;
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值