Link to home
Start Free TrialLog in
Avatar of amorzari
amorzari

asked on

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;

  ctermid(termid);

  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;
    }

  ioctl(fd,I_PUSH,"kb");

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

  if (i == TR_ASCII) printf ("ASCII!\n");
  else
    if (i == TR_NONE) printf ("NONE!\n");
    else
      if (i == TR_EVENT) printf ("EVENT\n");
      else
      if (i== TR_UNTRANS_EVENT) printf ("UNTRANSEVENT\n");
      else
        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]=' ';
 
  j=-5;
  ioctl (fd,I_GRDOPT,&j);

 if (j==RNORM)
   printf("RNORM\n");
 if (j==RMSGD)
   printf("RMSGD\n");
 if (j==RMSGN)
   printf("RMSGN\n");

 kybstream=fdopen(fd,"r");

  for (k=0;k<100000;k++)
    {
      flag=0;
     
      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.
Avatar of dhm
dhm

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.
Avatar of amorzari

ASKER

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


Thanks!
ASKER CERTIFIED SOLUTION
Avatar of jos010697
jos010697

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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!