Keyboard input/Obtain a Y or N response: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 190: Line 190:


=={{header|EGL}}==
=={{header|EGL}}==
{{Works with|EDT}}

{{Works with|EDT|RBD}}
{{Works with|RBD}}
{{Works with|EDT and RBD}}
<lang EGL>handler YesOrNoHandler type RUIhandler{initialUI =[ui], onConstructionFunction = start}
<lang EGL>handler YesOrNoHandler type RUIhandler{initialUI =[ui], onConstructionFunction = start}



Revision as of 20:41, 4 October 2012

Task
Keyboard input/Obtain a Y or N response
You are encouraged to solve this task according to the task description, using any language you may know.

Obtain a valid Y or N response from the keyboard. The keyboard should be flushed, so that any outstanding keypresses are removed, preventing any existing Y or N keypress from being evaluated. The response should be obtained as soon as Y or N are pressed, and there should be no need to press an enter key.

Ada

<lang Ada> function Yes_Or_No (Prompt : String := "Your answer (Y/N): ") return Boolean is

     Answer : Character;
  begin
     Ada.Text_IO.Put (Prompt);
     loop
        Ada.Text_IO.Get_Immediate (Answer);
        case Answer is
           when 'Y'|'y' => return True;
           when 'N'|'n' => return False;
           when others  => null;
        end case;
     end loop;
  end Yes_Or_No;</lang>

AutoHotkey

<lang AutoHotkey>#NoEnv ; Recommended for increased performance Input, Response,,,y,n

Waits until they press y or n, storing all characters.

StringRight, Out, Response, 1

retrieves the ending character (which will be y or n)

Msgbox %out% If (Out = "y")

   Msgbox You pressed Y

If (Out = "n")

   Msgbox You pressed n

ExitApp </lang>

BASIC

Applesoft BASIC

<lang applesoftbasic>10 LET C = PEEK (49168): REM CLEAR KEYBOARD 20 PRINT "PRESS Y OR N TO CONTINUE" 30 GET K$ 40 IF K$ < > "Y" AND K$ < > "N" THEN 30 50 PRINT "THE RESPONSE WAS ";K$ </lang>

Locomotive Basic

<lang locobasic>10 CLEAR INPUT 20 PRINT "Press Y or N to continue" 30 a$=LOWER$(INKEY$) 40 IF a$="" THEN 30 50 IF a$="y" THEN PRINT "Yes":END 60 IF a$="n" THEN PRINT "No":END 70 PRINT "Try again" 80 GOTO 30</lang>

ZX Spectrum Basic

Note that this will also work in GW-BASIC and most QBasic-compatible BASICs if all instances of "GO TO" are changed to "GOTO".

<lang qbasic>10 IF INKEY$<>"" THEN GO TO 10: REM flush the keyboard buffer 20 PRINT "Press Y or N to continue" 30 LET k$ = INKEY$ 40 IF k$ <> "y" AND k$ <> "Y" AND k$ <> "n" AND k$ <> "N" THEN GO TO 30 50 PRINT "The response was "; k$</lang>

C

For POSIX compliant systems (in theory that includes WinNT family). <lang C>#include <stdio.h>

  1. include <stdio.h>
  2. include <termios.h>
  3. include <unistd.h>
  4. include <fcntl.h>

void set_mode(int want_key) { static struct termios old, new; if (!want_key) { tcsetattr(STDIN_FILENO, TCSANOW, &old); return; }

tcgetattr(STDIN_FILENO, &old); new = old; new.c_lflag &= ~(ICANON); tcsetattr(STDIN_FILENO, TCSANOW, &new); }

int get_key(int no_timeout) { int c = 0; struct timeval tv; fd_set fs; tv.tv_usec = tv.tv_sec = 0;

FD_ZERO(&fs); FD_SET(STDIN_FILENO, &fs);

select(STDIN_FILENO + 1, &fs, 0, 0, no_timeout ? 0 : &tv); if (FD_ISSET(STDIN_FILENO, &fs)) { c = getchar(); set_mode(0); } return c; }

int main() { int c; while(1) { set_mode(1); while (get_key(0)); /* clear buffer */ printf("Prompt again [Y/N]? "); fflush(stdout);

c = get_key(1); if (c == 'Y' || c == 'y') { printf("\n"); continue; }

if (c == 'N' || c == 'n') { printf("\nDone\n"); break; }

printf("\nYes or no?\n"); }

return 0; }</lang>

C#

<lang c sharp>using System;

namespace Y_or_N {

   class Program
   {
       static void Main()
       {
           bool response = GetYorN();
       }
       static bool GetYorN()
       {
           ConsoleKey response; // Creates a variable to hold the user's response.
           do
           {
               while (Console.KeyAvailable) // Flushes the input queue.
                   Console.ReadKey();
               Console.Write("Y or N? "); // Asks the user to answer with 'Y' or 'N'.
               response = Console.ReadKey().Key; // Gets the user's response.
               Console.WriteLine(); // Breaks the line.
           } while (response != ConsoleKey.Y && response != ConsoleKey.N); // If the user did not respond with a 'Y' or an 'N', repeat the loop.
            /* 
             * Return true if the user responded with 'Y', otherwise false.
             * 
             * We know the response was either 'Y' or 'N', so we can assume 
             * the response is 'N' if it is not 'Y'.
             */
           return response == ConsoleKey.Y;
       }
   }

}</lang>

Common Lisp

<lang lisp>(defun rosetta-y-or-n ()

 (clear-input *query-io*)
 (y-or-n-p))</lang>

Euphoria

<lang Euphoria>integer key

puts(1,"Your answer? (Y/N)\n") while get_key()!=-1 do end while

while 1 do

   key = get_key()
   if key!=-1 and (key = 'Y' or key = 'y' or key = 'N' or key = 'n') then
       exit
   end if

end while

printf(1,"Your response was %s\n",key)</lang>

EGL

Works with: EDT
Works with: RBD

<lang EGL>handler YesOrNoHandler type RUIhandler{initialUI =[ui], onConstructionFunction = start}

   ui Div { };
   const KEY_N int = 78;
   const KEY_Y int = 89;
   function start()
   	document.onKeyDown = d_onKeyDown;
   end
   
   function d_onKeyDown(e Event in)

case (e.ch)

 	    when (KEY_N)

ui.innerText = "N pressed."; when (KEY_Y) ui.innerText = "Y pressed."; end

e.preventDefault();

   end

end</lang>

Forth

<lang Forth>: flush ( -- ) \ discard pending input

 begin key? while key drop repeat ;
y-or-n ( c-addr u -- f )
 flush begin
   cr 2dup type key bl or                  \ note 1.
   dup [char] y = swap [char] n = over or  \ note 2.
   if nip nip exit then
 drop again ;

\ Note 1. KEY BL OR returns a lowercase letter in the case that an \ uppercase letter was entered, an unchanged lowercase letter in the \ case that a lowercase letter was entered, and garbage otherwise. BL \ returns the ASCII code for a space, 32, which is incidentally the \ "bit of difference" between ASCII uppercase and lowercase letters.

\ Note 2. this line has the stack effect ( x -- f1 f2 ), where F1 is \ true only if x='y', and F2 is true only if x='y' OR if x='n'.

\ I think these expressions aren't too clever, but they _are_ rather \ optimized for the task at hand. This might be more conventional:

y-or-n ( c-addr u -- f )
 flush begin
   cr 2dup type key case
     [char] y of 2drop true  exit endof
     [char] Y of 2drop true  exit endof
     [char] n of 2drop false exit endof
     [char] N of 2drop false exit endof
 endcase again ;</lang>

GW-BASIC

<lang qbasic>10 IF INKEY$<>"" THEN GOTO 10: REM flush the keyboard buffer 20 PRINT "Press Y or N to continue" 30 LET k$ = INKEY$ 40 IF k$ <> "y" AND k$ <> "Y" AND k$ <> "n" AND k$ <> "N" THEN GOTO 30 50 PRINT "The response was "; k$</lang>

Icon and Unicon

This solution works in both Icon and Unicon. It also accepts y or n. <lang unicon>procedure main()

   write("Response was ",getResponse("OK? (Y or N): "))

end

procedure getResponse(prompt)

   while kbhit() do getch()   # flush input
   writes(prompt)
   repeat if map(answer := getch()) == ("y"|"n") then break
   return answer

end</lang>

Inform 7

Keyboard input goes through a virtual machine that's only required to provide blocking input operations, so flushing the buffer isn't possible.

Inform 7 has a built-in function to ask the user for yes-or-no input, but it requires them to press enter afterward: <lang inform7>Qwantz is a room.

When play begins: say "A wizard has turned you into a whale. Is this awesome (Y/N)? "; if the player consents, say "Awesome!"; end the story.</lang>

To read a single key without waiting for enter, we can redefine the function by including a snippet of Inform 6 code: <lang inform7>To decide whether player consents: (- (YesOrNoKey()) -).

Include (- [ YesOrNoKey ch;

   do { ch = VM_KeyChar(); } until (ch == 'y' or 'Y' or 'n' or 'N');
   return ch == 'y' or 'Y';

]; -).</lang>

Liberty BASIC

<lang lb> nomainwin open "Y/N" for graphics_nsb_nf as #1

  1. 1 "trapclose Quit"
  2. 1 "down;setfocus;when characterInput KeyCheck"
  3. 1 "place 10 50;\Press Y or N"

Inkey$="" wait

sub KeyCheck hndle$,k$

   k$=upper$(k$)
   #hndle$ "cls;place 10 50"
   select case k$
       case "Y"
       #hndle$ "\ Yes"
       case "N"
       #hndle$ "\No"
       case else
       #hndle$ "\Incorrect input. Press Y or N"
       end select
   end sub

sub Quit hndle$

   close #hndle$
   end
   end sub
</lang>

OpenEdge/Progress

<lang progress>DEF VAR lanswer AS LOGICAL INITIAL ?.

DO WHILE lanswer = ?:

  READKEY.
  IF CHR( LASTKEY ) = "n" OR CHR( LASTKEY ) = "y" THEN
     lanswer = CHR( LASTKEY ) = "y".

END.

MESSAGE lanswer VIEW-AS ALERT-BOX.</lang>

Pascal

Works with: Free_Pascal
Library: CRT

<lang pascal>Program ObtainYN;

uses

 crt;

var

 key: char;

begin

 write('Your answer? (Y/N): ');
 repeat
   key := readkey;
 until (key in ['Y', 'y', 'N', 'n']);
 writeln;
 writeln ('Your answer was: ', key);

end.</lang> Output:

% ./ObtainYN
Your answer? (Y/N): 
Your answer was: y

Perl

<lang perl>use Term::ReadKey;

ReadMode 4; # change to raw input mode

my $key = ;

while($key !~ /(Y|N)/i) {

   1 while defined ReadKey -1; # discard any previous input
   print "Type Y/N: ";
   $key = ReadKey 0; # read a single character
   print "$key\n";

}

ReadMode 0; # reset the terminal to normal mode

print "\nYou typed: $key\n"; </lang>

PicoLisp

<lang PicoLisp>(de yesno ()

  (loop
     (NIL (uppc (key)))
     (T (= "Y" @) T)
     (T (= "N" @)) ) )</lang>

PureBasic

Inkey() returns the character string of the key which is being pressed at the time. <lang PureBasic>PrintN("Press Y or N to continue")

Repeat

 ; Get the key being pressed, or a empty string.
 Key$=UCase(Inkey())
 ;
 ; To Reduce the problems with an active loop
 ; a Delay(1) will release the CPU for the rest
 ; of this quanta if no key where pressed.
 Delay(1)

Until Key$="Y" Or Key$="N" PrintN("The response was "+Key$)</lang>

Python

<lang python>#!/usr/bin/env python

try:

   from msvcrt import getch

except ImportError:

   def getch():
       import sys, tty, termios
       fd = sys.stdin.fileno()
       old_settings = termios.tcgetattr(fd)
       try:
           tty.setraw(sys.stdin.fileno())
           ch = sys.stdin.read(1)
       finally:
           termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
       return ch

print "Press Y or N to continue" while True:

   char = getch()
   if char.lower() in ("y", "n"):
       print char
       break</lang>
   

Retro

<lang Retro>

 : y|n ( -c )
   "\nPress Y or N..." puts
   0 [ drop getc dup [ 'Y <> ] [ 'N <> ] bi and ] while cr ;

</lang>

REXX

version 1

REXX (in general) requires the user to press ENTER when entering text.
This is because (IBM) REXX was designed and written in a time when all I/O to a user's terminal was in
block mode and required the user to press one of the following before any data was sent to the computer:

  • the ENTER key
  • A PF (program function key)
  • A PA (program assist key)
  • the ATTN (attention) key
  • possibly some other special key(s)


Some REXX interpreters have a keyboard read subroutine so that the program can
read keyboard keys as they are pressed (see version 2 below). <lang rexx>/*REXX program to test for a Y or N key when pressed. */

 do queued(); pull; end               /*flush stack if anything queued.*/

prompt='Press Y or N (and then ENTER).' /*prompt message*/

 do forever;  say             /*write a blank line for visual fidelity.*/
 say prompt                   /*prompt the user for an input.          */
 pull ans .                   /*get the answer,  also,   uppercase it. */
 if pos(ans,'NY')\==0 then leave                 /*if ans is OK, leave.*/
 end
                              /*as this point, ANS holds a   Y  or  N. */</lang>

version 2

This version of a REXX program works with PC/REXX. <lang rexx>/*REXX program to test for a Y or N key when pressed. */ prompt='Press Y or N for some reason.' /*prompt message*/

 do forever; say              /*write a blank line for visual fidelity.*/
 say prompt                   /*prompt the user for an input.          */
 ans=inkey('wait'); upper ans /*get the answer(s), also, uppercase it. */
 if pos(ans,'NY')\==0 then leave                 /*if ans is OK, leave.*/
 end
                              /*as this point, ANS holds a   Y  or  N. */</lang>

Ruby

<lang Ruby> def yesno

 begin
   system("stty raw -echo")
   str = STDIN.getc
 ensure
   system("stty -raw echo")
 end
 if str == "Y"
   return true
 elsif str == "N"
   return false
 else
   raise "Invalid character."
 end

end </lang>

Run BASIC

<lang runbasic>[loop] cls ' Clear screen html "Click Y or N" ' no other options

     button #y, "Y", [Y]                '   they either click [Y]
     button #n, "N", [N]                '   or they click [N]

html "
";msg$ ' print message showing what they entered wait [Y] msg$ = "You entered [Y]es": goto [loop] [N] msg$ = "You entered [N]o" : goto [loop] </lang>

Seed7

<lang seed7>$ include "seed7_05.s7i";

 include "keybd.s7i";

const func boolean: yesOrNo (in string: prompt) is func

 result
   var boolean: yes is FALSE;
 local
   var char: answer is ' ';
 begin
   while keypressed(KEYBOARD) do
     ignore(getc(KEYBOARD));
   end while;
   write(prompt);
   repeat
     answer := lower(getc(KEYBOARD));
   until answer in {'y', 'n'};
   yes := answer = 'y';
 end func;

const proc: main is func

 begin
   writeln(yesOrNo("Press Y or N to continue "));
 end func;</lang>

Tcl

Using the console (expects U*Xish stty)

<lang tcl>proc yesno Template:Message "Press Y or N to continue" {

   fconfigure stdin -blocking 0
   exec stty raw
   read stdin ; # flush
   puts -nonewline "${message}: "
   flush stdout
   while {![eof stdin]} {
       set c [string tolower [read stdin 1]]
       if {$c eq "y" || $c eq "n"} break
   }
   puts [string toupper $c]
   exec stty -raw
   fconfigure stdin -blocking 1
   return [expr {$c eq "y"}]

}

set yn [yesno "Do you like programming (Y/N)"]</lang>

Without a console (answer in the global variable yn; this should work in any GUI for which there is a TCL):

<lang tcl> proc yesno {message} {

 toplevel .msg 
 pack [label .msg.l -text "$message\n (type Y/N)?"]
 set ::yn ""
 bind .msg <Key-y> {set ::yn "Y"}
 bind .msg <Key-n> {set ::yn "N"}
 vwait ::yn
 destroy .msg

}

yesno "Do you like programming?"

</lang>

XPL0

<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations loop [OpenI(1); \flush any pending keystroke

       case ChIn(1) of         \get keystroke
        ^Y,^y: Text(0, "yes");
        ^N,^n: Text(0, "no");
        $1B:   quit            \Esc key terminates program
       other ChOut(0, 7\bel\);
       CrLf(0);
       ]</lang>