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

Posted on 1997-06-06
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.
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.


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 130 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

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
iSeries FTP Exit Program 8 123
Host to IP 7 76
deburging in oracle form 12 88
My project did see openJDK that I installed. What could be the problem 7 122
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
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.
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

911 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now