[feature request] Displaying input

26 views
Skip to first unread message

Marc Finet

unread,
Sep 28, 2011, 4:52:20 PM9/28/11
to PLAYTERM
Hi,

One nice feature of PLAYterm would be to display what recorder types
in his shell. So i quickly tried to hack ttyrec in order to produce a
ttyrecord.in that contains only 'input'. However, i noticed while
trying for instance a vim session a strange 'input', not initiated by
me:
$ ./ttyplay -t vim.in
1317238613:366180 "\x1b[>1;2801;0c"

It seems to be a response from vim's query "\x1b[>1c" according to
quick digging with vte part (http://git.gnome.org/browse/vte/tree/src/
caps.c#n469, http://git.gnome.org/browse/vte/tree/src/vteseq.c#n2508).
I do think that such values should be ignored, but while testing
(unmodified, i.e. debian's version) ttyplay it 'stopped' due to this
sequence; ttyrec recorded such a "\1b[1c" sequence (i.e. CSI[>c) and
terminals (either xfce4-terminal or xterm) responded on ttyin with the
above sequence (in fact my debian version of ttyplay has been linked
to an older version of libvte, hence version (2801 means version) was
different), but tty was stuck, and i had to enter '1' to continue
ttyplay (strace show that it was selecting only 'fd 0', i.e. stdin,
not 'fd 4', i.e. ttyrecord).

Anyway. the simple patch below does the following:
- add a -i switch to ttyrec to create a <ttyrecord>.in with input
recordings with same format as ttyrecord
- add a -t switch to ttyplay do 'nicely' timing and value display
from a record (hence interest comes when feeding it with
ttyrecord.in).

Now, for PLAYterm, i do not know how difficult it would be to add a
'subtitle' track that would display 'user input' (ignoring a subset of
'pure-terminal' entries). My dream would of course be something like a
'karaoke' mode, i.e. scrolling available inputs, and highlighting them
when being 'active'.

Regarding the ttyrec patch, my original approach was "simpliest", i.e.
to add both input and output in the same file but after failing i
realized:
- that in fact ttyrec created 3 processes (in fact, i started to
code without even reading the whole code :(...)
- no version or header is supported in current ttyrec, hence older
version would just 'stuck'
- this approach was simplest (as not dealing with concurrent access
to a file, modified file format, handling different types of events
(for ttyplay))
- maybe PLAYterm integration would be even simple with a 2-pass
process, 1 for output, 2 for input.

What do you think ?

Cheers,

Marc.


Patch against debian's version (reason was just that 'cvs' version was
not compiling):
--- ttyrec-1.0.8/ttyplay.c 2011-09-28 22:20:27.000000000 +0200
+++ ttyrec-with-input/ttyplay.c 2011-09-28 22:26:19.000000000 +0200
@@ -38,18 +38,18 @@
#include <termios.h>
#include <sys/time.h>
#include <string.h>
+#include <ctype.h>

#include "ttyrec.h"
#include "io.h"

-typedef double (*WaitFunc) (struct timeval prev,
- struct timeval cur,
+typedef double (*WaitFunc) (struct timeval prev,
+ struct timeval cur,
double speed);
typedef int (*ReadFunc) (FILE *fp, Header *h, char **buf);
-typedef void (*WriteFunc) (char *buf, int len);
-typedef void (*ProcessFunc) (FILE *fp, double speed,
+typedef void (*WriteFunc) (const char *buf, const Header *h);
+typedef void (*ProcessFunc) (FILE *fp, double speed,
ReadFunc read_func, WaitFunc wait_func);
-
struct timeval
timeval_diff (struct timeval tv1, struct timeval tv2)
{
@@ -166,10 +166,11 @@ ttyread (FILE *fp, Header *h, char **buf
if (*buf == NULL) {
perror("malloc");
}
-
+
if (fread(*buf, 1, h->len, fp) == 0) {
goto err;
}
+
return 1;

err:
@@ -200,19 +201,35 @@ ttypread (FILE *fp, Header *h, char **bu
}

void
-ttywrite (char *buf, int len)
+ttywrite (const char *buf, const Header *h)
+{
+ fwrite(buf, 1, h->len, stdout);
+}
+
+void
+ttywrite_time_raw(const char *buf, const Header *h)
{
- fwrite(buf, 1, len, stdout);
+ int i;
+ fprintf(stdout, "%ld:%ld\t\"", h->tv.tv_sec, h->tv.tv_usec);
+ for(i = 0; i < h->len; i++) {
+ if (isprint(buf[i])) {
+ fprintf(stdout, "%c", buf[i]);
+ } else {
+ fprintf(stdout, "\\x%02hhx", buf[i]);
+ }
+ }
+ fprintf(stdout, "\"\n");
}

void
-ttynowrite (char *buf, int len)
+ttynowrite (const char *buf, const Header *h)
{
/* do nothing */
}

+
void
-ttyplay (FILE *fp, double speed, ReadFunc read_func,
+ttyplay (FILE *fp, double speed, ReadFunc read_func,
WriteFunc write_func, WaitFunc wait_func)
{
int first_time = 1;
@@ -224,8 +241,9 @@ ttyplay (FILE *fp, double speed, ReadFun
while (1) {
char *buf;
Header h;
+ int rc;

- if (read_func(fp, &h, &buf) == 0) {
+ if ((rc = read_func(fp, &h, &buf)) == 0) {
break;
}

@@ -236,7 +254,7 @@ ttyplay (FILE *fp, double speed, ReadFun
}
first_time = 0;

- write_func(buf, h.len);
+ write_func(buf, &h);
prev = h.tv;
free(buf);
}
@@ -251,19 +269,25 @@ ttyskipall (FILE *fp)
ttyplay(fp, 0, ttyread, ttynowrite, ttynowait);
}

-void ttyplayback (FILE *fp, double speed,
+void ttyplayback (FILE *fp, double speed,
ReadFunc read_func, WaitFunc wait_func)
{
ttyplay(fp, speed, ttyread, ttywrite, wait_func);
}

-void ttypeek (FILE *fp, double speed,
+void ttypeek (FILE *fp, double speed,
ReadFunc read_func, WaitFunc wait_func)
{
ttyskipall(fp);
ttyplay(fp, speed, ttypread, ttywrite, ttynowait);
}

+void ttytime (FILE *fp, double speed,
+ ReadFunc read_func, WaitFunc wait_func)
+{
+ ttyplay(fp, speed, ttyread, ttywrite_time_raw, ttynowait);
+}
+

void
usage (void)
@@ -272,6 +296,7 @@ usage (void)
printf(" -s SPEED Set speed to SPEED [1.0]\n");
printf(" -n No wait mode\n");
printf(" -p Peek another person's ttyrecord\n");
+ printf(" -t Show timing info\n");
exit(EXIT_FAILURE);
}

@@ -287,7 +312,7 @@ input_from_stdin (void)
return efdopen(fd, "r");
}

-int
+int
main (int argc, char **argv)
{
double speed = 1.0;
@@ -299,7 +324,7 @@ main (int argc, char **argv)

set_progname(argv[0]);
while (1) {
- int ch = getopt(argc, argv, "s:np");
+ int ch = getopt(argc, argv, "s:npt");
if (ch == EOF) {
break;
}
@@ -317,6 +342,9 @@ main (int argc, char **argv)
case 'p':
process = ttypeek;
break;
+ case 't':
+ process = ttytime;
+ break;
default:
usage();
}
--- ttyrec-1.0.8/ttyrec.c 2011-09-28 22:20:27.000000000 +0200
+++ ttyrec-with-input/ttyrec.c 2011-09-28 22:18:55.000000000 +0200
@@ -95,6 +95,7 @@ void doshell(const char*);

char *shell;
FILE *fscript;
+FILE *fscript_in;
int master;
int slave;
int child;
@@ -110,8 +111,9 @@ int l;
char line[] = "/dev/ptyXX";
#endif
#endif /* !SVR4 */
-int aflg;
-int uflg;
+int aflg = 0;
+int uflg = 0;
+int in = 0;

static void
resize(int dummy) {
@@ -132,7 +134,7 @@ main(argc, argv)
char *getenv();
char *command = NULL;

- while ((ch = getopt(argc, argv, "aue:h?")) != EOF)
+ while ((ch = getopt(argc, argv, "aue:ih?")) != EOF)
switch((char)ch) {
case 'a':
aflg++;
@@ -140,13 +142,16 @@ main(argc, argv)
case 'u':
uflg++;
break;
+ case 'i':
+ in++;
+ break;
case 'e':
command = strdup(optarg);
break;
case 'h':
case '?':
default:
- fprintf(stderr, _("usage: ttyrec [-u] [-e command] [-a] [file]
\n"));
+ fprintf(stderr, _("usage: ttyrec [-u] [-e command] [-a] [-i] [file]
\n"));
exit(1);
}
argc -= optind;
@@ -162,6 +167,21 @@ main(argc, argv)
}
setbuf(fscript, NULL);

+ if (in) {
+ char *fname_in = malloc(strlen(fname) + sizeof(".in"));
+ if (!fname_in) {
+ perror("malloc");
+ fail();
+ }
+ strcpy(fname_in, fname);
+ strcat(fname_in, ".in");
+ if ((fscript_in = fopen(fname_in, aflg ? "a" : "w")) == NULL) {
+ perror(fname_in);
+ fail();
+ }
+ free(fname_in);
+ }
+
shell = getenv("SHELL");
if (shell == NULL)
shell = "/bin/sh";
@@ -179,6 +199,8 @@ main(argc, argv)
fail();
}
if (child == 0) {
+ if (fscript_in)
+ fclose(fscript_in);
subchild = child = fork();
if (child < 0) {
perror("fork");
@@ -199,18 +221,34 @@ main(argc, argv)
return 0;
}

+static int
+check_input(const char *str, int len)
+{
+ /* don't know (yet) when to 'forbid' input tracking */
+ return len;
+}
+
+
void
doinput()
{
register int cc;
char ibuf[BUFSIZ];
+ Header h;

(void) fclose(fscript);
#ifdef HAVE_openpty
(void) close(slave);
#endif
- while ((cc = read(0, ibuf, BUFSIZ)) > 0)
+ while ((cc = read(0, ibuf, BUFSIZ)) > 0) {
+ h.len = cc;
+ gettimeofday(&h.tv, NULL);
(void) write(master, ibuf, cc);
+ if ((cc = check_input(ibuf, cc)) && fscript_in) {
+ (void) write_header(fscript_in, &h);
+ (void) fwrite(ibuf, 1, cc, fscript_in);
+ }
+ }
done();
}

@@ -252,8 +290,8 @@ check_line (const char *line)
} else {
int dummy; char dummy2[BUFSIZ];
if (sscanf(line, "begin %o %s", &dummy, dummy2) == 2) {
- /*
- * uuencode line found!
+ /*
+ * uuencode line found!
*/
uudecode = popen("uudecode", "w");
fprintf(uudecode, "%s", line);
@@ -288,6 +326,7 @@ uu_check_output(const char *str, int len
}
}

+
static int
check_output(char *str, int len)
{
@@ -358,7 +397,7 @@ doshell(const char* command)
if (!command) {
execl(shell, strrchr(shell, '/') + 1, "-i", NULL);
} else {
- execl(shell, strrchr(shell, '/') + 1, "-c", command, NULL);
+ execl(shell, strrchr(shell, '/') + 1, "-c", command, NULL);
}
perror(shell);
fail();
--- ttyrec-1.0.8/ttytime.c 2006-06-11 17:52:50.000000000 +0200
+++ ttyrec-with-input/ttytime.c 2011-09-28 22:18:55.000000000 +0200
@@ -43,6 +43,7 @@ calc_time (const char *filename)
{
Header start, end;
FILE *fp = efopen(filename, "r");
+ end.tv.tv_sec = 0;

read_header(fp, &start);
fseek(fp, start.len, SEEK_CUR);

in...@leon.vankammen.eu

unread,
Nov 25, 2011, 8:12:40 AM11/25/11
to PLAYTERM
Hi,

I also mentioned this by email, but for the correctness lets also put
it here.

I think this is a great..no amazing feature, I've also looked for many
ways of doing this.
However, patching ttyrec also introduces another problem: forking off
the default ttyrec-branche.
I've tried to contact the maintainer but I could net get through.
Therefore, the first step in this feature would be contacting the
maintainer.
Because the fact everybody can just do 'emerge/apt-get ttyrec' is a
very low-obstacle operation, compilation from source not.

kind regards,

Leon

On 28 sep, 21:52, Marc Finet <m.dreadl...@gmail.com> wrote:
> Hi,
>
> One nice feature of PLAYterm would be to display what recorder types
> in his shell. So i quickly tried to hack ttyrec in order to produce a
> ttyrecord.in that contains only 'input'. However, i noticed while
> trying for instance a vim session a strange 'input', not initiated by
> me:
> $ ./ttyplay -t vim.in
> 1317238613:366180       "\x1b[>1;2801;0c"
>
> It seems to be a response from vim's query "\x1b[>1c" according to
> quick digging with vte part (http://git.gnome.org/browse/vte/tree/src/

> caps.c#n469,http://git.gnome.org/browse/vte/tree/src/vteseq.c#n2508).

Reply all
Reply to author
Forward
0 new messages