Monday 22 July 2013

Menus You Can Navigate With The Arrow Keys

Also Look At:

I have learnt to read from and write to file, so the database program for my friend has begun in earnest.
It is an extension of the program I posted a while back.

So far the program I am writing has 5046 lines of code in it. Programming can really be fun and at least to me, it is a brain twister I enjoy solving. Right now I am trying to solve the problem of displaying search results coming up dynamically as the user types in an item information. The results show in the lower part of the screen if the search results are less than 10.

I can do it for one value (Say Item ID), but what if the user types half of item ID and some characters of the name?

Anyway, the database program uses the following style extensively. It is a menu that the user can navigate around using the arrow keys. Like I always say, this may not be the best way to do it, but I don't know better. I'm just glad I could come up with code to do this, and right now I don't care if it is badly written code.

Although I haven't included in this example, a lot of things I use in my original program, let me mention that for the "Age" field I would include a check to make sure user is entering digits.

Something like: if(y==1 && a<9 && key>=48 && key <=57)


This example also uses the header myconstdwin.h. Click on it, copy paste the code to a notepad file, save it as "myconstdwin.h", copy paste the file into the include folder for codeblocks (the path on my computer is C:\Program Files\CodeBlocks\MinGW\include). Once you have the file in there, this program will compile and run.

More information on the get_key() function to detect the function and arrow keys etc. can be found in my previous post.

For this particular program, the user can enter the name, or maybe just half of the name, then decide to enter sex or age, using the DOWN arrow key to move from one menu item to another, I haven't included the UP arrow key to keep the program short. Backspace can be used for correction. The program will also make sure user does not exceed the array value when entering the values. For example, user can only enter 29 characters for 'Name', after that user is informed that they cannot enter more characters.

Later we can atoi the age, if we intend to use it numerically, before using it.
Finally hitting enter will show all the entered values.

Sample:




#include <myconstdwin.h>

void dl_hl(int x,int y);
int get_key();

main()
{
    int key,n=0,a=0,s=0,x,y=0; //since y, which is the verticle row, starts at 0

    char name[30],age[10],sex[15];

    gotoxy(0,10);
    printf("Hit Enter To See Values, Down Arrow key to navigate.");
    gotoxy(0,0);

    SetColorAndBackground(15,0); //bright white
    printf("Name\t- \n");
    SetColorAndBackground(8,0); //normal grey
    printf("Age\t- \n");
    printf("Sex\t- ");
    gotoxy(10,0);
    x=10; //in gotoxy, x will be 10 in the beginning
    while(1)
    {
        key=get_key();
        {
            /**If user hits the down key**/
            if(key==592)
            {
                if(y==0)  //y(row) is 0, IE at 'name'
                {
                    dl_hl(1,2); //dehighlight 1(name) highlight 2(age)
                    y=1; //y is now at age
                    x=10+a;
                    gotoxy(10+a,1); //move to cursor to one after the age field
                                    //+number of chars entered
                }
                else if(y==1) //y(row) is 1, that means highlight is at age
                {
                    dl_hl(2,3); //dehighlight 2(age) highlight 3(sex)
                    y=2; //y is now at sex
                    x=10+s;
                    gotoxy(10+s,2); //move to cursor to one after the sex field
                                    //+number of chars entered
                }
                else if(y==2) //y(row) is 2, that means highlight is at sex
                {
                    dl_hl(3,1); //dehighlight 3(sex) highlight 1(name)
                    y=0; //y is now at name
                    x=10+n;
                    gotoxy(10+n,0); //move to cursor to one after the name field + number
                                    //of characters entered
                }
            }
            /** User enters VALID CHARACTERS **/
            else if(key>=32 && key<=126) //valid characters
            {
                if(y==0 && n<29) //name is highlighted. characters less than 30
                {
                    printf("%c",key);
                    name[n]=key; //the particular block is assigned the key entered
                    n++; //n is incremented, ready to accept the next key user
                    x=10+n;
                }
                else if(n==29) //name can only hold 29 characters. The last one is for
                            //the terminating \0 NULL character
                {
                    gotoxy(0,5);
                    printf("Out of characters. 29 or less characters!");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("                                          ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                if(y==1 && a<9) //age is highlighted. characters less than 10
                {
                    printf("%c",key);
                    age[a]=key; //the particular block is assigned the key entered
                    a++; //n is incremented, ready to accept the next key user
                    x=10+a;
                }
                else if(a==9) //age can only hold 9 characters. The last one is for
                            //the terminating \0 NULL character
                {
                    gotoxy(0,5);
                    printf("Out of characters. 9 or less characters!");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("                                          ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                if(y==2 && s<14) //sex is highlighted. characters less than 10
                {
                    printf("%c",key);
                    sex[s]=key; //the particular block is assigned the key entered
                    s++; //n is incremented, ready to accept the next key user
                    x=10+s;
                }
                else if(s==14) //sex can only hold 14 characters. The last one is for
                            //the terminating \0 NULL character
                {
                    gotoxy(0,5);
                    printf("Out of characters. 14 or less characters!");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("                                          ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
            }
            /**If user hits the Backspace key**/
            else if(key==8)
            {
                if(y==0 && n>0) //if cursor is in name and characters are entered
                {
                    /*move cursor one back, then blank it out by printing a space
                    then go back again. Effectively, the last character is erased*/
                    printf("\b \b");
                    n--; //number of characters for name is decremented
                    x=10+n; //re-assign x for gotoxy.
                }
                else if(y==1 && a>0)
                {
                    /*move cursor one back, then blank it out by printing a space
                    then go back again. Effectively, the last character is erased*/
                    printf("\b \b");
                    a--; //number of characters for age is decremented
                    x=10+a; //re-assign x for gotoxy.
                }
                else if(y==2 && s>0)
                {
                    /*move cursor one back, then blank it out by printing a space
                    then go back again. Effectively, the last character is erased*/
                    printf("\b \b");
                    s--; //number of characters for age is decremented
                    x=10+s; //re-assign x for gotoxy.
                }
            }
            /**User hits enter key**/
            else if(key==13)
            {
                if(n==0 && a==0 && s==0)
                {
                    gotoxy(0,5);
                    printf("Enter values first");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("                       ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                else if(n==0)
                {
                    gotoxy(0,5);
                    printf("Enter Name");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("             ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                else if(a==0)
                {
                    gotoxy(0,5);
                    printf("Enter Age");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("              ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                else if(s==0)
                {
                    gotoxy(0,5);
                    printf("Enter Sex");
                    getch();
                    /*erase the message*/
                    gotoxy(0,5);
                    printf("              ");
                    gotoxy(x,y); //cursor moves back to where it was
                }
                else
                {
                    /**everything is entered. Make sure everything has
                    the terminating character so that they are valid strings**/
                    name[n]='\0';
                    age[a]='\0';
                    sex[s]='\0';
                    gotoxy(0,5);
                    printf("Name: %s\nAge: %s\nSex: %s\n",name,age,sex);
                    getch();
                    break;
                }
            }
        }
    }

}

void dl_hl(int x,int y)
{
    if(x==1)
    {
        gotoxy(0,0);
        SetColorAndBackground(8,0);
        printf("Name\t-");
    }
    else if(y==1)
    {
        gotoxy(0,0);
        SetColorAndBackground(15,0);
        printf("Name\t-");
        SetColorAndBackground(8,0);
    }
    if(x==2)
    {
        gotoxy(0,1);
        SetColorAndBackground(8,0);
        printf("Age\t-");
    }
    else if(y==2)
    {
        gotoxy(0,1);
        SetColorAndBackground(15,0);
        printf("Age\t-");
        SetColorAndBackground(8,0);
    }
    if(x==3)
    {
        gotoxy(0,2);
        SetColorAndBackground(8,0);
        printf("Sex\t-");
    }
    else if(y==3)
    {
        gotoxy(0,2);
        SetColorAndBackground(15,0);
        printf("Sex\t-");
        SetColorAndBackground(8,0);
    }
}

int get_key()
{
    int c = getch(); //first getch() sees the first value
    switch (c)  //This will only take action if the value is 0 or 224
    {
      case 0:   return getch()+256;  //and this second getch() eats the 2nd value
      case 224: return getch()+512; //and 256 or 512 is added to it and returned.
    }
    return c;   //if the value is not 0 or 224 (IE key is not special) normal value is returned
}

Monday 1 July 2013

Detecting The Arrow, Page Up & Page Down, Function Keys etc. And Using Ctrl Combinations In C Programming.

I found this function HERE a few months back when I looking how to detect the function keys.
I have used it a couple of times, but never really understood how it worked.
I decided to figure it out and I think I have it. All props to the 'nucleon' & 'hauzer' guys for sharing with noobs like me!

All the keys that have normal ASCII values are easy enough to implement in our codes, but the function, arrow, page. up down keys are a bit trickier.

Pressing the F1 ,F2, Pg Down keys etc. return 2 values. The first one is a value that varies
the other is either a 0 or 224. This function uses that fact to return a unique value.


Here is an example to see how the 2 values are handled in C:
_________________________________________________
#include <stdio.h>
#include <conio.h>

int main()
{
    printf("Press any key. Do it two times!");
    getch();
    getch();
}
__________________________________________________
The above program requires 2 key presses to end.
If you press one of the ascii keys, you will need to do it twice.
But if you press one of the special keys that return double values
you need to press it only once. That's because one keypress of, say F1,
returns 2 values (59, and 0): the first getch() in the program sees the zero
because that is the one sent last, but 59 is still in memory, and when it
encounters the second getch(); it is fed the value 59.

This function returns those values with additions to differentiate them from
the normal ascii values (eg. 59 is ;(semi-colon) in the ASCII character keyset.)
so 256 is added to the 59 for F1 and is returned as 315.

I have this program saved as "AllKeys.c" so that I can use it to quickly look up the key codes.
This program will exit when you hit the Esc key.
Suppose we want to perform a certain action when the user hits the F1 key. This function will return 315 for the F1 key. So we can declare an int variable, example 'key', and say 'key=get_key()', the program will wait for a user keypress, and if the user hits F1, 'key' will hold the value 315. Then we can do if(key==315){do your thing}.

By the way, Man Of Steel is friggin awesome! Watched it last night.

#include <stdio.h>
#include <conio.h>

int get_key()
{
    int c = getch(); //first getch() sees the first value
    switch (c)  //This will only take action if the value is 0 or 224
    {
      case 0:   return getch()+256;  //and this second getch() eats the 2nd value
      case 224: return getch()+512; //and 256 or 512 is added to it and returned.
    }
    return c;   //if the value is not 0 or 224 (IE key is not special) normal value is returned
}

int main()
{
    printf("Esc to exit: \n");
    int d;
    while ((d = get_key()) != 27)
    {
        printf( "%d\n", d);

        if(d==315)  //if the key if f1.....
        {
            printf("F1 Key!\n"); //print this
        }
    }
    printf( "%d\n",d); //print the return value of the key pressed
}


______________________________________________________________________________
EDIT:
I just saw that we can use the ctrl combination for most of the keys. Ctrl-a and ctrl-A both return value 1, combined with b it returns 2 and so on and so forth till 26 for ctrl-z.
These values are unique in the sense that no other key on the keyboard returns these values (1 through 26) because they are special characters not available on the keyboard,  except for Enter (value=13) is the same as Ctrl+m (value=13), Backspace (Value=8) is the same as Ctrl+h (value=8) and the TAB key (value=9) is the same as Ctrl+i (value=9). There may be others, but none I can find. Best avoid those combinations in our programs.
Incidentally, you can backspace using Ctrl+h when on the DOS screen, ESC using Ctrl+[ etc. So, it's not a problem we have to address I guess, DOS treats these return values as identical keys so we can do the same.

So yeah, I guess we can use ctrl combinations, unless you are Chuck Norris (Ref: Chuck Norris does not have Control keys on his keyboard; Chuck Norris is always in control). Now about the Alt keys.......