Page 1 of 1

writing keyboard driver

Posted: Thu Jan 17, 2008 4:53 pm
by sancho1980
hi

im trying to write a useful keyboard driver. it works, but only because i ignoed a couple of issues which in a real world situation just cannot be ignored.

i first defined a keyboard structure as follows:

Code: Select all

type keyboard:

	record;

		write: pointer to byte;

		modifier: dword;

		buffer: byte[KBD_BUFFER_SIZE];

	endrecord;
write is a pointer to the next byte in the buffer where a character can be placed
modifier might be something like SHIFT, ALT+SHIFT,etc..I havent yet implemented that
buffer is the actual buffer

next, i implemented a keymap structure as follows:

Code: Select all

type keymap:

	record;

		fnct: dword;

		no_args: uns32;

		args: dword;

	endrecord;
fnct is a function to be called when the specified scancode is recorded
no_args is the number of dword-arguments passed to the above function
args is then the pointer to the arguments to be passed to the above function, unless no_args = 1, in which case args is the argument itself

my keymap then looks like this:

Code: Select all

km: keymap[NO_SCANCODES, NO_MODIFIERS]:=

	[

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[&readchar, 1, (type dword 'q')], keymap:[&readchar, 1, (type dword 'Q')],

		keymap:[&readchar, 1, (type dword 'w')], keymap:[&readchar, 1, (type dword 'W')],

		keymap:[&readchar, 1, (type dword 'e')], keymap:[&readchar, 1, (type dword 'E')],

		keymap:[&readchar, 1, (type dword 'r')], keymap:[&readchar, 1, (type dword 'R')],

		keymap:[&readchar, 1, (type dword 't')], keymap:[&readchar, 1, (type dword 'T')],

		keymap:[&readchar, 1, (type dword 'z')], keymap:[&readchar, 1, (type dword 'Z')],

		keymap:[&readchar, 1, (type dword 'u')], keymap:[&readchar, 1, (type dword 'U')],

		keymap:[&readchar, 1, (type dword 'i')], keymap:[&readchar, 1, (type dword 'I')],

		keymap:[&readchar, 1, (type dword 'o')], keymap:[&readchar, 1, (type dword 'O')],

		keymap:[&readchar, 1, (type dword 'p')], keymap:[&readchar, 1, (type dword 'P')],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[&enter_pressed, 0, NULL], keymap:[&enter_pressed, 0, NULL],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[&readchar, 1, (type dword 'a')], keymap:[&readchar, 1, (type dword 'A')],

		keymap:[&readchar, 1, (type dword 's')], keymap:[&readchar, 1, (type dword 'S')],

		keymap:[&readchar, 1, (type dword 'd')], keymap:[&readchar, 1, (type dword 'D')],

		keymap:[&readchar, 1, (type dword 'f')], keymap:[&readchar, 1, (type dword 'F')],

		keymap:[&readchar, 1, (type dword 'g')], keymap:[&readchar, 1, (type dword 'G')],

		keymap:[&readchar, 1, (type dword 'h')], keymap:[&readchar, 1, (type dword 'H')],

		keymap:[&readchar, 1, (type dword 'j')], keymap:[&readchar, 1, (type dword 'J')],

		keymap:[&readchar, 1, (type dword 'k')], keymap:[&readchar, 1, (type dword 'K')],

		keymap:[&readchar, 1, (type dword 'l')], keymap:[&readchar, 1, (type dword 'L')],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],

		keymap:[&readchar, 1, (type dword 'y')], keymap:[&readchar, 1, (type dword 'Y')],

		keymap:[&readchar, 1, (type dword 'x')], keymap:[&readchar, 1, (type dword 'X')],

		keymap:[&readchar, 1, (type dword 'c')], keymap:[&readchar, 1, (type dword 'C')],

		keymap:[&readchar, 1, (type dword 'v')], keymap:[&readchar, 1, (type dword 'V')],
		keymap:[&readchar, 1, (type dword 'b')], keymap:[&readchar, 1, (type dword 'B')],

		keymap:[&readchar, 1, (type dword 'n')], keymap:[&readchar, 1, (type dword 'N')],
		keymap:[&readchar, 1, (type dword 'm')], keymap:[&readchar, 1, (type dword 'M')],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[NULL, 0, NULL], keymap:[NULL, 0, 0],
		keymap:[&readchar, 1, (type dword ' ')], keymap:[&readchar, 1, (type dword ' ')],

	];
You can see that for now I am only using the readchar and the enter_pressed functions, which both look like this:

Code: Select all

procedure readchar(what:dword);
begin readchar;
	push(eax);
	push(ebx);
	pushfd();	
	if (kbd.write <> NULL) then
		mov(kbd.write,eax);
		mov(what,ebx);
		mov(bl,[eax]);
		inc(eax);
		if (eax > &kbd.buffer[KBD_BUFFER_SIZE - 1]) then
			mov(NULL,eax);
		endif;
		mov(eax,kbd.write);
		putchar(what);
	endif;
	popfd();
	pop(ebx);
	pop(eax);
end readchar;

Code: Select all

procedure enter_pressed;

begin enter_pressed;
	mov(&kbd.buffer[0],kbd.write);
	putchar(LF);

end enter_pressed;
So what I can do is I can type characters and see them echoed on the screen. My characters are also buffered in the keyboard buffer until I press enter, making it potentially possible to get to the stage where I can actually enter commands :-)
But two very important things I dont quite know how to go about:

1) Backspace:

How do you implement this? Suppose I type a key and see the character displayed on the screen. Then I might want to type backspace. It's easy enough to remove that last character from the keyboard buffer, but when removing that character from screen, how can I be sure that the last character just before the cursor is really the last character I typed and not something the os printed out there in the meantime? how would i usually go about this?

2) tabs:

How do you implement them? Again, the problem is with backspacing. How do you remove backspaces? Removing from the buffer is easy, but when removing from the screen, you will have to make sure that the last n bytes before the cursor really belong to your tab.

Can any one give me some directions here?

Thanks

Martin

Posted: Thu Jan 17, 2008 6:06 pm
by bewing
You need to use multiple buffers.
You have a "user buffer" that holds a screenful of info that the user has typed.
You have a completely different "os message" buffer that holds os messages to display on the screen.
The screen itself is a third buffer.
You use some method to merge the user and os screens together, to dump to the screen buffer. Perhaps you display n lines of OS messages at the bottom of the screen, and 25-n lines of user data at the top. But then, the user buffer is never contaminated with data from anywhere else.
It is important to be able to at least recount (and perhaps redisplay) the characters that the user has typed on the current line (in order to recalculate tab lengths, if characters are deleted).

Posted: Fri Jan 18, 2008 10:08 am
by Ready4Dis
Typically, if you receive a keyboard stroke, you would a.) buffer it in your kernel, then pass it onto whatever your current application is (if you're using multiple consoles, ala linux, you would pass it to your current console), if you have a GUI, you would pass it to the current active window, etc. Your kernel should not write to an application's screen for any reason unless it crashes and you wanted to display debugging information (or for debugging in general). If you have a single tasking OS, then the kernel shouldn't really be processing much of anything and just simply passing it all onto the process. How each application wants to handle the inputs is up to them, for example, a console might want to echo to screen, while a game might want to just move the player or jump. I understand that you're just starting and migth not have all that stuff setup yet, so until then, your user input isn't really useful if you have no tasks running, so just get it working and move on or design a way to pass the inputs to an application for processing.

Posted: Fri Jan 18, 2008 2:14 pm
by mathematician
Both Windows and DOS simply pass control characters on to applications for them to do what they like with. Usually a back space is interpreted as a "delete the character to the left of the cursor" command, but that is just convention. With the possible exception of special key combinations like Ctrl-Alt-Del the OS's job is over once it has translated the scan code into ascii or unicode characters and stored them internally or passed them straight on to an application; after that it is up to the application