我使用 libgpm 来读取控制台应用程序中的鼠标事件。如果直接从 shell 启动它就可以正常工作。如果从 mc(午夜指挥官)启动,它不会接收任何鼠标事件。
问题与 mc 为我的进程创建的伪终端有关。我可以通过强制 gpm 使用作为第二个参数传递给 Gpm_Open 的指定控制台屏幕(而不是 0 - auto?)来半解决这个问题。
int Gpm_Open(Gpm_Connect*,int);
有什么方法可以知道在伪 tty(由 mc 创建)上运行时应该使用哪个虚拟控制台屏幕?我考虑过使用活动控制台,但它可能不是我的应用程序运行的控制台。可能遍历进程树并检查它的 TTY 是否是真正的控制台可以工作,但我不知道如何获取给定 pid 的 tty(name) ,我担心我需要提升权限。
或者希望有更简单的解决方法吗?
编辑:我刚刚注意到,从 mc 但通过 sudo (使用命令行)启动我的进程,而不强制 gpm 使用特定的 vc 屏幕 - 简单有效!
答案1
我设法创建一个简单的启动脚本,执行它ps f
是为了获取进程树。它给了我很好的输出,告诉我我需要的一切:
PID TTY STAT TIME COMMAND
281 tty1 Ss 0:00 -bash
383 tty1 S+ 0:00 \_ mc
385 pts/0 Ss 0:00 \_ bash -rcfile .bashrc
408 pts/0 R+ 0:00 \_ ps f
从最后一行解析出来导致我使用真正的 TTY=tty1 进行处理(当然这是有罪的mc
)。所以最后我可以用解析后的 mc 的 tty 号码作为参数来执行我的程序。
另一种选择是通过解析“/proc/PID/stat”文件来检索程序内的 tty 编号,就像ps
程序中包含 tty dev id 和父进程 id 一样。但使用脚本让我觉得它不太依赖于操作系统。下面的示例“/proc/PID/stat”:
383 (mc) R 281 383 281 1025 383 ...
| |_ TTY: test major bits for type and minor for id
|______________ PPID: use to traverse tree
所以最后我想出了这段代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <gpm.h>
static int find_tty()
{
char buf[256];
char* ptr;
FILE* f;
int r;
char stat;
int ppid,pgrp,sess,tty;
int pid = getpid();
while (pid>0)
{
sprintf(buf,"/proc/%d/stat",pid);
f = fopen(buf,"r");
if (!f)
return 0;
r = fread(buf,1,255,f);
fclose(f);
if (r<=0)
return 0;
buf[r] = 0;
ptr = strchr(buf,')');
if (!ptr || !ptr[1])
return 0;
r = sscanf(ptr+2,"%c %d %d %d %d", &stat,&ppid,&pgrp,&sess,&tty);
if (r!=5)
return 0;
if ( (tty&~63) == 1024 && (tty&63) )
return tty&63;
pid = ppid;
}
return 0;
}
int main(int argc, char* argv[])
{
Gpm_Connect gpm_connect;
// ...
int gpm = Gpm_Open(&gpm_connect,find_tty()/*0*/);
// ...
}