read keyboard?

Programming, for all ages and all languages.
Post Reply
User avatar
Lionel
Member
Member
Posts: 117
Joined: Fri Jul 16, 2010 2:16 pm
Libera.chat IRC: ryanel
Location: California

read keyboard?

Post by Lionel »

Hello,
I been trying to find a way for getting input from the keyboard. I don't mean getting the input and scan codes from the keyboard, but getting the input from after, say... readline(); is called and taking the output from readline() to the appropriate piece of code. I was a .net developer before a os developer, so I have always been sheltered by Console.Readline();. I tthought of a way to do it, but it would put readline in a infinite loop because reading could never be updated because it's waiting for it to change. I honestly can't find a solution, so could you help me osdev community?
~Lionel
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: read keyboard?

Post by Combuster »

In other words, you are saying you can't use the getkey() and putc() functions you seem to already have to emulate a command prompt?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Lionel
Member
Member
Posts: 117
Joined: Fri Jul 16, 2010 2:16 pm
Libera.chat IRC: ryanel
Location: California

Re: read keyboard?

Post by Lionel »

No, I can get keyboard input by redirecting the input from my keyboard handler, but I can't find a clean way to get the input in handled.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: read keyboard?

Post by Solar »

The Usual Diagnostic Message: Not Enough User Space Experience.

Try yourself at some userspace C. Don't jump into the deep waters of OS development before you learned to swim (without .NET water wings).

For one, documentation and help is much easier to come by for userspace.
Every good solution is obvious once you've found it.
User avatar
Lionel
Member
Member
Posts: 117
Joined: Fri Jul 16, 2010 2:16 pm
Libera.chat IRC: ryanel
Location: California

Re: read keyboard?

Post by Lionel »

I got it somewhat working:
readch();

Code: Select all

unsigned char readch()
{
    readingch=1;
    while (readingch==1)// readingch is set to 0 in keyboard handler
    {
    }
    if (readchar=="\n"){return 0;}
    if (readchar=="\b"){return 0;}
    return readchar;
}
reads();

Code: Select all

unsigned char *reads()
{
    unsigned char *buffer="";
    unsigned char charbuffer="";
    readings=1;
    while (readings==1 & readchar !="\n")
    {

         buffer=+readch();
         puts(buffer);
    }
    return buffer;
}
But I stumbled into another problem:Image
It seems that prints part of memory, but I can't find the bug in the code. Could someone help me with this problem please?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: read keyboard?

Post by bluemoon »

Hints:
1) buffer=+readch(); // buffer = +{0 ~ 255}
2) You are comparing char * string using == operator, which compares their address instead of content.
3) You use bitwise and where you actually would like logical and

ps. There are more errors not mentioned, which contributed to roughly 80% of the lines of your code...
User avatar
Lionel
Member
Member
Posts: 117
Joined: Fri Jul 16, 2010 2:16 pm
Libera.chat IRC: ryanel
Location: California

Re: read keyboard?

Post by Lionel »

Hmm. I got it working finally!
Thanks to bluemoon's first hint. I got it. Thanks bluemoon!

Code: Select all

unsigned char *reads()
{
    unsigned char *buffer="";
    int buffer_charnum=0;
    unsigned char input="";
    readings=1;
    while (readings==1)
    {
         input=readch();
         if (input==0xD)
         {
             break;
         }
         
         buffer[buffer_charnum]=input;
         buffer_charnum+=1;
    }
    return buffer;
}
p.s:I was going to get it to work, then fix errors and improve it's performance.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: read keyboard?

Post by Brendan »

Hi,
Lionel wrote:

Code: Select all

unsigned char *reads()
{
    unsigned char *buffer="";
    int buffer_charnum=0;
    unsigned char input="";
    readings=1;
    while (readings==1)
    {
         input=readch();
         if (input==0xD)
         {
             break;
         }
         
         buffer[buffer_charnum]=input;
         buffer_charnum+=1;
    }
    return buffer;
}
That is unbelievably wrong.

For C, string literals are created in the ".data" or ".rodata" section and only enough space for the string (e.g. 1 byte in your case) is reserved for it. This means as soon as you put anything in the buffer you trash other data (unless your OS happens to honour the read only attribute of the ".rodata" section and you get a page fault instead, which would be much better in this case as it'd prevent other data being trashed).
Lionel wrote:

Code: Select all

unsigned char readch()
{
    readingch=1;
    while (readingch==1)// readingch is set to 0 in keyboard handler
    {
    }
    if (readchar=="\n"){return 0;}
    if (readchar=="\b"){return 0;}
    return readchar;
}
This is badly wrong too. The "readingch" variable should be volatile (expect it to fail as soon as you compile with optimisations enabled); and nothing prevents the "readchar" variable from being changed (by the keyboard IRQ handler) multiple times before it's read (expect to lose keypresses).

On top of this, you're missing a fundamental understanding of how it should work.

For a single-tasking system; the keyboard IRQ handler should place data into a queue; and your "readch()" function should do something like "while( queue_is_empty() ) { __asm__(HLT); }".

For a multi-tasking system; you need to have some sort of IPC (Inter-Process Communication). It doesn't matter if it's some type of messaging or pipes or whatever else. The IRQ handler sends keypresses to wherever (typically a virtual terminal layer and/or GUI) using the IPC, and wherever forwards the keypresses (using IPC again) to the application that is currently "active". In this case the IPC itself handles the buffering/queuing; and the IPC interacts with the scheduler such that any tasks waiting for IPC don't waste any CPU time.

In either of these cases, ASCII alone is not suitable. For example, there is no ASCII code for "F2", "page up", "alt + C" or lots of other keys that normal applications will need. For some types of software (e.g. games) the application will need to know when a key is released, and not just when a key is pressed (but this isn't just limited to games - e.g. consider an application with a scroll bar, where it scrolls while the cursor key is held down and stops scrolling when the key is released). Also (mostly for games), sometimes software needs to know which key and doesn't care what character it corresponds to (for example, "if( key_code == user_settings[key_being_used_to_fire_primary_weapon]) fire_weapon1();". Then there's internationalisation - different keyboard maps, Unicode and support for "input method editors". You probably don't want these things yet, but you won't want to rewrite everything as soon as you start wanting these things later.

Basically if you put all that together, the keyboard driver should be creating and sending "keypress packets" and not ASCII characters. Something like:

Code: Select all

typedef struct keypress_packet {
    uint32_t Unicode_codepoint;  // Zero if not applicable
    uint32_t key_number          // Similar to the "scan code" the keyboard gives you but
                                 //   simplified (one code per key, unlike scan codes)
    uint32_t flags               // One flag for if the key was pressed or released; plus
                                 //   more flags for the state of the shift, control and
                                 //   alt keys; plus more flags for the state of caps lock
                                 //   scroll lock, numlock.
} KEYPRESS_PACKET;
If you don't want any internationalisation yet, then the "Unicode_codepoint" field can be used to store ASCII (as the first 128 Unicode codepoints correspond to ASCII codes anyway).

For legacy "console" applications, somewhere (e.g. in a user-space library) you'd have a "readch()" function that gets a keypress packet and ignores most of the extra information and only returns the "Unicode_codepoint" field (if it's non-zero; or for severely borked software only if it's non-zero and less than 128). For applications that aren't crusty old crud you'd also have a "get_keypress()" function (e.g. also in a user-space library) that returns the full information.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply