Reading Scan Codes (or Extended Keys like Alt/SHIFT/CTRL) from SunOS (BSD) without curses or X

Posted on 1997-06-06
Medium Priority
Last Modified: 2013-12-26
I am writing a UNIX program that needs keyboard input above and beyond regular ASCII.  This is run on a Sparc-5, so I also want to detect the following:

      - F1-F12
      - Shift F1 - Shift F12
      - CTRL F1 - CTRL F12
      - Numpad (as "NUMPAD0" instead of just "0")
      - Insert/Del/Home/End/PGup/PGdown keys in block btwn keybaord and numpad.

I am running SunOS (4.1 I think). It is BSD, NOT SYSV, but the program may have to move to Solaris soon.

I have checked the UNIX programming FAQ and it doesn't help me much.  It shows me now to read a character, but not a *special* character..

Here's what I have found so far:

NCURSES (curses) Library:  This gives me the F1-F12 keys automatically (but not in all terminal modes), but cannot detect Shift/CTRL keys at all, and reports Numpad keys as regular ones.  It maps INS/HOME etc on the numpad, but not on the island between the main keyboard and the numpad.

Raw Mode Read (through /dev/tty), This only gives me ASCII codes (for the most part) and therefore cannot recognize extra keys properly either.

KB Streams Handler: (under "man kb").  This gives me exactly what I want, but I cannot even get a  test program to work properly.  If it worked, I can detect all of the above keys.

Here's my test program: It loops through until the end and then quits. (no response out of the read call)..  Please HELP! :-(

Or if you have an easier way (without resorting to X) then I would like to hear that too! Thanks!

WARNING: I don't know much about stream i/o as may be evident in the code below. I originally had the code reading from the file descriptor, but that was incorrect because the kb is a streams module.   Somebody said that I must open a stream and do an fread.  However, the ioctl calls work only on Unix File Descriptions (or so I believe).  My solution was to fiddle with all of the ioctl calls and then call fdopen() to associate it withe a stream. This doesn't work..  


#include <stdlib.h>
#include <stdio.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sundev/vuid_event.h>
#include <sundev/kbio.h>
#include <sundev/kbd.h>
#include <fcntl.h>
#include <sys/termios.h>
int ioctl (int, unsigned long, ...);

void main ()

  struct termios term;
  int size;
  int flag;
  char termid[L_ctermid];

  FILE *kybstream;

  long k;
  int cnt;


  printf ("terminal is %s\n",termid);

  if ((fd=open (termid,O_RDWR | O_EXCL | O_NONBLOCK,0)) <0)
      printf ("CANNOT OPEN TERMINAL %s\n\n",termid);
      exit -1;


// Get current Translation mode
  if ((ioctl (fd,KIOCGTRANS,(int*) &i))!=-1)
      printf ("IT WORKED!\n");
    } else {
      printf ("RETURNED -1!\n");

  if (i == TR_ASCII) printf ("ASCII!\n");
    if (i == TR_NONE) printf ("NONE!\n");
      if (i == TR_EVENT) printf ("EVENT\n");
      if (i== TR_UNTRANS_EVENT) printf ("UNTRANSEVENT\n");
        printf ("BLAH (%d)!\n",i);

   if (tcgetattr(fd, &term) <0)
      printf ("Could not get term\n");
      exit -1;

  term.c_lflag &= ~ICANON;
  if (tcsetattr(fd,TCSANOW, &term) < 0)
      printf ("Could not set term\n");
      exit -1;

  bufchar[0]=' ';
  ioctl (fd,I_GRDOPT,&j);

 if (j==RNORM)
 if (j==RMSGD)
 if (j==RMSGN)


  for (k=0;k<100000;k++)
      if ((k % 1000) ==0) printf (".\n");
      if ((fread(bufchar,20,1,kybstream)) > 0)
        printf ("GOT=>(%c) (%d)\n",bufchar[0],(int)bufchar[0]);
ioctl (fd,I_POP,"kb");

close (fd);

  printf ("testing\n");


As you will see, all the IOCTL calls are successful if you push "kb" onto fd, but I can no longer read.  If I remove all the ioctl calls to "kb", then I can do raw mode nonblocking reads, but I only get ASCII codes, not scan codes.

The other part is that a KIOCTYPE call reveals a "-1" (unknown) for keyboard type, but my sparc-5 keyboard is supposed to be backwards compatible to the sparc 4.. (The #define's only go up to sparc 4)..

If anybody out there can help me, I would *REALLY* appreciate it.

Also, if you have ANOTHER way of doing this (without resorting to Xwindows), please let me know.
Question by:amorzari
  • 3
  • 2

Expert Comment

ID: 1293239
I haven't used SunOS for several years (and don't have a machine available to test) but your code looks a lot like what the Solaris-2.5.1 man pages suggest.  If you were using Solaris (and you mention you might) I think you'd need to open "/dev/kb" instead of the name returned by ctermid() in order to use

ioctl( fd, I_PUSH, "kb" );

If you have a file called "/dev/kb" or perhaps "/dev/kbd", you might want to try opening that, and doing your ioctl() on the resulting descriptor.

If it'll help, I can probably whip up something for 2.4 or 2.5.1, but I won't go to the trouble if you're just going to reject the answer because it's not for SunOS.

Author Comment

ID: 1293240
I have tried opening "/dev/kbd" as well as "/dev/console" as well as the actually tty (e.g. /dev/tty06) since ctermid only returns "/dev/tty".

The problem remains the same even while opening /dev/kbd, but instead of arresting the input for only that window, it grabs input for the whole system, and basically stops the system. The device "kb" doesn't exist (but presumably, it is the same as /dev/kbd".  Sorry, but "tried that, failed at that". :-(

Occassionally when I run OpenWindows (SunOS) NORMALLY, (i.e, not running any keyboard programs, just regular use), I get an ioctl translation call error when I exit. (Similiar to a broken pipe type of message).  It is an ioctl call for KIOCSLED (Set keyboard led) so I know it is possible under SunOS (since Openwindows is obviously using the same calls as I am).

The possibility of it working under Solaris is great, but since I know it is (somehow) possible to get this to work under SunOS, I want it to work for me as well. The port to Solaris isn't due until development is almost complete.

Sorry, but I have to wait for a SunOS answer.  However, I am raising the points to 115.  I hope you can help.


Expert Comment

ID: 1293241
Ahhh...I see.  I thought the reason you didn't want an X Windows program was that you didn't want to run X, but you're acutally running OpenWindows, and just don't want to write an X program.  Unfortunately, I don't think you'll be able to get raw keyboard input directly from the system while you're running X -- as you guessed, OpenWindows is doing the same thing you are to get raw keyboard input.  This means that it's already grabbed the keyboard, and doesn't expect you to be fiddling with it.  That's why the system hung when you opened /dev/kbd.

As I see it, you have two options: first, only run your program in console mode (then you should have no problem opening /dev/kbd, and your current program [with some mods] will work fine).  Or second, write an X program.  It's not *that* hard just to get keyboard input, but there's probably a lot more that you want to do, and I know that X can get hairy.  Which one you choose depends on what you're ultimately trying to do, and how important it is to have it run on under both OpenWindows and on the console.

BTW, don't forget that dial-in and telnet users won't be able to use your app at all if it depends on being able to get key down/up information directly from the keyboard; as you discovered, curses doesn't provide that information.
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.


Author Comment

ID: 1293242
Sorry, but I am looking for a non-Xwindows answer.  I have seen many programs that can read keyboard input (as I want) but are not "X" applications.  I have tried to use my code snippet in console mode, and have results identical to being out of Xwindows.  I know it is possible, but I just don't know how under SunOS.

The stipulation about "no Xwindows" relates to not using Xwindows calls (ie.. an X-app).  The idea is to run 60 "virtual" terminals on the same machine (and only inhouse use), so compatibility for telnet users is not an issue.

However, if you have any solutions that don't require Xwindows (Xlib) calls, I would still love to hear them.


Accepted Solution

jos010697 earned 260 total points
ID: 1293243
You're working almost at the bare metal level. The /dev/kb(d)
streams module does not deliver its output through calls of
read(2). You have to use ioctl() calls for that. Basically it
boils down to calling ioctl with command KIOCSKEY and
a pointer to a struct kiockeymap structure. If a key press
is present (it's called a 'station' in kb-module's terminology,
don't ask me why), the structure reflects everything about
what was pressed (alts, cntrls, shifts etc.etc.)

This is from the top of my head, please check your manual
entries for ioctl(2), kb(7) and related stuff mentioned in the
man pages ...

kind regards,

Jos aka jos@and.nl

Author Comment

ID: 1293244
Sorry for the late reply..

I have tried the above.. (I tried both KOICSKEY as well as KOICGKEY).. I also looked at the definition from the kbio.h file.. (Just my luck, I can't get them to work either.. <grin>)  I tried this from the regular console (i.e. no windowing system) as well as within OpenWindows and with equally bad results..

However, from my understanding of kbio.h, these are to change the definition map of the keys and not actually to read the keys.. This could be wrong, but that is how I read the comments in the file..

I have ofcourse looked at the man pages and it says to look at the .h file.. <argh!>

Can you help me out a bit more? (Or EVEN, suggest another/better method of grabbing the keys I want?)  I am raising the points on the question again..

Thanks in advance!

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question