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

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.
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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.
amorzariAuthor Commented:
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.

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.
OWASP: Avoiding Hacker Tricks

Learn to build secure applications from the mindset of the hacker and avoid being exploited.

amorzariAuthor Commented:
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.

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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
amorzariAuthor Commented:
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!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.