Solved

unbuffered input

Posted on 1998-12-04
38
412 Views
Last Modified: 2010-04-15
How can I get unbuffered input from the keyboard, and be able to check if there is no key being pressed when I call it? I will be useing DOS.
0
Comment
Question by:aiwa
  • 23
  • 8
  • 5
  • +2
38 Comments
 
LVL 16

Expert Comment

by:imladris
Comment Utility
Both unbuffered input, and checking if a key has been pressed are system specific actions. Systems do offer such functionality, but it will not be portable.

Please indicate which operating system you are working in.

0
 

Author Comment

by:aiwa
Comment Utility
Edited text of question
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
You can use the kbhit function (in conio.h) to test if a key is being pressed.  If a key is pressed, true is returned.  Then you can use getch to determine what the key was.  If no key was pressed, false is returned and you can go on with your program.  Here is some sample code.  (I know that kbhit is available in Borland C, I am not sure about others.  Its worth a try.)



#include <stdio.h>
#include <conio.h>

void main()
{
  char x;

  while (x!='x') if (kbhit()) {x = getch();   printf("%c key pressed.\n",x);}
  else printf("No key pressed.\n");
}
0
 

Author Comment

by:aiwa
Comment Utility
Thanks.
So why when I hit a key and keep my hand on it do my program not produce a continuous tone, which stops when I lift the key?


#include <dos.h>
#include <conio.h>
#include <ctype.h>

void playnote(unsigned int note)
{
      sound(note);
      delay(20);
            if(note == 0){
            nosound();
            }

}

int main()
{
char note;

      do{

      if (kbhit()){
            note = getch();
      }
      else
                                    note = 0;

      note = toupper(note);

            switch(note)
            {
                  case 'S' :
                         playnote(254);
                  break;

                  case 'D' :
                         playnote(297);
                  break;

                  case 'F' :
                         playnote(330);
                  break;

                  case 'G' :
                         playnote(352);
                  break;

                  case 'H' :
                         playnote(396);
                  break;

                  case 'J' :
                         playnote(440);
                  break;

                  case 'K' :
                         playnote(495);
                  break;

                  case 'L' :
                         playnote(528);
                  break;
            }
      }
      while(note != 'Q');

return 0;
}
0
 

Author Comment

by:aiwa
Comment Utility
Thanks.
So why when I hit a key and keep my hand on it do my program not produce a continuous tone, which stops when I lift the key?


#include <dos.h>
#include <conio.h>
#include <ctype.h>

void playnote(unsigned int note)
{
      sound(note);
      delay(20);
            if(note == 0){
            nosound();
            }

}

int main()
{
char note;

      do{

      if (kbhit()){
            note = getch();
      }
      else
                                    note = 0;

      note = toupper(note);

            switch(note)
            {
                  case 'S' :
                         playnote(254);
                  break;

                  case 'D' :
                         playnote(297);
                  break;

                  case 'F' :
                         playnote(330);
                  break;

                  case 'G' :
                         playnote(352);
                  break;

                  case 'H' :
                         playnote(396);
                  break;

                  case 'J' :
                         playnote(440);
                  break;

                  case 'K' :
                         playnote(495);
                  break;

                  case 'L' :
                         playnote(528);
                  break;
            }
      }
      while(note != 'Q');

return 0;
}
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
You are doing nothing to turn the sound off.  Your playsound function turns off the sound if the note is zero, but I you never seem to call playsound(0).

Why don't you change this line:

else
                                    note = 0;


to this:

else {note = 0; playsound(0);}  
0
 
LVL 16

Expert Comment

by:imladris
Comment Utility
>  So why when I hit a key and keep my hand on it do my program not produce a continuous tone?

The answer to that question is that the keyboard does not continuously send characters when a key is down. If you observe the behaviour you get in a word processor, you will notice that when you depress a key you get a single instance of the character, followed by a pause, followed by a stream of the character at some set rate.
kbhit allows you to determine if there is a character there for getch to get. Neither it, nor getch are geared to do what you wish to do namely: make the keyboard behave like a musical instrument by reporting on the state of the key (pressed or unpressed).
You might be able to fake it, if you can use the delay in playnote to pause longer than it takes the keyboard to produce another character. This will, of course, be at the expense of a certain amount of responsiveness of the program. I.e. When you release a key, it will not stop sounding for up to the full delay time specified.

To do that you would have to process the raw scancodes as they come in, in some fashion. They come with a "make" or "break" code indicating the state of the key. But accomplishing that will be a much bigger job.

0
 

Author Comment

by:aiwa
Comment Utility
OK Thanks that fixes the not turning off problem but why is there that little pause at the start of a long note, I have set the keyboards repeat delay and repeat rate both to max. How can I get a continuously tone.
Sorry if you think I am just using ye to debug my code but I don't know how to overcome these problems.
0
 
LVL 16

Expert Comment

by:imladris
Comment Utility
Sorry, that got garbled somehow. The last paragraph should have been up a bit:

>  So why when I hit a key and keep my hand on it do my program not produce a continuous tone?

The answer to that question is that the keyboard does not continuously send characters when a key is down. If you observe the behaviour you get in a word processor, you will notice that when you depress a key you get a single instance of the character, followed by a pause, followed by a stream of the character at some set rate.
kbhit allows you to determine if there is a character there for getch to get. Neither it, nor getch are geared to do what you wish to do namely: make the keyboard behave like a musical instrument by reporting on the state of the key (pressed or unpressed).
To do that you would have to process the raw scancodes as they come in, in some fashion. They come with a "make" or "break" code indicating the state of the key. But accomplishing that will be a much bigger job.

You might be able to fake it, if you can use the delay in playnote to pause longer than it takes the keyboard to produce another character. This will, of course, be at the expense of a certain amount of responsiveness of the program. I.e. When you release a key, it will not stop sounding for up to the full delay time specified.

0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
One other thing, take out the delay(20).
0
 

Author Comment

by:aiwa
Comment Utility
OK
Where can I find eather code for a simple music program, or the code that imladris is talking about. I searched under C CODE and could find nothing.
0
 

Author Comment

by:aiwa
Comment Utility
OK
Where can I find eather code for a simple music program, or the code that imladris is talking about. I searched under C CODE and could find nothing.
0
 

Author Comment

by:aiwa
Comment Utility
I cannot turn off the delay as I would get a good pitch (good as the system speker goes:)
0
 

Author Comment

by:aiwa
Comment Utility
I cannot turn off the delay as I would get a good pitch (good as the system speker goes:)
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
Searched under "c code" where?
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 

Author Comment

by:aiwa
Comment Utility
I used the WebFerret it uses about 14 search engens, I hoped people would have there code on the net.
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
Why did you post 6 times?

Searching for "c code" is way too general.  You're going to get hundreds of thousands of sites.

I will be on the lookout for programs like this.  Meanwhile, try this:



void main()
{
  asm {
       start:  call getkey
                        cmp al,1bh
                        jne skip
                        jmp done
       skip:   call beep
                        jmp start
       getkey: mov ah,7
                        int 21h
                        ret

       beep:   mov bl,al
                        mov al, 0b6h
                        out 42h+1,al
                        mov al,0
                        out 42h,al
                        mov al,bl
                        out 42h,al
                        mov al,4fh
                        out 61h,al
                        mov cx,0ffffh
                        rep lodsw
                        mov al,4dh
                        out 61h,al
                        mov ah,2
                        mov dl,0eh
                        int 21h
                        ret
       done:
  }


}

0
 

Author Comment

by:aiwa
Comment Utility
Thanks scrapdog, can you explain it a little?

Sorry about the meny postings, I have beening hitting reload and for some reasion that must resend the date
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
It is assembly language...I just threw this together as an experiment...probably not what you want, but this is the easiest way to access ports and the keyboard directly.

I will keep looking for source code that will be more understandable.
0
 

Author Comment

by:aiwa
Comment Utility
I have done a little assembly language, So if you can stick in a few comments or tell me where I can fine an instuction set. I've worked with the 68HC11. Do these instruction work with all CPU's ?
0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
int calls an interrupt, out sends data to a port (in this case ports $42 and $61 are of interest to us if we want to manipulate the speaker), mov is "move" which is self-explanatory, jne is branch if not equal, cmp is compare, ret is return.  I don't think if I could convert that to 68HC11, but hopefully you get an idea what these instructons do.  These instructions will only run on an Intel 80x86 compatible CPU.
0
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
Hello guys.

Why don't ya try this one??

#include <dos.h>
#include <conio.h>
#include <ctype.h>

void playnote(unsigned int note)
{
      sound(note);
      if (note == 0)
            nosound();
      delay(100);
}

int main()
{
      char note;
      do{
            kbhit() ? note = getch() : note = 0;
            switch(toupper(note)) {
                  case 'S' : playnote(254); break;
                  case 'D' : playnote(297); break;
                  case 'F' : playnote(330); break;
                  case 'G' : playnote(352); break;
                  case 'H' : playnote(396); break;
                  case 'J' : playnote(440); break;
                  case 'K' : playnote(495); break;
                  case 'L' : playnote(528); break;
                  default  : playnote(0);
            }
      } while (note != 'Q');
      return 0;
}

Hope this helps!

Cheers,
Viktor
0
 

Author Comment

by:aiwa
Comment Utility
This dos not fix the first dealy problem, I want to be able to "play it like a instrument". So if someone can send towards code that will do that for me.
0
 

Author Comment

by:aiwa
Comment Utility
Adjusted points to 210
0
 
LVL 1

Expert Comment

by:billyh
Comment Utility
Try the following code. Just copy and paste the code and compile it. Scrapdog, I don't think its a good idea to use Assembler because when compiling the code in a UNIX environment the program will not work. Also there are ports functions in C that you can use, like 'outp' in "CONIO.H". This will make the code more portable.

#include "conio.h"
#include "ctype.h"
#include "dos.h"

void main()
{
      void play_selection(char);

      char note;
      
      do
      {
            if (kbhit()) note = toupper(getch());
            play_selection(note);

      } while (note != 'Q');
}

void play_selection(char call_var)
{
      void playnote(unsigned int);
      
      switch(call_var)
      {
            case 'S':playnote(254); break;
            case 'D':playnote(297); break;
            case 'F':playnote(330); break;
            case 'G':playnote(352); break;
            case 'H':playnote(396); break;
            case 'J':playnote(440); break;
            case 'K':playnote(495); break;
            case 'L':playnote(548); break;
            default: playnote(0); break;
      }
}

void playnote(unsigned int note)
{
      if (!note) sound(0);  /* Plays no sound OR
                         Whatever sound you choose*/
      else
      {
            sound(note);
            delay(4);
      }
      nosound();
}

0
 

Author Comment

by:aiwa
Comment Utility
Agin that dos not do waht I want it to do, previous code was better, and this program will never see UNIX, a pity I accept but thats life!   I want an instrument like response, If this is not achievable through C than suggest alternatives. If not I think the points should go to schrapdog
0
 

Author Comment

by:aiwa
Comment Utility
Agin that dos not do waht I want it to do, previous code was better, and this program will never see UNIX, a pity I accept but thats life!   I want an instrument like response, If this is not achievable through C than suggest alternatives. If not I think the points should go to schrapdog
0
 

Author Comment

by:aiwa
Comment Utility
Oh NO it's bubbling posting on me agin!!
0
 
LVL 16

Accepted Solution

by:
imladris earned 210 total points
Comment Utility
Well aiwa, you seem determined, so here is the stuff I use to get keyboard scan codes directly. As you'll see, the requirement can be fulfilled by hooking the keyboard interrupt, and processing the scan codes directly. Accomplishing this requires assembler. Getting it to work will be fraught with many difficulties, not the least of which is that most kind of mistakes will deprive you of your keyboard (since you hooked the interrupt away). Running a debugger on this is next to impossible for the same reason. However, for the sake of showing that it can be done, and how I give you the following code:

First, here is a dirty method pair for hooking the interrupt:

#include "conio.h"

void turn_int(int,int);
void poke(int,int,char *,int);

#define ON   1
#define OFF  0


void patch(n,a)
int n;
int (*a)();

{   turn_int(n,OFF);
    poke(0,(n<8?0x20:0x1a0)+n*4,(char *)&a,4);
    turn_int(n,ON);
    return;
}


void turn_int(n,s)
int n,s;

{   int i;

    if(n==-1)
    {   outp(0x21,0xff);
        return;
    }
    i=inp(n<8?0x21:0xa1);
    if(s==OFF)i|=1<<(n-(n<8?0:8));
    else i&= ~(1<<(n-(n<8?0:8)));
    outp(n<8?0x21:0xa1,i);      /* Engineeringly a 0 enables and a 1 disables */
    return;
}


You really should use the dos interrupts for get and set vector. However, explaining the dos interrupt vector API is yet another lengthy process. You should also extend this to get the current contents of the interrupt vector, so that you can restore it before your program exits (or you won't have any keyboard control left).
This could be done with the peek routine.

Here is the interrupt and helper routines to use:

        public  _markkbd,_waskbd,_rstkbd,_kbdisr,_kbspk,_kbdsc
_markkbd proc   far
        push    ax
        mov     cs:kbdinp,1             ; set touched marker
        mov     al,020h                 ; send eoi
        out     020h,al
        pop     ax
        iret
_markkbd endp

_waskbd proc    far
        mov     ax,cs:kbdinp
        ret
_waskbd endp

_rstkbd proc    far
        mov     cs:kbdinp,0             ; set marker
        ret
_rstkbd endp


You use this by calling waskbd to see if a key was hit. If it was, reset the interrupt flag and read the keyboard port:

    rstkbd();
    k=inp(0x60);

k will contain the scan code from the keyboard. Each key on the keyboard has a 7 bit scan code associated with it. For your purposes suffice it to say that Q is 16, A is 30 and Z is 44, and the keys to their right increase by 1 (e.g. W is 17, E is 18 etc.).
The top bit in the scan code is make or break. Make (key pressed) is 0, break (key released) is 1.

Good Luck!

0
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
It would probably be a good idea to make an array of booleans for the keys pressed.  For example, when a make code is received, set the corresponding element in the array to TRUE, and when a break code is received, set it to FALSE.

And when you get to your play routine, check to see which keys are down by checking this array of booleans.  Play the sound the corresponds to the FIRST key that has a value of true.

The reason for this is that if you rely simply on the make and break codes, ANY break code will turn the sound off.  For example, lets say you press A and hold it down, and then your press S a millsecond before you let up on the A key;  the make code from the S will cause the S note to be played, but then the break code from the A will immediately shut it off.

If you use the method of using an array, you would only shut off the sound if ALL values in the array are false, i.e. NO key is down.

Using an array will also allow you to recognize if more than one key is down, if you wanted to be able to play more than one note at a time.  The PC speaker can only play one note at a time, but you could simulate two or more notes by arpeggiating them.  The best way to arpeggiate is to use the timer interrupt.
0
 

Author Comment

by:aiwa
Comment Utility
I got it to work at last!! Thanks for all your help!!!
0
 
LVL 16

Expert Comment

by:imladris
Comment Utility
I am truely impressed you got it to work! I'm bemused in that case as to why you gave me a D for the answer. Did you use someone else's information?

0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now