🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: microsoft.public.vc.language
9 messages
9 total messages Started by frank spencer Mon, 12 Jan 2004 17:09
choiceyn: cut down choice command, use of sleep, kbhit and getch
#6
Author: frank spencer
Date: Mon, 12 Jan 2004 17:09
92 lines
3700 bytes
Hello,

I have put this short program together and would like constructive comments
on what improvements could be made.

It works like the choice.com command on win98 with no parameters.

I am particularly concerned about  the use of sleep, kbhit and getch but any
other errors found would be appreciated.
It seems to work but  I'm guessing there are some naive assumptions in
there.

Thanks in advance for any help given

Hal
/*__________________________________________________________________________
_*/
/*__________________________________________________________________________
_*/
/*
 * choiceyn.c - emulates Win98's choice.com (with no parameters)
 * no warranty whatsoever given or implied.
 *
 * Hal Styli, 2004.
 */

#include <stdio.h>

#ifdef _MSC_VER
 #include <conio.h>
 #include <windows.h>
 #define KBHIT()  _kbhit()
 #define GETCH()  _getch()
 #define SLEEPX(s) Sleep((s)*1000)
#elif defined( __BORLANDC__ )
 #include <conio.h>
 #define KBHIT()  kbhit()
 #define GETCH()  getch()
 #define SLEEPX(s) _sleep(s)
#else
 #pragma message( "\n\n* * * U n t e s t e d * * *" )
 #pragma message( "This source has not been tested on this platform/with
this compiler" )
 #include "*** ERROR -- Untested environment ***\n\n"
#endif

#define BEEP '\a'
/*__________________________________________________________________________
_*/
/*__________________________________________________________________________
_*/

int main()
{
    char c;

    putchar('[');
    putchar('Y');
    putchar(',');
    putchar('N');
    putchar(']');
    putchar('?');

    for(;;)
    {
      if (KBHIT())
      {
        c=GETCH();
        if( (c=='Y') || (c=='y') )
    {
      putchar('Y');
      putchar('\n');
      return 1;
    }
 else
 if ( (c=='N') || (c=='n') )
    {
      putchar('N');
      putchar('\n');
      return 2;
    }
 else
     putchar(BEEP);
      }
      else
        SLEEPX(1);
    }
}
/*__________________________________________________________________________
_*/
/*__________________________________________________________________________
_*/
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#7
Author: Frank Hickman
Date: Mon, 12 Jan 2004 19:30
149 lines
5089 bytes
"frank spencer" <no_spam@all> wrote in message news:4002d4eb_5@127.0.0.1...
> Hello,
>
> I have put this short program together and would like constructive
comments
> on what improvements could be made.
>
> It works like the choice.com command on win98 with no parameters.
>
> I am particularly concerned about  the use of sleep, kbhit and getch but
any
> other errors found would be appreciated.
> It seems to work but  I'm guessing there are some naive assumptions in
> there.
>
> Thanks in advance for any help given
>
> Hal
>
/*__________________________________________________________________________
> _*/
>
/*__________________________________________________________________________
> _*/
> /*
>  * choiceyn.c - emulates Win98's choice.com (with no parameters)
>  * no warranty whatsoever given or implied.
>  *
>  * Hal Styli, 2004.
>  */
>
> #include <stdio.h>
>
> #ifdef _MSC_VER
>  #include <conio.h>
conio.h is in both MS and Borland, why have multiple lines.

>  #include <windows.h>
Not needed unless your also doing some SDK calls somewhere.

>  #define KBHIT()  _kbhit()
>  #define GETCH()  _getch()
MS has these defined without the leading _ so they already match Borland, no
need to seperate.

>  #define SLEEPX(s) Sleep((s)*1000)
Not needed, getch will wait for input.

> #elif defined( __BORLANDC__ )
>  #include <conio.h>
>  #define KBHIT()  kbhit()
>  #define GETCH()  getch()
>  #define SLEEPX(s) _sleep(s)
See comments above.

> #else
>  #pragma message( "\n\n* * * U n t e s t e d * * *" )
>  #pragma message( "This source has not been tested on this platform/with
> this compiler" )
>  #include "*** ERROR -- Untested environment ***\n\n"
This should be a #error directive not a #include one.
> #endif
>
> #define BEEP '\a'
>
/*__________________________________________________________________________
> _*/
>
/*__________________________________________________________________________
> _*/
>
> int main()
> {
>     char c;
>
>     putchar('[');
>     putchar('Y');
>     putchar(',');
>     putchar('N');
>     putchar(']');
>     putchar('?');
printf would add to much additional code for such a small utility however I
would write a function to output strings something like this...

void output( char* spString )
{
    while( *spString != '\0' )
        putchar( *spString++ );
}

so you could do this...

output( "[Y,N]? " );

makes your source more readable.

>
>     for(;;)
>     {
>       if (KBHIT())
>       {
>         c=GETCH();
>         if( (c=='Y') || (c=='y') )
>     {
>       putchar('Y');
>       putchar('\n');
>       return 1;
>     }
>  else
>  if ( (c=='N') || (c=='n') )
>     {
>       putchar('N');
>       putchar('\n');
>       return 2;
>     }
>  else
>      putchar(BEEP);
>       }
>       else
>         SLEEPX(1);
>     }
> }

I would write it something like this...

    for( ;; )
    {
        ch= getch();
        if ( ch == 'Y' || ch == 'y' || ch == 'N' || ch == 'n' )
        {
            putchar( ch );
            putchar( '\n' );
            return (ch == 'Y' || ch == 'y') ? 1 : 2;
        }
        else
        {
            // Test for special characters...
            if ( ch == '\0' || ch == 0xE0 )
                getch();    // Discard special keys (function, arrows,
etc.)...
            putchar( BEEP );
        }
    }

Just my two cents, of course when asking a question like this your bound to
get several different variations :)

--
Frank
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#8
Author: Hal Styli
Date: Tue, 13 Jan 2004 04:18
124 lines
4162 bytes
"Frank Hickman" <fhickman_nosp@m_noblesoft.com> wrote in message
news:uIWdnZPEO6ofaJ_dRVn-ig@comcast.com...
<<>>>
>
> Just my two cents, of course when asking a question like this your bound
to
> get several different variations :)
>
<<>>
Thanks Frank, much more than 2 cents worth, very useful.
I must admit I expected more takers wich such an inviting subject line!
I came up with one more variation myself taking your comments into
account...
and then added a timeout.

Any comments on the code below?

Hal.

/*
 * choiceyn.c - heavily cut down clone of Win98's CHOICE.COM.
 * The only parameter allowed is -t which works like '/t:y,05' does on
 * CHOICE.COM, otherwise works like 'CHOICE.COM' (i.e. with no arguments)
 *
 * No warranty whatsoever given or implied.
 *
 * v1.1, Hal Styli, 2004.
 */

#if !defined( _MSC_VER ) && !defined( __BORLANDC__ )
 #error This source has not otherkeyeen tested on this platform / with this
compiler
#endif

#include <stdio.h>
#include <conio.h>   /* for getch() */
#include <windows.h> /* for Sleep() */

#define WAITTIME 200
#define TIMEOUT (5*(1000/WAITTIME))

#define PR(s)  fputs(s,stdout)
#define PRE(s) fputs(s,stderr)

void yn();
int getargs(int argc, char **argv);

/*---------------------------------------------------*/
int main(int argc, char **argv )
{
    int t=0, otherkey=0;

    t=getargs(argc,argv);

    PR("[Y,N]?");

    if(t>0)
    {
       while(t--)
       {
          if (kbhit())
   {
             yn();
      otherkey=1;
      break;
   }

          Sleep(WAITTIME);
       }

       if (otherkey)  /* then revert to no timeout.*/
         for(;;)
            yn();
       {
  PR("Y\n");
  exit(1);
       }
    }
    else
       for(;;)
   yn();
}
/*---------------------------------------------------*/
void yn()
{
   switch(getch())
   {
      case 'y':  case 'Y':
        PR("Y\n");
        exit(1);
        /*break;*/
      case 'n': case 'N':
        PR("N\n");
        exit(2);
        /*break;*/
      default:
        putchar('\a'); /*beep*/
        break;
   }
}
/*---------------------------------------------------*/
int getargs(int argc, char **argv)
{
  int t=0;

    if(argc==2)
    {
 if( (argv[1][0]=='-') && (argv[1][1]=='t'))
           t= TIMEOUT;
  else
    t= -1;
    }
    else if(argc!=1)
 t= -1;

    if(t==-1)
    {
      PRE("\nInvalid argument in choiceyn command.\n");
      exit(255);
    }
    else
      return t;
}
/*---------------------------------------------------*/
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#9
Author: Frank Hickman
Date: Tue, 13 Jan 2004 05:55
137 lines
4852 bytes
Coming along, one thing sticks out though...in your yn() function your still
not handling special keys.  Run it and try pressing F1, you should hear two
beeps.  This is because getch() will return zero or 0xE0 for special keys in
which case getch() must be called again to get the extended key code.

--
Frank

"Hal Styli" <no_spam@all> wrote in message news:4003717f_5@127.0.0.1...
> "Frank Hickman" <fhickman_nosp@m_noblesoft.com> wrote in message
> news:uIWdnZPEO6ofaJ_dRVn-ig@comcast.com...
> <<>>>
> >
> > Just my two cents, of course when asking a question like this your bound
> to
> > get several different variations :)
> >
> <<>>
> Thanks Frank, much more than 2 cents worth, very useful.
> I must admit I expected more takers wich such an inviting subject line!
> I came up with one more variation myself taking your comments into
> account...
> and then added a timeout.
>
> Any comments on the code below?
>
> Hal.
>
> /*
>  * choiceyn.c - heavily cut down clone of Win98's CHOICE.COM.
>  * The only parameter allowed is -t which works like '/t:y,05' does on
>  * CHOICE.COM, otherwise works like 'CHOICE.COM' (i.e. with no arguments)
>  *
>  * No warranty whatsoever given or implied.
>  *
>  * v1.1, Hal Styli, 2004.
>  */
>
> #if !defined( _MSC_VER ) && !defined( __BORLANDC__ )
>  #error This source has not otherkeyeen tested on this platform / with
this
> compiler
> #endif
>
> #include <stdio.h>
> #include <conio.h>   /* for getch() */
> #include <windows.h> /* for Sleep() */
>
> #define WAITTIME 200
> #define TIMEOUT (5*(1000/WAITTIME))
>
> #define PR(s)  fputs(s,stdout)
> #define PRE(s) fputs(s,stderr)
>
> void yn();
> int getargs(int argc, char **argv);
>
> /*---------------------------------------------------*/
> int main(int argc, char **argv )
> {
>     int t=0, otherkey=0;
>
>     t=getargs(argc,argv);
>
>     PR("[Y,N]?");
>
>     if(t>0)
>     {
>        while(t--)
>        {
>           if (kbhit())
>    {
>              yn();
>       otherkey=1;
>       break;
>    }
>
>           Sleep(WAITTIME);
>        }
>
>        if (otherkey)  /* then revert to no timeout.*/
>          for(;;)
>             yn();
>        {
>   PR("Y\n");
>   exit(1);
>        }
>     }
>     else
>        for(;;)
>    yn();
> }
> /*---------------------------------------------------*/
> void yn()
> {
>    switch(getch())
>    {
>       case 'y':  case 'Y':
>         PR("Y\n");
>         exit(1);
>         /*break;*/
>       case 'n': case 'N':
>         PR("N\n");
>         exit(2);
>         /*break;*/
>       default:
>         putchar('\a'); /*beep*/
>         break;
>    }
> }
> /*---------------------------------------------------*/
> int getargs(int argc, char **argv)
> {
>   int t=0;
>
>     if(argc==2)
>     {
>  if( (argv[1][0]=='-') && (argv[1][1]=='t'))
>            t= TIMEOUT;
>   else
>     t= -1;
>     }
>     else if(argc!=1)
>  t= -1;
>
>     if(t==-1)
>     {
>       PRE("\nInvalid argument in choiceyn command.\n");
>       exit(255);
>     }
>     else
>       return t;
> }
> /*---------------------------------------------------*/
>
>
>
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#10
Author: Hal Styli
Date: Tue, 13 Jan 2004 07:44
49 lines
3770 bytes
"Frank Hickman" <fhickman_nosp@m_noblesoft.com> wrote in message
news:yJOdnaEvW6CsFZ7d4p2dnA@comcast.com...
> Coming along, one thing sticks out though...in your yn() function your
still
> not handling special keys.  Run it and try pressing F1, you should hear
two
> beeps.  This is because getch() will return zero or 0xE0 for special keys
in
> which case getch() must be called again to get the extended key code.
>
> --
> Frank
>
<<>>

Thanks Frank,

My version of CHOICE.COM on win98 gives 2 beeps when F1 is pressed, so I
think  I'll leave it unless you think I should be doing something special
with the special keys which I could put in as a non-standard extension.

No promises but Im close to a version 0.5 of  a full blown choice command
and would prefer to add no more features unless absolutely necessary to keep
maintenance  time to a minimum. I just wanted to port my bat files from 98
to xp and be confident that I would have the choice command available, as
well as humour myself with some C. I have seen a version in assembler on
google but no source was available.

Its gonna be 5-10 pages of code unless I have really underestimated how to
properly check parameters. At this sort of size, I think its too small to
stick on sourceforge but I would like to make it available as open source
and generate more interest and testing as I have had many queries about
where it has gone in xp. Is there an appropriate site you could reccomend ?

How about reducing its size? If I could get it down to a couple of kb I
would be tempted to stay with C for a final version.

Obvious ideas are:-
a) rewrite in assembler - which appeals to me since its an opportunity to
learn more assembler too. I guess I could start with the assembler out put
you can get from the compiler or keep hunting for an open source file as a
starting point. Anyway thats for another day and another newsgroup.
b) use all size optimization flags on compile
c) do some sort of squeeze and remove debug info
d) use some neat tricks that strip out unused code within these large exe
files. Im guessing there are some neat tricks!

Any thoughts?
Hal.
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#11
Author: Frank Hickman
Date: Tue, 13 Jan 2004 08:53
72 lines
4552 bytes
Yes, there are some tricks you can use to shrink the executable.  I don't
have my cheat sheet handy but you can probably find it in a google search.
I wasn't suggesting that you use the special keys, but you should test the
condition because in certain circumstances the second key code may be a y or
n and perhaps cause problems.  I used to use .bat and .cmd files allot in my
day to day operations, then I started messing around with scripting.  It's
definitely more powerful.

--
Frank

"Hal Styli" <no_spam@all> wrote in message news:4003a1fc_5@127.0.0.1...
> "Frank Hickman" <fhickman_nosp@m_noblesoft.com> wrote in message
> news:yJOdnaEvW6CsFZ7d4p2dnA@comcast.com...
> > Coming along, one thing sticks out though...in your yn() function your
> still
> > not handling special keys.  Run it and try pressing F1, you should hear
> two
> > beeps.  This is because getch() will return zero or 0xE0 for special
keys
> in
> > which case getch() must be called again to get the extended key code.
> >
> > --
> > Frank
> >
> <<>>
>
> Thanks Frank,
>
> My version of CHOICE.COM on win98 gives 2 beeps when F1 is pressed, so I
> think  I'll leave it unless you think I should be doing something special
> with the special keys which I could put in as a non-standard extension.
>
> No promises but Im close to a version 0.5 of  a full blown choice command
> and would prefer to add no more features unless absolutely necessary to
keep
> maintenance  time to a minimum. I just wanted to port my bat files from 98
> to xp and be confident that I would have the choice command available, as
> well as humour myself with some C. I have seen a version in assembler on
> google but no source was available.
>
> Its gonna be 5-10 pages of code unless I have really underestimated how to
> properly check parameters. At this sort of size, I think its too small to
> stick on sourceforge but I would like to make it available as open source
> and generate more interest and testing as I have had many queries about
> where it has gone in xp. Is there an appropriate site you could reccomend
?
>
> How about reducing its size? If I could get it down to a couple of kb I
> would be tempted to stay with C for a final version.
>
> Obvious ideas are:-
> a) rewrite in assembler - which appeals to me since its an opportunity to
> learn more assembler too. I guess I could start with the assembler out put
> you can get from the compiler or keep hunting for an open source file as a
> starting point. Anyway thats for another day and another newsgroup.
> b) use all size optimization flags on compile
> c) do some sort of squeeze and remove debug info
> d) use some neat tricks that strip out unused code within these large exe
> files. Im guessing there are some neat tricks!
>
> Any thoughts?
> Hal.
>
>
>
>
>
>
>
>
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#12
Author: Tim Roberts
Date: Wed, 14 Jan 2004 06:56
33 lines
2678 bytes
"Hal Styli" <no_spam@all> wrote:
>
>My version of CHOICE.COM on win98 gives 2 beeps when F1 is pressed, so I
>think  I'll leave it unless you think I should be doing something special
>with the special keys which I could put in as a non-standard extension.
>
>No promises but Im close to a version 0.5 of  a full blown choice command
>and would prefer to add no more features unless absolutely necessary to keep
>maintenance  time to a minimum. I just wanted to port my bat files from 98
>to xp and be confident that I would have the choice command available, as
>well as humour myself with some C.

You could just copy CHOICE.COM from Win98 and carry it with you.  It will
work just fine. in NT/2K/XP.

>How about reducing its size? If I could get it down to a couple of kb I
>would be tempted to stay with C for a final version.
>
>Obvious ideas are:-
>a) rewrite in assembler - which appeals to me since its an opportunity to
>learn more assembler too. I guess I could start with the assembler out put
>you can get from the compiler or keep hunting for an open source file as a
>starting point. Anyway thats for another day and another newsgroup.

If you keep it a Win32 app, going to assembler isn't going to reduce the
size.  There is almost no code in the program: the size is all in the
standard library.

However, if you did it as a 16-bit DOS app in assembler, you could make it
a true .COM and cut the size way down.
-- 
- Tim Roberts, timr@probo.com
  Providenza & Boekelheide, Inc
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#13
Author: Hal Styli
Date: Thu, 15 Jan 2004 12:21
140 lines
6028 bytes
I use WSH for scripting (as well as c++ ;o). I started the choice program to
ease porting win98 bat files that have been thoroughly tested.

Here is the final ( I think ) choiceyn.c,  I think it looks pretty good,
could be a cut down ASK.EXE from Norton too.

Its got line numbers so no need for long quotes...

All comments welcome

Hal
______________________________________
/*:  1:*/ /* choiceyn.c - heavily cut down clone of
/*:  2:*/ ** CHOICE.COM command found on Windows 98.
/*:  3:*/ **
/*:  4:*/ ** The only parameter allowed is -t which works like
/*:  5:*/ ** 'CHOICE /t:y,10' otherwise  works like
/*:  6:*/ ** 'CHOICE.COM' (i.e. with no arguments)
/*:  7:*/ **
/*:  8:*/ ** No warranty whatsoever given or implied.
/*:  9:*/ */
/*: 10:*/ #define VER "1.2a, Hal Styli, 2004"
/*: 11:*/
/*: 12:*/ #if !defined( _MSC_VER ) && !defined( __BORLANDC__ )
/*: 13:*/  #error Untested on this platform / with this compiler.
/*: 14:*/ #endif
/*: 15:*/
/*: 16:*/ #include <stdio.h>
/*: 17:*/ #include <conio.h>   /* for getch() & kbhit() */
/*: 18:*/ #include <windows.h> /* for Sleep() */
/*: 19:*/
/*: 20:*/ #define WAITTIME 200
/*: 21:*/ #define TIMEOUT (10*(1000/WAITTIME))
/*: 22:*/ #define PATHDELIM '\\'
/*: 23:*/ #define PR(s)  fputs(s,stdout)
/*: 24:*/ #define PRE(s) fputs(s,stderr)
/*: 25:*/ /*---------------------------------------------------*/
/*: 26:*/ char *fname(char *p)
/*: 27:*/    /*similar to fnsplit(p, NULL, NULL, name, NULL)
/*: 28:*/          and _splitpath(p, NULL, NULL, name, NULL) */
/*: 29:*/ {
/*: 30:*/  char *q;
/*: 31:*/
/*: 32:*/  while(q=strchr(p,PATHDELIM))
/*: 33:*/     p=q+1;
/*: 34:*/
/*: 35:*/  return p;
/*: 36:*/ }
/*: 37:*/ /*---------------------------------------------------*/
/*: 38:*/ int getargs(int argc, char **argv)
/*: 39:*/ {
/*: 40:*/   int t=0;
/*: 41:*/
/*: 42:*/     if(argc==2)
/*: 43:*/     {
/*: 44:*/  if( (argv[1][0]=='-') && (argv[1][1]=='t'))
/*: 45:*/            t= TIMEOUT;
/*: 46:*/   else
/*: 47:*/     t= -1;
/*: 48:*/     }
/*: 49:*/     else if(argc!=1)
/*: 50:*/  t= -1;
/*: 51:*/
/*: 52:*/     if(t==-1)
/*: 53:*/     {
/*: 54:*/       PRE("-----------------------------------------\n");
/*: 55:*/       PRE("\n  Error! Format is: '");
/*: 56:*/       PRE(fname(*argv));
/*: 57:*/       PRE(" [-t]'.  \n\n  [version: " VER "].\n\n");
/*: 58:*/       PRE("-----------------------------------------\n");
/*: 59:*/       exit(255);
/*: 60:*/     }
/*: 61:*/     else
/*: 62:*/       return t;
/*: 63:*/
/*: 64:*/  /* to stop compiler warning...*/
/*: 65:*/   return 0;
/*: 66:*/ }
/*: 67:*/ /*---------------------------------------------------*/
/*: 68:*/ void yn(void)
/*: 69:*/ {
/*: 70:*/    switch(getch())
/*: 71:*/    {
/*: 72:*/       case 'y':  case 'Y':
/*: 73:*/         PR("Y\n");
/*: 74:*/         exit(1);
/*: 75:*/         /*break;*/
/*: 76:*/       case 'n': case 'N':
/*: 77:*/         PR("N\n");
/*: 78:*/         exit(2);
/*: 79:*/         /*break;*/
/*: 80:*/
/*: 81:*/    /* Discard special keys (function, arrows,etc.)...?*/
/*: 82:*/    /* maybe necessary but seems to work without for me
/*: 83:*/       case '\0': case 0xE0:
/*: 84:*/         getch();
/*: 85:*/    */
/*: 86:*/       default:
/*: 87:*/         putchar('\a'); /*beep*/
/*: 88:*/         break;
/*: 89:*/    }
/*: 90:*/ }
/*: 91:*/ /*---------------------------------------------------*/
/*: 92:*/ int main(int argc, char **argv )
/*: 93:*/ {
/*: 94:*/     int t, otherkey=0;
/*: 95:*/
/*: 96:*/     t=getargs(argc,argv);
/*: 97:*/
/*: 98:*/     PR("[Y,N]?");
/*: 99:*/
/*:100:*/     if(t>0)
/*:101:*/     {
/*:102:*/        while(t--)
/*:103:*/        {
/*:104:*/           if (kbhit())
/*:105:*/    {
/*:106:*/              yn();
/*:107:*/       otherkey=1;
/*:108:*/       break;
/*:109:*/    }
/*:110:*/
/*:111:*/           Sleep(WAITTIME);
/*:112:*/        }
/*:113:*/
/*:114:*/        if (otherkey)  /* then revert to no timeout.*/
/*:115:*/          for(;;)
/*:116:*/             yn();
/*:117:*/        {
/*:118:*/   PR("Y\n");
/*:119:*/   exit(1);
/*:120:*/        }
/*:121:*/     }
/*:122:*/     else
/*:123:*/        for(;;)
/*:124:*/    yn();
/*:125:*/
/*:126:*/  /* to stop compiler warning...*/
/*:127:*/  return 0;
/*:128:*/ }
Re: choiceyn: cut down choice command, use of sleep, kbhit and getch
#14
Author: Hal Styli
Date: Thu, 15 Jan 2004 13:39
7 lines
1897 bytes
"Hal Styli" <no_spam@all> wrote in message news:400685d3_5@127.0.0.1...
>
> Its got line numbers so no need for long quotes...
>

Strictly there should be an 'else' between  lines 116 and 117 but works fine
without.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads