gpt4 book ai didi

c - TAB 和 KEY_UP 之类的键在 PTY 程序中无法按预期工作(例如 KEY_UP 变为 "^[[A")

转载 作者:行者123 更新时间:2023-11-30 16:33:33 25 4
gpt4 key购买 nike

我有一个 pty 代码示例,(可能是最流行的 pty 示例)我尝试使用它在从属设备中启动 sh [shell 终端],但 cd 或 key up [最后一个命令] 等热键不起作用 [什么也没做]我用 gcc -o pty.o pty.c 编译它并运行 ./pty.o "sh"但是当我尝试执行向上键时,它只是打印 ^[[A 和 tab 做 tab 缩进,而不是建议目录选项。代码在 http://www.rkoucha.fr/tech_corner/pty_pdip.html :

在 mypty3 下:

We can make mypty2 more generic in order to be able to execute any program behind the pty (slave side). In mypty3, the father process writes all the data from its standard input to the master side of the pty and writes all the data from the master side of the pty to its standard output. The child process behaves the same as in mypty2 but executes an interactive program along with its parameters passed as arguments to the program. We can note the calls to setsid() and ioctl(TIOCSCTTY) to make the pty be the control terminal of the executed program. We can also note the closing of the fds file descriptor which becomes useless after the calls to dup().

 #define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#define __USE_BSD
#include <termios.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <string.h>


int main(int ac, char *av[])
{
int fdm, fds;
int rc;
char input[150];

// Check arguments
if (ac <= 1)
{
fprintf(stderr, "Usage: %s program_name [parameters]\n", av[0]);
exit(1);
}

fdm = posix_openpt(O_RDWR);
if (fdm < 0)
{
fprintf(stderr, "Error %d on posix_openpt()\n", errno);
return 1;
}

rc = grantpt(fdm);
if (rc != 0)
{
fprintf(stderr, "Error %d on grantpt()\n", errno);
return 1;
}

rc = unlockpt(fdm);
if (rc != 0)
{
fprintf(stderr, "Error %d on unlockpt()\n", errno);
return 1;
}

// Open the slave side ot the PTY
fds = open(ptsname(fdm), O_RDWR);

// Create the child process
if (fork())
{
fd_set fd_in;

// FATHER

// Close the slave side of the PTY
close(fds);

while (1)
{
// Wait for data from standard input and master side of PTY
FD_ZERO(&fd_in);
FD_SET(0, &fd_in);
FD_SET(fdm, &fd_in);

rc = select(fdm + 1, &fd_in, NULL, NULL, NULL);
switch(rc)
{
case -1 : fprintf(stderr, "Error %d on select()\n", errno);
exit(1);

default :
{
// If data on standard input
if (FD_ISSET(0, &fd_in))
{
rc = read(0, input, sizeof(input));
if (rc > 0)
{
// Send data on the master side of PTY
write(fdm, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read standard input\n", errno);
exit(1);
}
}
}

// If data on master side of PTY
if (FD_ISSET(fdm, &fd_in))
{
rc = read(fdm, input, sizeof(input));
if (rc > 0)
{
// Send data on standard output
write(1, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read master PTY\n", errno);
exit(1);
}
}
}
}
} // End switch
} // End while
}
else
{
struct termios slave_orig_term_settings; // Saved terminal settings
struct termios new_term_settings; // Current terminal settings

// CHILD

// Close the master side of the PTY
close(fdm);

// Save the defaults parameters of the slave side of the PTY
rc = tcgetattr(fds, &slave_orig_term_settings);

// Set RAW mode on slave side of PTY
new_term_settings = slave_orig_term_settings;
cfmakeraw (&new_term_settings);
tcsetattr (fds, TCSANOW, &new_term_settings);

// The slave side of the PTY becomes the standard input and outputs of the child process
close(0); // Close standard input (current terminal)
close(1); // Close standard output (current terminal)
close(2); // Close standard error (current terminal)

dup(fds); // PTY becomes standard input (0)
dup(fds); // PTY becomes standard output (1)
dup(fds); // PTY becomes standard error (2)

// Now the original file descriptor is useless
close(fds);

// Make the current process a new session leader
setsid();

// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
// (Mandatory for programs like the shell to make them manage correctly their outputs)
ioctl(0, TIOCSCTTY, 1);

// Execution of the program
{
char **child_av;
int i;

// Build the command line
child_av = (char **)malloc(ac * sizeof(char *));
for (i = 1; i < ac; i ++)
{
child_av[i - 1] = strdup(av[i]);
}
child_av[i - 1] = NULL;
rc = execvp(child_av[0], child_av);
}

// if Error...
return 1;
}

return 0;
} // main

最佳答案

应该在父进程而不是子进程中调用cfmakeraw()。然后所有用户输入(TAB,...)将由子进程处理。并且父级在退出之前需要恢复其原始终端设置。

更新了代码(1. 将 cfmakeraw() 从子级移动到父级;2. 在 exit() 之前恢复终端设置):

#define _GNU_SOURCE

#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <string.h>

struct termios save_termios;

void restore_term(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &save_termios);
}

int main(int ac, char *av[])
{
int fdm, fds;
int rc;
char input[150];

tcgetattr(STDIN_FILENO, & save_termios);

// Check arguments
if (ac <= 1)
{
fprintf(stderr, "Usage: %s program_name [parameters]\n", av[0]);
exit(1);
}

fdm = posix_openpt(O_RDWR);
if (fdm < 0)
{
fprintf(stderr, "Error %d on posix_openpt()\n", errno);
return 1;
}

rc = grantpt(fdm);
if (rc != 0)
{
fprintf(stderr, "Error %d on grantpt()\n", errno);
return 1;
}

rc = unlockpt(fdm);
if (rc != 0)
{
fprintf(stderr, "Error %d on unlockpt()\n", errno);
return 1;
}

// Open the slave side ot the PTY
fds = open(ptsname(fdm), O_RDWR);

// Create the child process
if (fork())
{
fd_set fd_in;
struct termios new_setting;

// FATHER
atexit(restore_term);

new_setting = save_termios;
cfmakeraw ( & new_setting);
tcsetattr(STDIN_FILENO, TCSANOW, & new_setting);

// Close the slave side of the PTY
close(fds);

while (1)
{
// Wait for data from standard input and master side of PTY
FD_ZERO(&fd_in);
FD_SET(0, &fd_in);
FD_SET(fdm, &fd_in);

rc = select(fdm + 1, &fd_in, NULL, NULL, NULL);
switch(rc)
{
case -1 : fprintf(stderr, "Error %d on select()\n", errno);
exit(1);

default :
{
// If data on standard input
if (FD_ISSET(0, &fd_in))
{
rc = read(0, input, sizeof(input));
if (rc > 0)
{
// Send data on the master side of PTY
write(fdm, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read standard input\n", errno);
exit(1);
}
}
}

// If data on master side of PTY
if (FD_ISSET(fdm, &fd_in))
{
rc = read(fdm, input, sizeof(input));
if (rc > 0)
{
// Send data on standard output
write(1, input, rc);
}
else
{
if (rc < 0)
{
fprintf(stderr, "Error %d on read master PTY\n", errno);
exit(1);
}
}
}
}
} // End switch
} // End while
}
else
{
// CHILD

// Close the master side of the PTY
close(fdm);

// The slave side of the PTY becomes the standard input and outputs of the child process
close(0); // Close standard input (current terminal)
close(1); // Close standard output (current terminal)
close(2); // Close standard error (current terminal)

dup(fds); // PTY becomes standard input (0)
dup(fds); // PTY becomes standard output (1)
dup(fds); // PTY becomes standard error (2)

// Now the original file descriptor is useless
close(fds);

// Make the current process a new session leader
setsid();

// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
// (Mandatory for programs like the shell to make them manage correctly their outputs)
ioctl(0, TIOCSCTTY, 1);

// Execution of the program
{
char **child_av;
int i;

// Build the command line
child_av = (char **)malloc(ac * sizeof(char *));
for (i = 1; i < ac; i ++)
{
child_av[i - 1] = strdup(av[i]);
}
child_av[i - 1] = NULL;
rc = execvp(child_av[0], child_av);
}

// if Error...
return 1;
}

return 0;
} // main

关于c - TAB 和 KEY_UP 之类的键在 PTY 程序中无法按预期工作(例如 KEY_UP 变为 "^[[A"),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49717202/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com