PS/2 Keyboard: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Spelling & typo corrections)
No edit summary
Line 1: Line 1:
{{Convert}}
{{Convert}}


!! How to get keyboard input in protected mode
== How to get keyboard input in protected mode ==


First of all you should have this steps ready in your OS:
First of all you should have this steps ready in your OS:


* [Kernel loaded|BareBones]
* [[Kernels|Kernel]] loaded
* [IDT set up|InterruptsForDummies]
* [[IDT]] set up
* [PIC remapped|Can I remap the PIC?]
* [[PIC]] remapped
* IRQ for keyboard unmasked and pointing to your future [keyboard ISR|InterruptServiceRoutines]
* IRQ for keyboard unmasked and pointing to your future keyboard [[ISR]]
Read all about IRQ's and PIC's at HardWareIrq
Read all about IRQ's and PIC's at HardWareIrq


To get keyboard input you read the port 0x60 and save the translated scan code to a buffer.
To get keyboard input you read the port 0x60 and save the translated scan code to a buffer.


!! Okay, then what ?
== Okay, then what ? ==


The keyboard communicates with your computer through a chip called 8042 (on modern system, the functionality of that chip is emulated by the chipset). Any key press or key release leads to the transmission of a _scancode_ to the 8042 which then raises IRQ1 and makes the scancode available in its dataport (port 0x60).
The keyboard communicates with your computer through a chip called 8042 (on modern system, the functionality of that chip is emulated by the chipset). Any key press or key release leads to the transmission of a _scancode_ to the 8042 which then raises IRQ1 and makes the scancode available in its dataport (port 0x60).


From your point of view, things are as easy as
From your point of view, things are as easy as
<pre>
<verbatim>
void KeyboardIsr()
void KeyboardIsr()
{
{
Line 28: Line 28:
outportb(0x20,0x20); // acknowledge the IRQ, pretty much tells the PIC that we can accept >=priority IRQs now
outportb(0x20,0x20); // acknowledge the IRQ, pretty much tells the PIC that we can accept >=priority IRQs now
}
}
</verbatim>
</pre>


See http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html for hints about how you should interprete what you get from the keyboard.
See http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html for hints about how you should interprete what you get from the keyboard.


Note that if you repeatedly read the port 0x60 without waiting for another IRQ, you'll read the same byte again. That's the 'normal' behaviour of keyboard controller, but if that doesn't suit your needs, you can still "acknowledge" the scancode by quickly disabling and re-enabling the keyboard at the PPI (Programmable Peripheral Interface):
Note that if you repeatedly read the port 0x60 without waiting for another IRQ, you'll read the same byte again. That's the 'normal' behaviour of keyboard controller, but if that doesn't suit your needs, you can still "acknowledge" the scancode by quickly disabling and re-enabling the keyboard at the PPI (Programmable Peripheral Interface):
<pre>
<verbatim>
int temp = inportb(0x61);
int temp = inportb(0x61);
outportb(0x61,temp | 0x80); // disable
outportb(0x61,temp | 0x80); // disable
outportb(0x61,temp & 0x7F); // and re-enable
outportb(0x61,temp & 0x7F); // and re-enable
</verbatim>
</pre>




!! Ctrl, Alt, shift, etc.
== Ctrl, Alt, shift, etc. ==


The keyboard only reports _keystrokes_. That means it makes no difference between an uppercase 'A' and a lowercase 'a' when you hit the key. The trick is that you'll get two kind of scancodes: _make_ codes and _break_ codes, depending on whether you hit or release the key. For instance if you type an uppercase 'A', you'll get
The keyboard only reports _keystrokes_. That means it makes no difference between an uppercase 'A' and a lowercase 'a' when you hit the key. The trick is that you'll get two kind of scancodes: _make_ codes and _break_ codes, depending on whether you hit or release the key. For instance if you type an uppercase 'A', you'll get

<verbatim>
{| {{wikitable}}
0x2A (make shift)
|-
0x1E (make A)
| 0x2A
0x9E (break A)
0xAA (break shift)
| (make shift)
|-
</verbatim>
| 0x1E
| (make A)
|-
| 0x9E
| (break A)
|-
| 0xAA
| (break shift)
|}


Similarly, when you type 'hi' with the CTRL key hold down, your keyboard sends the codes 1d, 23, a3, 17, 97, 9d to the CPU. That means if you want to interpret character 'A' differently based on whether the 'SHIFT' key is up or down, you have first to _remember_ the state of the shift key.
Similarly, when you type 'hi' with the CTRL key hold down, your keyboard sends the codes 1d, 23, a3, 17, 97, 9d to the CPU. That means if you want to interpret character 'A' differently based on whether the 'SHIFT' key is up or down, you have first to _remember_ the state of the shift key.


<pre>
<verbatim>
char lowercase[256] = {0x1E:'a'};
char lowercase[256] = {0x1E:'a'};
char uppercase[256] = {0x1E:'A'};
char uppercase[256] = {0x1E:'A'};
Line 75: Line 84:
outportb(0x20,0x20);
outportb(0x20,0x20);
}
}
</verbatim>
</pre>


The arrays =lowercase= and =uppercase= are the _conversion arrays_, also called _keyboard map_. A different keyboard language will lead to different keyboard maps, so you're welcome to provide an API call that will allow the change of that map. You might also want an =alternate= map for characters composed with ~[ALTgr] key hold down or a =wchar_t= based map that will allow you to map a keystroke directly to Unicode characters.
The arrays =lowercase= and =uppercase= are the _conversion arrays_, also called _keyboard map_. A different keyboard language will lead to different keyboard maps, so you're welcome to provide an API call that will allow the change of that map. You might also want an =alternate= map for characters composed with ~[ALTgr] key hold down or a <tt>wchar_t</tt> based map that will allow you to map a keystroke directly to Unicode characters.




!! What's that E0 scancode i get all the time ?
== What's that E0 scancode i get all the time ? ==


Several keys on your keyboard have a two-bytes scan code (they're said to be _escaped_ scancodes). All those codes start with 0xe0 and are then followed by the 'real' scancode, which means when receiving scancode 0xe0, you should just store the info and wait for the next scancode to know what key even actually occurred.
Several keys on your keyboard have a two-bytes scan code (they're said to be _escaped_ scancodes). All those codes start with 0xe0 and are then followed by the 'real' scancode, which means when receiving scancode 0xe0, you should just store the info and wait for the next scancode to know what key even actually occurred.
Line 86: Line 95:
If you look at the list of escaped scancodes on http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html, you'll note that none of them correspond to a 'printable' character.
If you look at the list of escaped scancodes on http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html, you'll note that none of them correspond to a 'printable' character.


<pre>
<verbatim>
unsigned shift_state = 0;
unsigned shift_state = 0;
unsigned escaped=0;
unsigned escaped=0;
Line 109: Line 118:
outportb(0x20,0x20);
outportb(0x20,0x20);
}
}
</verbatim>
</pre>




!! What should i do with non-printable characters ?
== What should i do with non-printable characters ? ==


ToDo: think about it. We can however already say that they should follow the same 'datapath' as regular characters: we want cursor displacements, regular keytypes and commands (such as CTRL+S) to be delivered to the application in the same order the user typed them, and the best way to achieve this is to ensure they're delivered through the same data stream.
ToDo: think about it. We can however already say that they should follow the same 'datapath' as regular characters: we want cursor displacements, regular keytypes and commands (such as CTRL+S) to be delivered to the application in the same order the user typed them, and the best way to achieve this is to ensure they're delivered through the same data stream.




!! How can I support non-latin characters ?
== How can I support non-latin characters ? ==


In case you'd like to write an OS with support of arabic, kanji or whatever, you'll at least need support for Unicode. We had a thread about [loading arabic fonts|Forum:7657] on the forum, which you might like to look at.
In case you'd like to write an OS with support of arabic, kanji or whatever, you'll at least need support for Unicode. We had a thread about [loading arabic fonts|Forum:7657] on the forum, which you might like to look at.
Line 124: Line 133:




==See Also==

===Threads===
----
*[Keyboard input | Forum:6451]
!Related threads
[Keyboard input | Forum:6451]
*[Up or down press? | Forum:6479]
[Up or down press? | Forum:6479]
*[Change typerate | Forum:6395]
[Change typerate | Forum:6395]
*[Converting the scancodes | Forum:6304]
[Converting the scancodes | Forum:6304]
*[Discussion about keyboard input in a GUI | Forum:5919]
[Discussion about keyboard input in a GUI | Forum:5919]
*[Scroll-lock LED | Forum:6213]
[Scroll-lock LED | Forum:6213]
*[Keyboard LEDs (C source) | Forum:7182]
[Keyboard LEDs (C source) | Forum:7182]
*[Keyboard LEDs (asm source) | Forum:7009]
[Keyboard LEDs (asm source) | Forum:7009]

----
!Todo:
Add info on: scan codes, changing led lights, handle shift/caps etc, etc...
Maybe change name to "Keyboard programming" or similar, since it's not only about getting a key.

Revision as of 19:36, 19 March 2007

Template:Convert

How to get keyboard input in protected mode

First of all you should have this steps ready in your OS:

  • Kernel loaded
  • IDT set up
  • PIC remapped
  • IRQ for keyboard unmasked and pointing to your future keyboard ISR

Read all about IRQ's and PIC's at HardWareIrq

To get keyboard input you read the port 0x60 and save the translated scan code to a buffer.

Okay, then what ?

The keyboard communicates with your computer through a chip called 8042 (on modern system, the functionality of that chip is emulated by the chipset). Any key press or key release leads to the transmission of a _scancode_ to the 8042 which then raises IRQ1 and makes the scancode available in its dataport (port 0x60).

From your point of view, things are as easy as

void KeyboardIsr()
{
   byte new_scan_code = inportb(0x60);
   // do something with the scancode ...
   // remember you only get ONE byte of the scancode each time the ISR is invoked
   // (though most of the times the scancode is only one byte)

   outportb(0x20,0x20);  // acknowledge the IRQ, pretty much tells the PIC that we can accept >=priority IRQs now
}

See http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html for hints about how you should interprete what you get from the keyboard.

Note that if you repeatedly read the port 0x60 without waiting for another IRQ, you'll read the same byte again. That's the 'normal' behaviour of keyboard controller, but if that doesn't suit your needs, you can still "acknowledge" the scancode by quickly disabling and re-enabling the keyboard at the PPI (Programmable Peripheral Interface):

int temp = inportb(0x61);
outportb(0x61,temp | 0x80);  // disable
outportb(0x61,temp & 0x7F);  // and re-enable


Ctrl, Alt, shift, etc.

The keyboard only reports _keystrokes_. That means it makes no difference between an uppercase 'A' and a lowercase 'a' when you hit the key. The trick is that you'll get two kind of scancodes: _make_ codes and _break_ codes, depending on whether you hit or release the key. For instance if you type an uppercase 'A', you'll get

0x2A (make shift)
0x1E (make A)
0x9E (break A)
0xAA (break shift)

Similarly, when you type 'hi' with the CTRL key hold down, your keyboard sends the codes 1d, 23, a3, 17, 97, 9d to the CPU. That means if you want to interpret character 'A' differently based on whether the 'SHIFT' key is up or down, you have first to _remember_ the state of the shift key.

char lowercase[256] = {0x1E:'a'};
char uppercase[256] = {0x1E:'A'};

unsigned shift_state = 0;

void KeyboardIsr()
{
   byte new_scan_code = inportb(0x60);
   switch(new_scan_code) {
   case 0x2a: shift_state = 1; break;
   case 0xaa: shift_state = 0; break;
   default:
      if (new_scan_code & 0x80) {
         // ignore the break code
      } else {
         new_char=(shift_state?uppercase:lowercase)[new_scan_code];
         // do something with new_char
      }
  break;

  outportb(0x20,0x20);
}

The arrays =lowercase= and =uppercase= are the _conversion arrays_, also called _keyboard map_. A different keyboard language will lead to different keyboard maps, so you're welcome to provide an API call that will allow the change of that map. You might also want an =alternate= map for characters composed with ~[ALTgr] key hold down or a wchar_t based map that will allow you to map a keystroke directly to Unicode characters.


What's that E0 scancode i get all the time ?

Several keys on your keyboard have a two-bytes scan code (they're said to be _escaped_ scancodes). All those codes start with 0xe0 and are then followed by the 'real' scancode, which means when receiving scancode 0xe0, you should just store the info and wait for the next scancode to know what key even actually occurred.

If you look at the list of escaped scancodes on http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html, you'll note that none of them correspond to a 'printable' character.

unsigned shift_state = 0;
unsigned escaped=0;

void KeyboardIsr()
{
   unsigned new_scan_code = inportb(0x60);
   if (escaped) new_scan_code += 256;
   switch(new_scan_code) {
   case 0x2a: shift_state = 1; break;
   case 0xaa: shift_state = 0; break;
   case 0xe0: escaped = 1; break;
   default:
      if (new_scan_code & 0x80) {
         // ignore the break code
      } else {
         new_char=(shift_state?uppercase:lowercase)[new_scan_code];
         // do something with new_char
      }
  break;

  outportb(0x20,0x20);
}


What should i do with non-printable characters ?

ToDo: think about it. We can however already say that they should follow the same 'datapath' as regular characters: we want cursor displacements, regular keytypes and commands (such as CTRL+S) to be delivered to the application in the same order the user typed them, and the best way to achieve this is to ensure they're delivered through the same data stream.


How can I support non-latin characters ?

In case you'd like to write an OS with support of arabic, kanji or whatever, you'll at least need support for Unicode. We had a thread about [loading arabic fonts|Forum:7657] on the forum, which you might like to look at.

Anyway, please consider the following: even if your userbase is mainly arabic/japanese/whatever, your guru base is likely to be international and to prefer messages about "queue" or "thread" than about whatever the translation might look like, so english might be preferred for "behind the scene" stuff ...


See Also

Threads

  • [Keyboard input | Forum:6451]
  • [Up or down press? | Forum:6479]
  • [Change typerate | Forum:6395]
  • [Converting the scancodes | Forum:6304]
  • [Discussion about keyboard input in a GUI | Forum:5919]
  • [Scroll-lock LED | Forum:6213]
  • [Keyboard LEDs (C source) | Forum:7182]
  • [Keyboard LEDs (asm source) | Forum:7009]