NCURSES Programming HOWTO
Prev |  | Next

# 12. Interfacing with the mouse

Now that you have seen how to get keys, lets do the same thing from mouse. Usually each UI allows the user to interact with both keyboard and mouse.

## 12.1. The Basics

Before you do any thing else, the events you want to receive have to be enabled with `mousemask()`.

        mousemask(  mmask_t newmask,    /* The events you want to listen to */
                    mmask_t *oldmask)    /* The old events mask                */

The first parameter to above function is a bit mask of events you would like to listen. By default, all the events are turned off. The bit mask `ALL_MOUSE_EVENTS` can be used to get all the events.

The following are all the event masks:

        Name            Description
           ---------------------------------------------------------------------
           BUTTON1_PRESSED          mouse button 1 down
           BUTTON1_RELEASED         mouse button 1 up
           BUTTON1_CLICKED          mouse button 1 clicked
           BUTTON1_DOUBLE_CLICKED   mouse button 1 double clicked
           BUTTON1_TRIPLE_CLICKED   mouse button 1 triple clicked
           BUTTON2_PRESSED          mouse button 2 down
           BUTTON2_RELEASED         mouse button 2 up
           BUTTON2_CLICKED          mouse button 2 clicked
           BUTTON2_DOUBLE_CLICKED   mouse button 2 double clicked
           BUTTON2_TRIPLE_CLICKED   mouse button 2 triple clicked
           BUTTON3_PRESSED          mouse button 3 down
           BUTTON3_RELEASED         mouse button 3 up
           BUTTON3_CLICKED          mouse button 3 clicked
           BUTTON3_DOUBLE_CLICKED   mouse button 3 double clicked
           BUTTON3_TRIPLE_CLICKED   mouse button 3 triple clicked
           BUTTON4_PRESSED          mouse button 4 down
           BUTTON4_RELEASED         mouse button 4 up
           BUTTON4_CLICKED          mouse button 4 clicked
           BUTTON4_DOUBLE_CLICKED   mouse button 4 double clicked
           BUTTON4_TRIPLE_CLICKED   mouse button 4 triple clicked
           BUTTON_SHIFT             shift was down during button state change
           BUTTON_CTRL              control was down during button state change
           BUTTON_ALT               alt was down during button state change
           ALL_MOUSE_EVENTS         report all button state changes
           REPORT_MOUSE_POSITION    report mouse movement

## 12.2. Getting the events

Once a class of mouse events have been enabled, getch() class of functions return KEY_MOUSE every time some mouse event happens. Then the mouse event can be retrieved with `getmouse()`.

The code approximately looks like this:

        MEVENT event;

        ch = getch();
        if(ch == KEY_MOUSE)
            if(getmouse(&event) == OK)
                .    /* Do some thing with the event */
                .
                .

getmouse() returns the event into the pointer given to it. It's a structure which contains

        typedef struct
        {
            short id;         /* ID to distinguish multiple devices */
            int x, y, z;      /* event coordinates */
            mmask_t bstate;   /* button state bits */
        }

The `bstate` is the main variable we are interested in. It tells the button state of the mouse.

Then with a code snippet like the following, we can find out what happened.

        if(event.bstate & BUTTON1_PRESSED)
            printw("Left Button Pressed");

## 12.3. Putting it all Together

That's pretty much interfacing with mouse. Let's create the same menu and enable mouse interaction. To make things simpler, key handling is removed.

Example 11. Access the menu with mouse !!!

    #include <ncurses.h>

    #define WIDTH 30
    #define HEIGHT 10

    int startx = 0;
    int starty = 0;

    char *choices[] = { 	"Choice 1",
    			"Choice 2",
    			"Choice 3",
    			"Choice 4",
    			"Exit",
    		  };

    int n_choices = sizeof(choices) / sizeof(char *);

    void print_menu(WINDOW *menu_win, int highlight);
    void report_choice(int mouse_x, int mouse_y, int *p_choice);

    int main()
    {	int c, choice = 0;
    	WINDOW *menu_win;
    	MEVENT event;

    	/* Initialize curses */
    	initscr();
    	clear();
    	noecho();
    	cbreak();	//Line buffering disabled. pass on everything

    	/* Try to put the window in the middle of screen */
    	startx = (80 - WIDTH) / 2;
    	starty = (24 - HEIGHT) / 2;

    	attron(A_REVERSE);
    	mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)");
    	refresh();
    	attroff(A_REVERSE);

    	/* Print the menu for the first time */
    	menu_win = newwin(HEIGHT, WIDTH, starty, startx);
    	print_menu(menu_win, 1);
    	/* Get all the mouse events */
    	mousemask(ALL_MOUSE_EVENTS, NULL);

    	while(1)
    	{	c = wgetch(menu_win);
    		switch(c)
    		{	case KEY_MOUSE:
    			if(getmouse(&event) == OK)
    			{	/* When the user clicks left mouse button */
    				if(event.bstate & BUTTON1_PRESSED)
    				{	report_choice(event.x + 1, event.y + 1, &choice);
    					if(choice == -1) //Exit chosen
    						goto end;
    					mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
    					refresh();
    				}
    			}
    			print_menu(menu_win, choice);
    			break;
    		}
    	}
    end:
    	endwin();
    	return 0;
    }

    void print_menu(WINDOW *menu_win, int highlight)
    {
    	int x, y, i;

    	x = 2;
    	y = 2;
    	box(menu_win, 0, 0);
    	for(i = 0; i < n_choices; ++i)
    	{	if(highlight == i + 1)
    		{	wattron(menu_win, A_REVERSE);
    			mvwprintw(menu_win, y, x, "%s", choices[i]);
    			wattroff(menu_win, A_REVERSE);
    		}
    		else
    			mvwprintw(menu_win, y, x, "%s", choices[i]);
    		++y;
    	}
    	wrefresh(menu_win);
    }

    /* Report the choice according to mouse position */
    void report_choice(int mouse_x, int mouse_y, int *p_choice)
    {	int i,j, choice;

    	i = startx + 2;
    	j = starty + 3;

    	for(choice = 0; choice < n_choices; ++choice)
    		if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice]))
    		{	if(choice == n_choices - 1)
    				*p_choice = -1;
    			else
    				*p_choice = choice + 1;
    			break;
    		}
    }

## 12.4. Miscellaneous Functions

The functions mouse_trafo() and wmouse_trafo() can be used to convert to mouse co-ordinates to screen relative co-ordinates. See curs_mouse(3X) man page for details.

The mouseinterval function sets the maximum time (in thousands of a second) that can elapse between press and release events in order for them to be recognized as a click. This function returns the previous interval value. The default is one fifth of a second.

Prev | Home | Next
Interfacing with the key board |  | Screen Manipulation