Board index » delphi » Page up -- extended keys

Page up -- extended keys

Cut and paste sure does help to propagate errors :)

In the previous post I wrote:

Quote
>            Readkey := Char(128 + Ord(Readkey))
and
>            Readkey := Ord(Readkey) shl 8

these should have been:

        Readkey := Char(128 + Ord(CRT.Readkey))
        Readkey := Ord(CRT.Readkey) shl 8

Hopefully everyone that tried them would recognize what was wrong,
especially when the stack overflowed.  

Do I get I got half credit for having qualified the earlier
reference to readkey in each of the routines? :D

    ...red

 

Re:Page up -- extended keys


Quote
>I want to use PgDown key in my program: ask for a key (char) and
>determine if it is PgDown or something else.  Unlike this similar
>program I enclose, I don't do it in a cycle there, because I want
>to ask for a key only once.
>The thing is, that PgDown, like some other keys, has two ascii
>values: 0 and 81.  Letter Q has a value of 81, so how do I make
>a difference between Q and PgDown?

here is a little function I wrote called ext --

function ext : string
   var
      st1,st2 : string;
   begin
      st1 := '';
      st2 := '';
      if keypressed then
         begin
            st1 := readkey;
            if keypressed then
               st2 := readkey;
         end;
      ext := st1 + st2;
   end;

then use ext instead of readkey, and imply a case statement like this

   tst := ext;
   if tst[1] = #0 then
      case tst[2] of
         'Q' : <page up code>

Re:Page up -- extended keys


In article <Pine.ULT.3.91.960725112829.261B-100...@sqruhs.ruhs.uwm.edu>

Quote
scott wisniewski wrote:
>>I want to use PgDown key in my program: ask for a key (char) and
>>determine if it is PgDown or something else.  Unlike this similar
>>program I enclose, I don't do it in a cycle there, because I want
>>to ask for a key only once.
>>The thing is, that PgDown, like some other keys, has two ascii
>>values: 0 and 81.  Letter Q has a value of 81, so how do I make
>>a difference between Q and PgDown?  

Actually it has a char value of #0 and scan code of 81.  All keys
have scan codes, with them it is possible to know exactly which key
was pressed.  e.g. Did the character '5' come from the keypad or from
the top row of keys?  Did that ^C come from Ctrl+C or was it entered
through the numeric keypad with ALT+3?

Keyboard interrupt 16h returns a word (hi-byte=scan code and
lo-byte=char value) which DOS and TP saves and returns the character
value.  On a subsequent call Readkey will check the previous character,
and if zero will save and return the scan code as the next character.

An old solution used to set the hi-bit of scan codes as in the
following:

   Procedure ReadKey: Char;
   VAR c: Char;
   Begin
       c := CRT.Readkey;
       if c = #0 then
        Readkey := Char(128 + Ord(Readkey))
       Else Readkey := c;
   End;

In this example Q = #81 and PgDn = #128 + #81 = #209
            or  Q = #$51 and PgDn = #$80 + #$51 = #$D1

This will work most of the time, however there will be some overlap
in ALT and function keys.  But that's what happens when your container
is too small.  You do know what a blivot is, don't you?

Another solution is to have readkey return a word, as in the
following:

   Procedure ReadKey: Word;
   VAR c: Char;
   Begin
       c := CRT.Readkey;
       if c = #0 then
        Readkey := Ord(Readkey) shl 8
       Else Readkey := Ord(c);
   End;

This will separate characters from alt and function keys w/no
overlap.  The only difference between this and the value returned
by interrupt 16h is that characters will have scan code of zero.  

Using this method, PgDn will have a value of $5100 and Q $0051.
A typical case statement would be

    key := ReadKey;
    Case Key of
       $5100: DoPageDown;
       $000D: DoEnter;
       ...
    Else
       Case Char(Key) of
          ' '..'~': --- process ascii character
       End;
    End;

I doubt that any solution will do everything that you want.  The
value 81 derives its meaning from the context in which it is used.  
When read from the keyboard it is a PgDn key if it was preceded by
a #0, and a 'Q' otherwise.  In other contexts it could just as easily
be an 81 or a push CX instruction.  

I'm not certain why you and others are so unwilling to create a
nested case so that you can be sensitive to function keys and know
the context that you are currently working under.  

Quote

>here is a little function I wrote called ext --

>function ext : string
>   var
>      st1,st2 : string;
>   begin
>      st1 := '';
>      st2 := '';
>      if keypressed then
>         begin
>            st1 := readkey;
>            if keypressed then
>               st2 := readkey;
>         end;
>      ext := st1 + st2;
>   end;

This is bad :(  Suppose I use this routine and while the program is
busy doing something the user starts typing.  When the task is
complete the routine finds multiple keys in the buffer, hence
keypressed is true and two _normal_ characters are returned.  Since
two characters will be returned in this situation as well as when a
function key is pressed I must now examine the characters to determine
if I have two characters, a function key, or a normal character and
the nul (#0) from a function key whose scan code will be returned on
the next call.

Quote
>then use ext instead of readkey, and imply a case statement like this

>   tst := ext;
>   if tst[1] = #0 then
>      case tst[2] of
>         'Q' : <page up code>

          #0  : opps -- I have the start of a function key that
                will be processed as a characetr on the next
                go-around  ;(

    ...red

Re:Page up -- extended keys


In article <4t9dng$...@news-e2d.gnn.com>,
R. E. Donais  <RDon...@gnn.com> wrote:

Quote

>An old solution used to set the hi-bit of scan codes as in the
>following:

>   Procedure ReadKey: Char;
>   VAR c: Char;
>   Begin
>       c := CRT.Readkey;
>       if c = #0 then
>            Readkey := Char(128 + Ord(Readkey))
>       Else Readkey := c;
>   End;

>In this example Q = #81 and PgDn = #128 + #81 = #209
>            or  Q = #$51 and PgDn = #$80 + #$51 = #$D1

That does not work for text entry though. In text entry one has to
accept extended ascii characters.

Quote
>This will work most of the time, however there will be some overlap
>in ALT and function keys.  But that's what happens when your container
>is too small.  You do know what a blivot is, don't you?

>Another solution is to have readkey return a word, as in the
>following:

>   Procedure ReadKey: Word;
>   VAR c: Char;
>   Begin
>       c := CRT.Readkey;
>       if c = #0 then
>            Readkey := Ord(Readkey) shl 8
>       Else Readkey := Ord(c);
>   End;

Why not put readkey:=256+ord(crt.readkey)? In that way the codes would
be nicely from 1 to 511. One should also define constants for each of
the codes. The main program should not care of the presentation of the
keystrokes

Quote

>This will separate characters from alt and function keys w/no
>overlap.  The only difference between this and the value returned
>by interrupt 16h is that characters will have scan code of zero.  

>Using this method, PgDn will have a value of $5100 and Q $0051.
>A typical case statement would be

>    key := ReadKey;
>    Case Key of
>       $5100: DoPageDown;
>       $000D: DoEnter;

What I mean is one should code:

       PgDn: DoPageDown;
         13: DoEnter:

- Show quoted text -

Quote
>       ...
>    Else
>       Case Char(Key) of
>          ' '..'~': --- process ascii character
>       End;
>    End;

>I doubt that any solution will do everything that you want.  The
>value 81 derives its meaning from the context in which it is used.  
>When read from the keyboard it is a PgDn key if it was preceded by
>a #0, and a 'Q' otherwise.  In other contexts it could just as easily
>be an 81 or a push CX instruction.  

>I'm not certain why you and others are so unwilling to create a
>nested case so that you can be sensitive to function keys and know
>the context that you are currently working under.  

I do not like the nested cases because for the function of the program,
it is irrelevant whether the code is Alt_A or Chrl_A, those should be
handled in the same way. I might even want that those two have same
function, in which case it would be nice to specify them in same case
statement.

Some people may say that large cases are not good and the readkey forces
structuring, but that is like saying that 64K segments force good
programs.

Unit Keys;

Interface

Uses Crt;

Type KeyType=word;

Function KeyStroke:Keytype;

Const Offset=256;

      F1=59+Offset;
      F2=60+Offset;
      F3=61+Offset;
      F4=62+Offset;
      F5=63+Offset;
      F6=64+Offset;
      F7=65+Offset;
      F8=66+Offset;
      F9=67+Offset;
      F10=68+Offset;

      Shift_F1=84+Offset;
      Shift_F2=85+Offset;
      Shift_F3=86+Offset;
      Shift_F4=87+Offset;
      Shift_F5=88+Offset;
      Shift_F6=89+Offset;
      Shift_F7=90+Offset;
      Shift_F8=91+Offset;
      Shift_F9=92+Offset;
      Shift_F10=93+Offset;

      Ctrl_F1=94+Offset;
      Ctrl_F2=95+Offset;
      Ctrl_F3=96+Offset;
      Ctrl_F4=97+Offset;
      Ctrl_F5=98+Offset;
      Ctrl_F6=99+Offset;
      Ctrl_F7=100+Offset;
      Ctrl_F8=101+Offset;
      Ctrl_F9=102+Offset;
      Ctrl_F10=103+Offset;

      Alt_F1=104+Offset;
      Alt_F2=105+Offset;
      Alt_F3=106+Offset;
      Alt_F4=107+Offset;
      Alt_F5=108+Offset;
      Alt_F6=109+Offset;
      Alt_F7=110+Offset;
      Alt_F8=111+Offset;
      Alt_F9=112+Offset;
      Alt_F10=113+Offset;

      Alt_1=120+Offset;
      Alt_2=121+Offset;
      Alt_3=122+Offset;
      Alt_4=123+Offset;
      Alt_5=124+Offset;
      Alt_6=125+Offset;
      Alt_7=126+Offset;
      Alt_8=127+Offset;
      Alt_9=128+Offset;
      Alt_0=129+Offset;

      Alt_A=30+Offset;
      Alt_B=48+Offset;
      Alt_C=46+Offset;
      Alt_D=32+Offset;
      Alt_E=18+Offset;
      Alt_F=33+Offset;
      Alt_G=34+Offset;
      Alt_H=35+Offset;
      Alt_I=23+Offset;
      Alt_J=36+Offset;
      Alt_K=37+Offset;
      Alt_L=38+Offset;
      Alt_M=50+Offset;
      Alt_N=49+Offset;
      Alt_O=24+Offset;
      Alt_P=25+Offset;
      Alt_Q=16+Offset;
      Alt_R=19+Offset;
      Alt_S=31+Offset;
      Alt_T=20+Offset;
      Alt_U=22+Offset;
      Alt_V=47+Offset;
      Alt_W=17+Offset;
      Alt_X=45+Offset;
      Alt_Y=21+Offset;
      Alt_Z=44+Offset;

      Alt_Hyphen=130+Offset;
      Alt_Equals=131+Offset;

      Shift_Tab=15+Offset;

      Home=71+Offset;
      Up=72+Offset;
      PgUp=73+Offset;
      Left=75+Offset;
      Right=77+Offset;
      End_=79+Offset;
      Down=80+Offset;
      PgDn=81+Offset;
      Ins=82+Offset;
      Del=83+Offset;

      Ctrl_PrtSc=114+Offset;

      Ctrl_Left=115+Offset;
      Ctrl_Right=116+Offset;
      Ctrl_End=117+Offset;
      Ctrl_PgDn=118+Offset;
      Ctrl_Home=119+Offset;
      Ctrl_PgUp=132+Offset;

      Ctrl_A=1;
      Ctrl_B=2;
      Ctrl_C=3;
      Ctrl_D=4;
      Ctrl_E=5;
      Ctrl_F=6;
      Ctrl_G=7;
      Ctrl_H=8;
      Ctrl_I=9;
      Ctrl_J=10;
      Ctrl_K=11;
      Ctrl_L=12;
      Ctrl_M=13;
      Ctrl_N=14;
      Ctrl_O=15;
      Ctrl_P=16;
      Ctrl_Q=17;
      Ctrl_R=18;
      Ctrl_S=19;
      Ctrl_T=20;
      Ctrl_U=21;
      Ctrl_V=22;
      Ctrl_W=23;
      Ctrl_X=24;
      Ctrl_Y=25;
      Ctrl_Z=26;
      ESC=27;

Implementation

Function KeyStroke:Keytype;
var c:word;
Begin
  c:=ord(readkey);
  if c=0 then c:=offset+ord(readkey);
  Keystroke:=c;
End;

end.

Re:Page up -- extended keys


Quote
In article <4tdqfs$...@kruuna.Helsinki.FI> Osmo Ronkanen wrote:
>In article <4t9dng$...@news-e2d.gnn.com>,
>R. E. Donais  <RDon...@gnn.com> wrote:

>>An old solution used to set the hi-bit of scan codes as in the
>>following:

>>   Procedure ReadKey: Char;
>>   VAR c: Char;
>>   Begin
>>       c := CRT.Readkey;
>>       if c = #0 then
>>        Readkey := Char(128 + Ord(CRT.Readkey))
>>       Else Readkey := c;
>>   End;

>>In this example Q = #81 and PgDn = #128 + #81 = #209
>>            or  Q = #$51 and PgDn = #$80 + #$51 = #$D1

>That does not work for text entry though. In text entry one has to
>accept extended ascii characters.

This might not work for you, but if the original post came from the
US like I thought it might, it will probably work fine.  I had
assumed that anyone needing hi-order ascii would recognize the short
coming of this technique. You have to admit that for those that don't
need anything more than ASCII-7 and can live with the overlap of a
few ALT and function keys, it is a workable and worthwhile solution.

- Show quoted text -

Quote

>>This will work most of the time, however there will be some overlap
>>in ALT and function keys.  But that's what happens when your container
>>is too small.  You do know what a blivot is, don't you?

>>Another solution is to have readkey return a word, as in the
>>following:

>>   Procedure ReadKey: Word;
>>   VAR c: Char;
>>   Begin
>>       c := CRT.Readkey;
>>       if c = #0 then
>>        Readkey := Ord(CRT.Readkey) shl 8
>>       Else Readkey := Ord(c);
>>   End;

>Why not put readkey:=256+ord(crt.readkey)? In that way the codes would
>be nicely from 1 to 511. One should also define constants for each of
>the codes. The main program should not care of the presentation of the
>keystrokes

I agree that this is a solution, but I don't really see it as having
any particular advantage over the previously described solution.  
Since all keys should be defined as constants it doesn't really
matter if PgDn = $5100, or PgDn = $0151.  It simply becomes a matter
of preference.

- Show quoted text -

Quote

>>This will separate characters from alt and function keys w/no
>>overlap.  The only difference between this and the value returned
>>by interrupt 16h is that characters will have scan code of zero.  

>>Using this method, PgDn will have a value of $5100 and Q $0051.
>>A typical case statement would be

>>    key := ReadKey;
>>    Case Key of
>>       $5100: DoPageDown;
>>       $000D: DoEnter;

>What I mean is one should code:

>       PgDn: DoPageDown;
>         13: DoEnter:

>>       ...
>>    Else
>>       Case Char(Key) of
>>          ' '..'~': --- process ascii character
>>       End;
>>    End;

In practice key declarations should incldue control keys as well
as function keys -
CONST
   CR = 13;
   LF = 10;
   BS = 08;
   SP = 32;
  TAB = 09;
  ESC = 27;
 HOME = $4700;
 ENDE = $4F00;
  ....etc

Quote
>>I doubt that any solution will do everything that you want.  The
>>value 81 derives its meaning from the context in which it is used.  
>>When read from the keyboard it is a PgDn key if it was preceded by
>>a #0, and a 'Q' otherwise.  In other contexts it could just as easily
>>be an 81 or a push CX instruction.  

>>I'm not certain why you and others are so unwilling to create a
>>nested case so that you can be sensitive to function keys and know
>>the context that you are currently working under.  

>I do not like the nested cases because for the function of the program,
>it is irrelevant whether the code is Alt_A or Chrl_A, those should be
>handled in the same way. I might even want that those two have same
>function, in which case it would be nice to specify them in same case
>statement.

I agree with you Osmo, that's why my ReadKey returns the scan code
and key value from int 16h.  By using it or any of the previous
methods, there is no difference in the type variable used for AltA
or ctrlA. And by using const declarations their numerical value also
becomes irrelevant.

However, I assumed that the original post was from a student who
couldn't grasp the idea of data having context and thought it more
appropriate to hint on going with the flow rather than make more
problems.

Quote

>Some people may say that large cases are not good and the readkey forces
>structuring, but that is like saying that 64K segments force good
>programs.

You won't catch me arguing here!  

BTW, in my keyboard unit I declared a word "TC" which receives the
current keystroke.  By making it global rather than local I can use
ReadKey in a case statement w/o having to first save the key so that
it can be recalled later.  Some purists might find it objectionable,
but IMO saving the keystroke has to be done much too often, so I
chose to do it at a lower level.

   ...red

Other Threads