我正在尝试构建一个打印"默认值的程序"用户可以通过删除部分内容并再次书写来快速更改。
该程序将打印例如:
enter app name: xcode
用户应该能够更换" xcode"字符串(但不是":"部分)然后程序应该得到整个输入。
有没有办法在纯C中使用标准控制台OSX使用? 非常感谢
答案 0 :(得分:0)
这将在屏幕上显示提示和默认输入。箭头键将向右和向左移动光标。模式可以从INS(插入)更改为OVW (覆盖)使用Ins键。 Enter将终止输入,因为太多字符。可以使用LETTERS |的某些组合来限制有效字符NUMBERS | DOT |空间|签名| PUNCT。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#define ESC 27
#define INSERT 50
#define DELETE 51
#define PGUP 53
#define PGDN 54
#define ARROWRIGHT 67
#define ARROWLEFT 68
#define END 70
#define HOME 72
#define OTHER 79
#define BRACKETLEFT 91
#define TILDE 126
#define BACKSPACE 127
#define LETTERS 1
#define NUMBERS 2
#define DOT 4
#define SPACE 8
#define SIGN 16
#define PUNCT 32
#define SIZE 30
static const int STDIN = 0;
typedef struct Field {
int row;//place input on screen row and col
int col;
int contentsize;//allowed length of input
int inputat;//input at this index
int used;//characters used so far
int valid;//limit input to these characters
int insert;//mode insert/overwrite
int promptrow;//place prompt on screen row and col
int promptcol;
int promptsize;
int lastline;
int lastcol;
int stopon;//stop input with this character
char *content;
char *prompt;
} field;
int kbhit(void)
{
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
void prompt ( field *psfield) {
printf ( "\033[%d;%dH", psfield->promptrow, psfield->promptcol);
printf ( "%s", psfield->prompt);
}
int input ( field *psfield) {
int ch = 0;
int to = 0;
printf ( "\033[%d;1H", psfield->lastline);
if ( psfield->insert) {
printf ( "INS");
}
else {
printf ( "OVW");
}
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
while ( ( ch = getchar ()) != psfield->stopon) {
printf ( "\033[%d;10H", psfield->lastline);
printf ( "\033[K");//erase to end of line
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
if (
( ( psfield->valid & LETTERS && isalpha ( ch)))
|| ( ( psfield->valid & SPACE && ch == ' '))
|| ( ( psfield->valid & DOT && ch == '.'))
|| ( ( psfield->valid & SIGN && ( ch == '+' || ch == '-')))
|| ( ( psfield->valid & NUMBERS && isdigit ( ch)))
|| ( ( psfield->valid & PUNCT && ispunct ( ch)))
) {
if ( psfield->insert && psfield->inputat < psfield->used && psfield->used < psfield->contentsize-3) {
//expand
psfield->used++;
for ( to = psfield->used; to >= psfield->inputat; to--) {
psfield->content[to + 1] = psfield->content[to];
}
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
}
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
printf ( "%c", ch);
psfield->content[psfield->inputat] = ch;
psfield->inputat++;
if ( psfield->inputat > psfield->used) {
psfield->used = psfield->inputat;
}
if ( psfield->inputat == psfield->used) {
psfield->content[psfield->inputat] = '\0';
}
if ( psfield->inputat >= psfield->contentsize-1) {
return -1;
}
continue;
}
if ( isprint ( ch)) {
printf ( "\033[%d;10H", psfield->lastline);
printf ( "\033[48;5;124m");//set color white text on red
printf ( "Invalid character");
printf ( "\033[0m");//reset to default colors
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
continue;
}
if ( ch == BACKSPACE) {
if ( psfield->inputat) {
psfield->inputat--;
//contract
for ( to = psfield->inputat; to <= psfield->used; to++) {
psfield->content[to] = psfield->content[to + 1];
}
psfield->used--;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == ESC) {
if ( !kbhit ( )) {
continue;
}
ch = getchar ( );
if ( ch == OTHER) {
ch = getchar ( );
if ( ch == HOME) {
psfield->inputat = 0;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
ch = getchar ( );
}
if ( ch == END) {
psfield->inputat = psfield->used;
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
ch = getchar ( );
}
}
if ( ch == BRACKETLEFT) {
ch = getchar ( );
if ( ch == INSERT) {
ch = getchar ( );
if ( ch == TILDE) {
psfield->insert = !psfield->insert;
printf ( "\033[%d;1H", psfield->lastline);
if ( psfield->insert) {
printf ( "INS");
}
else {
printf ( "OVW");
}
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == DELETE) {
ch = getchar ( );
if ( ch == TILDE) {
//contract
for ( to = psfield->inputat; to <= psfield->used; to++) {
psfield->content[to] = psfield->content[to + 1];
}
psfield->used--;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == ARROWRIGHT) {
if ( psfield->inputat < psfield->used) {
printf ( "\033[C");//cursor right
psfield->inputat++;
}
}
if ( ch == ARROWLEFT) {
if ( psfield->inputat) {
printf ( "\033[D");//cursor left
psfield->inputat--;
}
}
}
else {
ungetc ( ch, stdin);
}
}
}
return 0;
}
int main ( ) {
struct termios oldattr, newattr;
struct winsize w;
field sfield = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', NULL, NULL};
//set terminal
tcgetattr( STDIN, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN, TCSANOW, &newattr );
setbuf(stdin, NULL);
//get terminal dimensions
ioctl( 0, TIOCGWINSZ, &w );
sfield.lastline = w.ws_row;
sfield.lastcol = w.ws_col;
printf ( "\033[2J");//clear screen
sfield.row = 5;
sfield.col = 26;
sfield.promptrow = 5;
sfield.promptcol = 1;
sfield.stopon = '\n';//newline will end input
sfield.valid = LETTERS | SPACE | DOT;
sfield.contentsize = 40;//allowed length of input
if ( ( sfield.content = calloc ( sfield.contentsize, 1)) == NULL) {
printf ( "calloc failed\n");
return 1;
}
sfield.prompt = strdup ( "Enter letters or spaces:");
sfield.promptsize = strlen ( sfield.prompt) + 1;
strcpy ( sfield.content, "default");
sfield.used = strlen ( sfield.content);
prompt ( &sfield);
input ( &sfield);
printf ( "\n\ninput was [%s]\n", sfield.content);
printf ( "\n\nbye\n");
free ( sfield.content);
free ( sfield.prompt);
//restore terminal
tcsetattr( STDIN, TCSANOW, &oldattr );
return 0;
}