Mouse Programming with libgpm
When I was first introduced to programming (back with DOS), I used to add mouse support to my applications to impress my teachers. Programming the mouse largely consisted of putting the right values in the registers (like 0x00 in the ax register to reset the mouse) and calling the interrupt service routine with int86 ( a function provided by Turbo C to access interrupt service routines). So when I put my hands on a Linux box, I looked for some thing similar. I soon found out that only root can access hardware registers directly. But there's an elegant way to handle this.
Welcome to the world of gpm and its client libraries. When I started searching for useful information about how to program mouses in UNIX (Linux in particular), I found some C code that let people access and program the mouse through /dev/mouse . But I was overwhelmed by the intricacies of handling different mice and was forced to look for other avenues. After pouring over the man pages of gpm, I learned to program the mouse with ease, and in no time, I was playing with my mouse. I was quite impressed by the extent of services these libraries provided and was compelled to explore them further.
It is quite easy to program with gpm and write portable and robust applications with a few lines of code. In this article, I will explain the concepts involved in programming the mouse with simple but effective examples. To compile them you will need libgpm, which can be obtained from ftp.prosa.it/pub/gpm. To compile the program successfully, you will have to add the -lgpm flag:
gcc [a c file that uses libgpm] -lgpm
Some programs require ncurses, which can be obtained from ftp.gnu.org/pub/gnu/ncurses. The programs that require curses have to be compiled with the -lncurses flag:
gcc [a c file which uses both libgpm and libncurses] -lgpm -lncurses
GPM (General Purpose Mouse): A Cut an Paste Utility and Mouser server for Linux Virtual Consoles.
These are the first lines of the man page on gpm. To put it simply gpm is a server that says "Hey! I know about the mouse installed here. I know how to handle its events. And I am here to serve you with whatever you are interested in." The clients simply have to connect to the server and inform it of which events they are interested in. They need not worry about the intricacies of the different types of mice. This client-server philosophy is put to its best in Unices. X is a very good example of how this architecture is put to useful ends. The server knows about the hardware, and it will handle all the dirty hardware interrupts, registers, etc. What the clients see is a unified interface that they can use to interact with the hardware. Henceforth, I will use the term gpm to refer to gpm and its libraries and the term server to refer to the gpm dæmon.
To handle the mouse with gpm, the client has to connect to the server and specify which events it wants to handle. The function Gpm_Open() takes a structure of type Gpm_Connect, whose variables have to be filled accordingly. The variables of interest in the Gpm_Connect structure are the eventMask, defaultMask, minMod and maxMod. The variable eventMask is a bitmask of the events the client is interested in. defaultMask specifies which events the client wants the server to handle in the default manner. Thus, we can explicitly specify the events we want to handle and tell the server to handle the others events in the default manner.
The variables minMod and maxMod can be used to access keyboard modifiers like ALT, CTRL and SHIFT. The client will not be informed about mouse events that are less than the set minimum and more than the set maximum. The following code explains these concepts and also shows how to read events.
#include <stdio.h>
#include <gpm.h>
int my_handler(Gpm_Event *event, void *data)
{ printf("Event Type : %d at x=%d y=%d\n", event->type, event->x, event->y);
return 0;
}
int main()
{ Gpm_Connect conn;
int c;
conn.eventMask = ~0; /* Want to know about all the events */
conn.defaultMask = 0; /* don't handle anything by default */
conn.minMod = 0; /* want everything */
conn.maxMod = ~0; /* all modifiers included */
if(Gpm_Open(&conn, 0) == -1)
printf("Cannot connect to mouse server\n");
gpm_handler = my_handler;
while((c = Gpm_Getc(stdin)) != EOF)
printf("%c", c);
Gpm_Close();
return 0;
}
This example introduces us to a useful function, Gpm_Getc(), that works like the ordinary getch() function, except that when a mouse event occurs it calls the gpm_handler with the event structure as a parameter. gpm_handler is a global variable initialized to null. Clients are required to initialize this variable with the function that defines the way they wish to handle events.
Now that we have seen how easy it is to get mouse events with gpm, let's dive into the details. The variables in the connection structure can be manipulated to handle only the events of our choice. For example, we don't want to handle motion and drag of the mouse and are interested only in the clicks of the mouse. Then we can use an eventMask like conn.eventMask = Gpm_Down; and a conn.defaultMask = ~conn.eventMask;. This will only report the mouse button down events to us. Similarly a prudent choice of minMod and maxMod can simplify programming and reduce overhead. It is also useful if you want to pass on the events to other processes.
If we set minMod and maxMod to zero, only mouse events are reported. If we are interested in only mouse + modifier events and not in mouse-only events, then minMod should be a combination of
conn.minMod = 1<<KG_SHIFT; conn.maxMod = ~0;
which tells the server that the client is interested in shift + mouse events but not interested in mouse-only events. This is how gpm-root works. gpm-root takes only the events with modifiers (by default CTRL only) and draws menus accordingly. But we have to remember that gpm-root knows about these events only if the application running on the console is not handling the events or if it has passed them to the default handler. That is why choosing the correct set of events is very important.
Note: You must include linux/keyboard.h to make use of the define constants KG_SHIFT, etc.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- Designing Electronics with Linux
- New Products
- Linux Systems Administrator
- Senior Perl Developer
- Technical Support Rep
- UX Designer
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Dynamic DNS—an Object Lesson in Problem Solving
- Web & UI Developer (JavaScript & j Query)
- Using Salt Stack and Vagrant for Drupal Development
- Reply to comment | Linux Journal
6 hours 19 min ago - Dynamic DNS
6 hours 53 min ago - Reply to comment | Linux Journal
7 hours 51 min ago - Reply to comment | Linux Journal
8 hours 41 min ago - Not free anymore
12 hours 43 min ago - Great
16 hours 30 min ago - Reply to comment | Linux Journal
16 hours 38 min ago - Understanding the Linux Kernel
18 hours 53 min ago - General
21 hours 23 min ago - Kernel Problem
1 day 7 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
Mouse programming
really good stuff ,
thanks to author , i got this at right time
Re: Mouse Programming with libgpm
I tried the sample progam but the #includes on
the website did not appear on my netscape.
So I used the obvious includes and it worked
just fine. Here are the includes you need
without angle brackets that this web site can't
digest. (Webmaster, please work on accepting
plain text in comments, we're not all MS junkies
here).
stdio.h
stdlib.h
ncurses.h
gpm.h
However, after exiting, the sample program, I
could not cut and paste as before to or from that
one xterm window. All other windows, xterm or
GUI, were unaffected. I don't know what this
means but I know it works in Xfree86 using Gnome.
I assume that means it works as well on the CRT
80x24 screen as well.
This might be something to follow up on for
anybody writing sam and smit type console programs
for linux administration. I know I hate using the
GUI with pictures, where you don't know if the
little birdie icon means add or delete. I like
the text based GUI that spells it out so you know
what you get when you press return, or maybe, now,
if you click on the highlighted text.
Re: Mouse Programming with libgpm
Which sample program you had problems? I checked all of them on plain console and I have no problems
--pradeep
Re: Mouse Programming with libgpm
This is that code.... after exiting .... just see whether cut copy paste with mouse works ... on the same xterm where u executed this program .
#include
#include
#include
#include
int my_handler(Gpm_Event *event, void *data)
{ printf("Event Type : %d at x=%d y=%d
", event->type, event->x, event->y);
return 0;
}
int main()
{ Gpm_Connect conn;
int c;
conn.eventMask = ~0; /* Want to know about all the events */
conn.defaultMask = 0; /* don't handle anything by default */
conn.minMod = 0; /* want everything */
conn.maxMod = ~0; /* all modifiers included */
if(Gpm_Open(&conn, 0) == -1)
printf("Cannot connect to mouse server
");
gpm_handler = my_handler;
while((c = Gpm_Getc(stdin)) != EOF)
printf("%c", c);
Gpm_Close();
return 0;
}
How to capture special keys like F1 F2 etc...
Gpm_Getc does not appear to be returning F1 F2... etc other keystrokes. Do u know how to capture those apart fromthis mouse and regular key strokes.
Suneel