Solved

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

Posted on 1997-06-06
6
774 Views
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;

  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.
0
Comment
Question by:amorzari
  • 3
  • 2
6 Comments
 
LVL 3

Expert Comment

by:dhm
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.
0
 

Author Comment

by:amorzari
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.

0
 
LVL 3

Expert Comment

by:dhm
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.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:amorzari
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.


Thanks!
0
 
LVL 4

Accepted Solution

by:
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 jos@and.nl
0
 

Author Comment

by:amorzari
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!
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Expand data scrubbing tool 13 31
isEverywhere  challenge 19 64
FizzBuzz challenge 9 73
fix34  challenge 9 97
In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
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.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

759 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

18 Experts available now in Live!

Get 1:1 Help Now