[英]How to get fully interactive bash terminal in C with shift + ctrl keys?
I want to know how to create a fully interactive terminal. 我想知道如何创建一个完全交互式的终端。 I am creating an interactive bash terminal like this:
我正在创建一个交互式bash终端,如下所示:
fds = open(ptsname(fdm), O_RDWR);
if (fork())
{
....
}
else
{
...
ioctl(0, TIOCSCTTY, 1);
// Execution of the program
{
char *child_av[] = {"/bin/sh", "-i", NULL};
rc = execvp(child_av[0], child_av);
}
// if Error...
return -1;
}
I can then go on to use read()/write() to send commands and receive output. 然后,我可以继续使用read()/ write()发送命令并接收输出。 My problem is how do I automate CTRL & SHIFT keys?
我的问题是如何自动执行CTRL和SHIFT键? Python's subprocess does this so it's definitely possible.
Python的子进程可以做到这一点,因此绝对有可能。
process = subprocess.Popen(..) ...
process.send_signal(signal.SIGINT)
from subprocess import Popen, PIPE
shift_a_sequence = '''keydown Shift_L
key A
keyup Shift_L
'''
def keypress(sequence):
p = Popen(['xte'], stdin=PIPE)
p.communicate(input=sequence)`
You seem to have most of the framework needed: 您似乎拥有所需的大多数框架:
For more detail on where you are going wrong, you'd need to provide a Minimal, Complete, and Verifiable example of what you are actually trying to do, not just a vague description. 有关错误原因的更多详细信息,您需要提供一个最小,完整和可验证的示例来说明您实际要做什么,而不仅仅是模糊的描述。
There are four separate issues here: 这里有四个独立的问题:
The sigint is triggered by the terminal's line discipline upon receiving Ctrl-C as input (in cooked mode). 当接收到Ctrl-C作为输入时(在烹饪模式下),终端的线路规程会触发sigint。 You can do this by sending 0x03, which is equivalent to uppercase ASCII 'C' with the 7th bit cleared:
您可以通过发送0x03来做到这一点,它等于清除了第7位的大写ASCII'C':
write(fdm, "\x03", 1);
process.send_signal
process.send_signal
process = subprocess.Popen(..) ... process.send_signal(signal.SIGINT)
This simply does a fork
+ kill
, so it's unrelated to anything you'd do to accomplish #1. 这只是执行
fork
+ kill
,因此它与您为实现#1所做的一切无关。 You can see this in strace
: 您可以在
strace
看到:
$ cat foo.py
import signal
import subprocess
process = subprocess.Popen(["sleep", "10"])
process.send_signal(signal.SIGINT)
$ strace -f -eclone,kill,execve python foo.py
execve("/usr/bin/python", ["python", "foo.py"], 0x7ffe4d179458 /* 30 vars */) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fa0f6e14a10) = 12917
strace: Process 12917 attached
[pid 12917] execve("/usr/bin/sleep", ["sleep", "10"], 0x7ffe6a45efc0 /* 30 vars */) = -1 ENOENT (No such file or directory)
[pid 12917] execve("/bin/sleep", ["sleep", "10"], 0x7ffe6a45efc0 /* 30 vars */ <unfinished ...>
[pid 12916] kill(12917, SIGINT) = 0
[pid 12917] <... execve resumed> ) = 0
[pid 12917] --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=12916, si_uid=1000} ---
[pid 12917] +++ killed by SIGINT +++
Esc is simple: you just send its ASCII value. Esc很简单:您只需发送其ASCII值即可。 Here's
man ascii
: 这是
man ascii
:
033 27 1B ESC (escape)
Shift and Control are modifiers, so you don't actually send them. Shift和Control是修饰符,因此您实际上并不发送它们。 You just modify the character you send.
您只需修改发送的字符。 #1 already covered how to do this for Ctrl on simple ascii characters.
#1已经介绍了如何在简单的ascii字符上使用Ctrl进行此操作。
For shift, you should simply uppercase the character you're interested in using appropriate string functions. 对于shift,您应该使用适当的字符串函数将您感兴趣的字符简单地大写。 The traditional hardware logic of clearing/setting bit 6 doesn't work well for unicode characters, but
'c' == 'C'+0x20
if you feel like it. 清除/设置位6的传统硬件逻辑不适用于unicode字符,但是如果您愿意,可以使用
'c' == 'C'+0x20
。
Note that this does not apply to things like arrow keys, where you need to send a different ANSI escape code corresponding to the terminal you're trying to emulate. 请注意,这不适用于箭头键之类的东西,在该情况下,您需要发送与您要模拟的终端相对应的不同ANSI转义码。
For completeness, Alt/Meta has two forms: Traditionally setting bit 8 (mostly deprecated for Unicode reasons), or Meta-As-Escape where you simply send the two bytes ESC
x
for Alt+x
. 为了完整起见,Alt / Meta具有两种形式:传统上将bit 8设置(大多出于Unicode原因而弃用),或Meta-As-Escape,您只需将两个字节的
ESC
x
发送给Alt+x
。
xte
xte
的管道的C from subprocess import Popen, PIPE shift_a_sequence = '''keydown Shift_L key A keyup Shift_L ''' def keypress(sequence): p = Popen(['xte'], stdin=PIPE) p.communicate(input=sequence)`
This opens an X11 utility that simulates an X11 key sequence. 这将打开一个模拟X11按键序列的X11实用程序。 If you are running the program in an XTerm and don't switch focus, this will hopefully end up in the terminal where you started, but this is not at all a guarantee.
如果您在XTerm中运行该程序并且不切换焦点,则希望最终会在您启动的终端中结束,但这完全不能保证。 It is definitely nothing like #3.
绝对不像#3。
If you wanted to do this though, you can use popen
from C in much the same way, but it won't help you do anything of what you describe textually. 但是,如果要执行此操作,则可以使用与C
popen
的方式来使用popen
,但它不会帮助您执行任何用文本描述的内容。
You can find a complete example for sending Ctrl+C
adapted from your code here: 您可以在此处找到根据代码发送改编的
Ctrl+C
的完整示例:
#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define __USE_BSD
#include <termios.h>
#define guard(x) do { if((x)<0) { perror(#x); exit(1); } } while(0);
int main(void)
{
int fdm, fds, rc;
char input[150];
fdm = posix_openpt(O_RDWR);
guard(grantpt(fdm));
guard(unlockpt(fdm));
if (fork())
{
char* output = "sleep 60\n";
// Start a long sleep
write(fdm, output, strlen(output));
// Wait and send Ctrl-C to abort it after 1 second
sleep(1); write(fdm, "\x03", 1);
// Make sure shell is still alive
output = "echo 'Shell is still alive'\n";
write(fdm, output, strlen(output));
// Wait and send Ctrl-D to exit
sleep(1); write(fdm, "\x04", 1);
while((rc = read(fdm, input, sizeof(input)-1)) > 0) {
input[rc] = 0;
printf("From PTY:\n%s\n", input);
}
close(fdm);
wait(NULL);
}
else
{
setsid();
guard(fds = open(ptsname(fdm), O_RDWR));
close(fdm);
dup2(fds, 0);
dup2(fds, 1);
dup2(fds, 2);
close(fds);
execlp("sh", "sh", "-i", NULL);
}
return 0;
} // main
Execution shows that sleep is interrupted, the shell continues, and is finally exited: 执行表明睡眠被中断,shell继续运行,最后退出:
$ ./foo
From PTY:
sleep 60
$ ^C
echo 'Shell is still alive'
$ Shell is still alive
$
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.