Input Line Editor with Keymap

From Nutwiki
Jump to: navigation, search

Overview

This example extends the basic Input Line Editor example by adding a custom keymap that only allows to input numbers. Please familiarize yourself with that example first as we will only discuss the new things here.

Source Code

<source lang="c">

  1. include <stdio.h>
  2. include <io.h>
  1. include <dev/board.h>
  1. include <gorp/edline.h>
  1. define LINE_MAXLENGTH 100

EDLINE *el; char *buf;

int CustomKeyMap(int key, int *seq) {

   key = EdLineKeyMap(key, seq);
   /* if we already have to ignore it do so, if not check if it is a control char */
   if ((key != EDIT_KEY_IGNORE) && (key >= 32)) {
       /* if the key is no number, we ignore it */
       if ((key < '0') || (key > '9')) {
           key = EDIT_KEY_IGNORE;
       }
   }
   return key;

}

int main(void) {

   u_long baud = 115200;
   NutRegisterDevice(&DEV_UART, 0, 0);
   freopen(DEV_UART_NAME, "w", stdout);
   freopen(DEV_UART_NAME, "r", stdin);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   puts("\nNut/OS EdLine Demo");
   puts("\nFor this demo only numbers and are allowed. ");
   puts("\nPlease enter some text: ");
   buf = malloc(LINE_MAXLENGTH);
   el = EdLineOpen(EDIT_MODE_ECHO);
   EdLineRegisterKeymap(el, CustomKeyMap);
   EdLineRead(el, buf, LINE_MAXLENGTH);
   EdLineClose(el);
   printf("You entered: %s", buf);
   for (;;) {
   }
   return 0;

} </source>

Details

If you haven't already done so, please read the Input Line Editor example to get explanations for the basic workings of the EdLine functions Nut/OS provides.

The only thing different in the main function is this: <source lang="c"> EdLineRegisterKeymap(el, CustomKeyMap); </source>

This function registers a custom "keymap" for your input line editor. Well actually it does not. What it does is register a custom function to interpret the keys for you, which allows you to make more or less complex custom behaviours for your editor.

The first parameter to this function is the input line editor we just created. The second is the address of the function we want to register as our custom keymap function. Please note that since we're passing the address of the function there are no parentheses after the name, just the name.

Of course we will have to create our custom keymap function for this to work. Our example will use a keymap that only allows number input, no characters or symbols.

<source lang="c"> int CustomKeyMap(int key, int *seq) { </source> The function gets these two parameters, key and *seq. key is the last key that was pressed and *seq points to the next characters in the buffer. We don't actually need seq for this example but the prototype needs it in order to work properly. If you want to see how it can be of use have a look at the barebones EdLineKeyMap function that is the default keymap.

<source lang="c">

   key = EdLineKeyMap(key, seq);

</source> Speaking of which... Since we replaced the default keymap with our own, we have to invoke the default keymap ourselves. This is necessary since it takes care of handling linefeeds and carriage returns. We want that wince we want to be able to press the Enter key to enter our number.

This function may tell us to ignore the character that was just entered. If it does, we really should do so and just pass it on.

<source lang="c">

   /* if we already have to ignore it do so, if not check if it is a control char */
   if ((key != EDIT_KEY_IGNORE) && (key >= 32)) {

</source> Here we check if the default function tells us to ignore the key or if it is a control character (control characters take ASCII 0-31). If it is a control character we will not touch it. But if it is not... well, we'll have to make sure it is a number, right?

<source lang="c">

       /* if the key is no number, we ignore it */
       if ((key < '0') || (key > '9')) {
           key = EDIT_KEY_IGNORE;
       }

</source> Now we check if the character is a number, which is actually pretty easy. We just compare it to the 0 and 9 symbols since all numbers neatly follow one after another. This way we can safely say if it is a digit or not without checking for each individual digit.

Now if the character is no digit (and no control character since we checked for that just a moment ago!) we set it to EDIT_KEY_IGNORE. Using this constant will tell the EdLine functions to not do anything with it.

<source lang="c">

   }
   return key;

} </source> Lastly, we return the new key to the EdLine functionality so it can carry on. That's it.


We could also set the key to some different character or, as the name of keymaps implies, remap keys to different locations. One wide-spread use for this would be the YZ problem on european versus american keyboards: In Europe many - but not all - keyboard layouts have the Y in the lower left corner, next to the shift key, while the Z is located between T and U. On american keyboards and all the other european ones, though, those 2 keys are switched. Using a keymap we could easily remedy this problem by offering a "remapping" of the keys.

Output

<source lang="text"> Nut/OS EdLine Demo

For this demo only numbers and are allowed.

Please enter some text: 1234567890 You entered: 1234567890 </source>