Page 1 of 1

Use of shift with keyboard

Posted: Thu May 14, 2009 10:23 am
by jrothwell
EDIT: Just as a side note, due to the fact that I'm not using this as my actual OS project, existing drivers that work in the same way as Bran's would be fine, as I would be able to see how the driver accomplishes using shift.

Hi there,

I'm rather new to OS development.
I am currently using Bran's tutorial as a start point, and once I understand everything in there, I will write my own from scratch.

However, I have come to a problem...

kb.c

Code: Select all

/* bkerndev - Bran's Kernel Development Tutorial
*  By:   Brandon F. ([email protected])
*  Desc: Keyboard driver
*
*  Notes: No warranty expressed or implied. Use at own risk. */
#include <system.h>

/* KBDUS means US Keyboard Layout. This is a scancode table
*  used to layout a standard US keyboard. I have left some
*  comments in to give you an idea of what key is what, even
*  though I set it's array index to 0. You can change that to
*  whatever you want using a macro, if you wish! */
unsigned char kbdus[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8',	/* 9 */
  '9', '0', '-', '=', '\b',	/* Backspace */
  '\t',			/* Tab */
  'q', 'w', 'e', 'r',	/* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',		/* Enter key */
    0,			/* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',	/* 39 */
 '\'', '`',   0,		/* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',			/* 49 */
  'm', ',', '.', '/',   0,					/* Right shift */
  '*',
    0,	/* Alt */
  ' ',	/* Space bar */
    0,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
};

/* Handles the keyboard interrupt */
void keyboard_handler(struct regs *r)
{
    unsigned char scancode;

    /* Read from the keyboard's data buffer */
    scancode = inportb(0x60);

    /* If the top bit of the byte we read from the keyboard is
    *  set, that means that a key has just been released */
    if (scancode & 0x80)
    {
        /* You can use this one to see if the user released the
        *  shift, alt, or control keys... */
    }
    else
    {
        /* Here, a key was just pressed. Please note that if you
        *  hold a key down, you will get repeated key press
        *  interrupts. */

        /* Just to show you how this works, we simply translate
        *  the keyboard scancode into an ASCII value, and then
        *  display it to the screen. You can get creative and
        *  use some flags to see if a shift is pressed and use a
        *  different layout, or you can add another 128 entries
        *  to the above layout to correspond to 'shift' being
        *  held. If shift is held using the larger lookup table,
        *  you would add 128 to the scancode when you look for it */
        putch(kbdus[scancode]);
    }
}

/* Installs the keyboard handler into IRQ1 */
void keyboard_install()
{
    irq_install_handler(1, keyboard_handler);
}
Right, basically, I can't see a way to read whether or not shift is being held down, and how to then use an upper case letter. I know that LSHIFT's scancode number is 42, but how would I go about reading if it is being held down?

I have read everywhere that I can, tried many different tags in google etc., so if somebody could give me a hand, or point me in the direction of a tutorial on this, it would be a great help...

Thanks in advance,
Joe

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 11:55 am
by bewing
You have to keep track of keyups as well as keydowns. Left shift key goes down -- set a global bitflag or two. Handler IRETs. Right shift key goes down, set an additional bitflag. IRET. Left shift key goes up -- clear a bitflag. IRET. Right shift goes up -- clear the last bitflags. If a "shift" bitflag is set, you use a different or additional mapping step to get to shifted-ascii, which may or may not be part of the interrupt handler -- and the shifted ascii value may be returned in addition to the unshifted value.

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 11:57 am
by salil_bhagurkar
If you know the scancode, then you just need to check when it appears. When it does, set a flag. There will be another scancode for the release of the shift key (IMHO 0x80 anded with the press scancode). When this appears, you clear the flag. When the flag is set, and some other key comes in, you know that it has appeared with shift pressed.

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 2:56 pm
by jrothwell
Hi there again:

Basically, I tried a few things with no success,
and then tried this:

Code: Select all

#include <system.h>


unsigned char kbdusnsh[128] =
{
    -1,  27, '1', '2', '3', '4', '5', '6', '7', '8',	/* 9 */
  '9', '0', '-', '=', '\b', '\t',
  'q', 'w', 'e', 'r',
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',		/* Enter key */
    0,			/* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',	/* 39 */
 '\'', '`',   0,		/* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',			/* 49 */
  'm', ',', '.', '/',   0,					/* Right shift */
  '*',
    0,	/* Alt */
  ' ',	/* Space bar */
    58,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
   
};

	unsigned char kbdusysh[128] =
{
 0,  0, '!', '"', '£', '$', '%', '^', '&', '*',	/* 9 */
  '(', ')', '_', '+', '\b', '\t',
  'Q', 'W', 'E', 'R',
  'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',		/* Enter key */
    0,			/* 29   - Control */
  'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';',	/* 39 */
 '|', '¬',   42,		/* Left shift */
 '\\', 'Z', 'X', 'C', 'V', 'B', 'N',			/* 49 */
  'M', '<', '>', '?',   0,					/* Right shift */
  0,
    0,	/* Alt */
  ' ',	/* Space bar */
    58,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
};

/* Handles the keyboard interrupt */
void keyboard_handler(struct regs *r)
{
    unsigned char scancode;
    int lshiftpress;
    /* Read from the keyboard's data buffer */
    scancode = inportb(0x60);

    /* If the top bit of the byte we read from the keyboard is
    *  set, that means that a key has just been released */
    while ((scancode == 42) & 0x1C)
    {
        lshiftpress = 1;

    }
    while ((scancode == 42) & 0x80)
	{
		lshiftpress = 0;
	}
	
    if (scancode & 0x80)
	{
	}
    {
        /* Here, a key was just pressed. Please note that if you
        *  hold a key down, you will get repeated key press
        *  interrupts. */

        /* Just to show you how this works, we simply translate
        *  the keyboard scancode into an ASCII value, and then
        *  display it to the screen. You can get creative and
        *  use some flags to see if a shift is pressed and use a
        *  different layout, or you can add another 128 entries
        *  to the above layout to correspond to 'shift' being
        *  held. If shift is held using the larger lookup table,
        *  you would add 128 to the scancode when you look for it */

	if (lshiftpress == 1)
	{
        putch(kbdusysh[scancode]);
	
	}
	else if (lshiftpress == 0)
	{
	putch(kbdusnsh[scancode]);
	}
    }
}

/* Installs the keyboard handler into IRQ1 */
void keyboard_install()
{
    irq_install_handler(1, keyboard_handler);
}
and now I have this problem...
When shift isn't pressed, if I press "a" it shows on screen as "aA", and if I have shift pressed, it shows "aA*".

I'm not getting this at all... would someone mind going into a little more detail? ><

Sorry... and thanks again...
Joe

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 4:30 pm
by Troy Martin
I'm having a similar problem in my assembly language OS (although, no uppercase comes out and the star is big and centred.) I'm guessing the issue is the same, so I'll just wait for the outcome and adapt it.

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 4:40 pm
by jrothwell
The star is big and centered for me as well, although I just think this is the default font...

I'm not sure how to do this, but it seems to me like its printing both kbdusysh and kbdusnsh... for me as well, when I press shift but without pressing anything else, when I release I get the star...
Obviously the shift key is corresponding to * for some reason, and I haven't solved my problem of capital/lower, instead I am now printing both...
Seemingly my lshiftpress variable isn't working, so I'm stuck completely...
What I was trying to do with this was:
if shift is pressed, lshiftpress is true, and therefore use kbdusysh for printing, and if it isn't pressed, lshiftpress is false and therefore use kbdusnsh for printing... its using both though...

I'm going to try and work on it overnight...

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 4:44 pm
by Troy Martin
The star appears to be some kind of control code, as another asterisk is something else entirely.

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 7:37 pm
by jrothwell
It is 2:40AM here in the UK and I haven't gotten any further...

Would someone please go into a little more detail or give a link or something?

Thanks,

Joe

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 7:47 pm
by pcmattman
Your handler is wrong.

Try something more like this:

Code: Select all

/* Handles the keyboard interrupt */
void keyboard_handler(struct regs *r)
{
    unsigned char scancode;
    static int lshiftpress = 0; // will persist across all calls of the handler
	
    /* Read from the keyboard's data buffer */
    scancode = inportb(0x60);

    /* If the top bit of the byte we read from the keyboard is
     *  set, that means that a key has just been released 
	 */
	if(scancode & 0x1C)
	{
		if(scancode == 42)
			lshiftpress = 1;
	}
	
	if(scancode & 0x80)
	{
		if(scancode == 42)
		{
			lshiftpress = 0;
		}
		else
		{
			if(lshiftpress)
				putch(kbdusysh[scancode]);
			else
				putch(kbdusnsh[scancode]);
		}
	}
}
I can't say for certain it'll work, but I hope you can see what's different and at least pick up the basic idea behind it.

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 8:12 pm
by jrothwell
@pcmattman:
This gave a strange different problem...
Now when I load what I get is this scenario:
1) it uses my shift characters without shift being pressed,
2) I can type for as long as I want like this,
3) When I hit shift, it stops being able to type anything... even when released...

There is one good thing: it got rid of the asterisk xD

On a serious note though, some questions about your code there:
Why "if (scancode & 0x1C);" ? I thought that 0x1C refers to the make for "A"...

Also... am I supposed to be using 0x12 for the L_Shift key, rather than 42? 42 is it's number according to the layout, but its make scancode is 0x12...

I'm really tired xD it is 3:15AM, and I have work at 6:45AM XD

Anyway, if anyone has any tips please feel free to leave them... I'm going to sleep now...

Night all,
thanks again

Joe

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 8:28 pm
by pcmattman
Ok. As I said, I wasn't sure if it would actually work - it was more or less a conceptual thing.

The basic outline should be something more like:

Code: Select all

void key_handler()
{
    static int lshiftpressed = 0;
    unsigned char scancode;

    scancode = inb(0x60);

    if(scancode & 0x80)
    {
        // Handle key up event - check that SHIFT isn't pressed anymore
    }
    else
    {
        // Handle key down event - check for SHIFT for example
    }
}
In both event sections you handle the incoming scancode. Also, IIRC, for the key up event, you will need to remove the 0x80 from the scancode, or else when you use it as an offset into your 128 byte scancode -> ASCII translation table you'll be working from the end of the array :)

Re: Use of shift with keyboard

Posted: Thu May 14, 2009 10:34 pm
by salil_bhagurkar
Okay, why don't you get a bit crude and just print out the scancodes in the handler and observe what is happening? Print out the scancodes, then add condition for the shift key you see. Then start coding to your normal handler step by step, observing the debug output at each stage.

This should tell you exactly which condition is failing.

Re: Use of shift with keyboard

Posted: Sat May 16, 2009 6:08 pm
by jrothwell
I have decided to review the majority of the C language again before coming back to this project; I guess I missed some valuable points and so I need to fill in the gaps.
Equally, I think that I am going to learn ASM fully, and start reading as many OS Development theory articles, how systems work etc again.

There is no point trying to do something this complex with a limited knowledge of what you are doing.

Sorry to have wasted everybody's time; see you in a few weeks when I have relearnt what I need to.

Thanks,
Joe