如何使用 ioctl 获取终端的宽度和高度?
Posted
技术标签:
【中文标题】如何使用 ioctl 获取终端的宽度和高度?【英文标题】:How do I get width and height of my terminal with ioctl? 【发布时间】:2010-11-26 14:37:20 【问题描述】:我必须改变什么才能使它工作?
#!/usr/bin/perl
use 5.012;
use warnings;
require "/usr/lib/perl5/vendor_perl/5.12.1/x86_64-linux-thread-multi/sys/ioctl.ph";
my ($rows, $cols, $xpix, $ypix);
my $winsize = "\0" x 8;
my $TIOCGWINSZ = 0x40087468; # should be require sys/ioctl.pl
if (ioctl(STDOUT, $TIOCGWINSZ, $winsize))
($rows, $cols, $xpix, $ypix) = unpack('S4', $winsize);
else
say "something didn't work" and exit;
灵感来自tchrist's answer in From column to row。
【问题讨论】:
你真的有一个正确安装了sys/ioctl.ph
的系统吗?哪一个?
【参考方案1】:
要获取行数和列数,我这样做:
#!/usr/bin/perl
use strict;
use warnings;
my $cols = 80;
my $rows = 24;
for (`stty -a`)
/columns ([0-9]+);/ and do if ($1 > 0) $cols = $1; ;
/rows ([0-9]+);/ and do if ($1 > 0) $rows = $1; ;
print "cols=$cols\trows=$rows\n";
【讨论】:
【参考方案2】:为什么不直接使用Term::Size
?这使用了ioctl()
方法,包裹在漂亮整洁的 XS 代码中,所有这些都可以从 Perl 中使用。
【讨论】:
【参考方案3】:Term::ReadKey
有一个内置的方法来检索终端的大小,它supports a range of different terminals 包括 Windows。考虑到sheer number of modules on CPAN that use this module,您可能已经安装了它。
#!/usr/bin/perl -w
use strict;
use Term::ReadKey qw/ GetTerminalSize /;
my @winsize = &GetTerminalSize(\*STDOUT);
my ($cols, $rows, $xpix, $ypix) = @winsize;
print "cols:$cols rows:$rows xpix:$xpix ypix:$ypix\n";
【讨论】:
【参考方案4】:这对我来说很好用:
#!perl
use strict;
use warnings;
require 'sys/ioctl.ph';
my $winsize = ""; # Silence warning
if (ioctl(STDOUT, TIOCGWINSZ() , $winsize))
my ($rows, $cols, $xpix, $ypix) = unpack 'S4', $winsize;
print join ":", $rows, $cols, $xpix, $ypix;
print "\n";
else
warn "Something didn't work.\n";
require 不需要(也不应该有)完整路径; TIOCGWINSZ 已经通过加载 ioctl 标头进行了定义,并且没有迹象表明必须将目标标量初始化为正确的大小(尽管如果根本没有初始化,perl 会抛出警告,因为它似乎无法识别特殊的 @ 987654322@-like ioctl 的性质,所以我将它设置为 "" 只是为了让它安静)。
【讨论】:
您会发现很少系统实际安装了sys/ioctl.ph
文件。【参考方案5】:
另一种方法是让 C 告诉你TIOCGWINSZ
的值是什么。还不如让它告诉你另一个参数的大小,当你在它的时候。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
int
main(argc, argv)
int argc;
char *argv[];
struct winsize mywinsize;
int ttyfd;
if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY)) == -1)
perror("open /dev/tty");
exit(-1);
if (ioctl(ttyfd, TIOCGWINSZ, &mywinsize) == -1)
perror("ioctl TIOCGWINSZ");
exit(-1);
printf("TIOCGWINSZ %#08lx\n", TIOCGWINSZ );
printf("sizeof struct winsize %lu\n", sizeof(struct winsize) );
printf("rows %d\n", mywinsize.ws_row );
printf("cols %d\n", mywinsize.ws_col );
if (fclose(stdout) == EOF)
perror("close stdout");
exit(-1);
exit(0);
也许某个善良的灵魂会告诉你如何为你将其包装在Inline::C
中,但与此同时,这应该就足够了。请注意,这是一个可移植的程序,因为它可以在 ̲b̲o̲t̲h̲ 类型的系统上运行:
☺ BSD ☺
OpenBSD% cc getwinsz.c && a.out
TIOCGWINSZ 0x40087468
sizeof struct winsize 8
rows 81
cols 166
Darwin% cc getwinsz.c && a.out
TIOCGWINSZ 0x40087468
sizeof struct winsize 8
rows 37
cols 126
☹ SysV ☹
Slolaris% cc getwinsz.c && a.out
TIOCGWINSZ 0x005468
sizeof struct winsize 8
rows 37
cols 126
Leenooxe% cc getwinsz.c && a.out
TIOCGWINSZ 0x005413
sizeof struct winsize 8
rows 37
cols 126
【讨论】:
以上是关于如何使用 ioctl 获取终端的宽度和高度?的主要内容,如果未能解决你的问题,请参考以下文章