home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / joyptrs.c < prev    next >
C/C++ Source or Header  |  1996-03-19  |  12KB  |  498 lines

  1. /* Read the joystick, and simulated mouse and key "joysticks" */
  2. // Implemented as pointer drivers.  These are good examples of how
  3. // simple pointer drivers can be.
  4.  
  5. // ALL code in this file by Dave Stampe, 12/24/93
  6.  
  7. /*
  8.  This code is part of the VR-386 project, created by Dave Stampe.
  9.  VR-386 is a desendent of REND386, created by Dave Stampe and
  10.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  11.  Stampre for VR-386.
  12.  
  13.  Copyright (c) 1994 by Dave Stampe:
  14.  May be freely used to write software for release into the public domain
  15.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  16.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  17.  this software or source code into their products!  Usually there is no
  18.  charge for under 50-100 items for low-cost or shareware products, and terms
  19.  are reasonable.  Any royalties are used for development, so equipment is
  20.  often acceptable payment.
  21.  
  22.  ATTRIBUTION:  If you use any part of this source code or the libraries
  23.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  24.  and any other authors in your documentation, source code, and at startup
  25.  of your program.  Let's keep the freeware ball rolling!
  26.  
  27.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  28.  REND386, improving programmer access by rewriting the code and supplying
  29.  a standard API.  If you write improvements, add new functions rather
  30.  than rewriting current functions.  This will make it possible to
  31.  include you improved code in the next API release.  YOU can help advance
  32.  VR-386.  Comments on the API are welcome.
  33.  
  34.  CONTACT: dstampe@psych.toronto.edu
  35. */
  36.  
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <dos.h>
  41. #include <bios.h>
  42. #include <conio.h>
  43.  
  44. #include "pointint.h"
  45. #include "vr_api.h"
  46. #include "vrconst.h"   /* for nouse joy ctrl */
  47. #include "pcdevice.h"  /* for low-level joystick and keyboard */
  48. #include "intmath.h"
  49.  
  50.  
  51. extern int joystick_j1;     /* raw joystick results */
  52. extern int joystick_j2;     /* modified directly by raw_joystick_read(); */
  53. extern int joystick_j3;     /* you may read these elsewhere for trackers */
  54. extern int joystick_j4;
  55. extern int joystick_buttons;
  56.  
  57. static int joy_ok = 1;
  58.  
  59. /* This routine reads the joystick, setting x y and buttons */
  60.  
  61. static int use_pothead = 0;      /* used by pot head tracker */
  62.  
  63. // returns: 0 if OK, 1 if failure, -1 if time to shutoff
  64.  
  65. static int joyx, joyy, joyb;
  66. static int jcenter_x, jcenter_y;
  67.  
  68. static int joystick_read()
  69. {
  70.  int c, k, jx, jy;
  71.  int ovf = 0;
  72.  int j;
  73.  
  74.  if(!joy_ok) return -1;
  75.  
  76.  c = 0x03;         // determine read mask
  77.  if(use_pothead) c |= 0x0C;          // force read of second input
  78.  
  79.  for(ovf=0;ovf<30;ovf++)               // wait till timeout or success
  80.    {
  81.     if(!raw_joystick_read(c)) break;
  82.    }
  83.  
  84.  if(ovf==30)    // not responding! so turn it off
  85.   {
  86.    joyx = joyy = 0;
  87.    joyb = 0;
  88.    joy_ok = 0;
  89.    return -1;
  90.   }
  91.  
  92.  joyb = joystick_buttons;
  93.  
  94.  joyx = joystick_j1-jcenter_x;
  95.  joyy = joystick_j2-jcenter_y;
  96.  
  97.  return 0;
  98. }
  99.  
  100. static int joystick_init()
  101. {
  102.  jcenter_x = jcenter_y = 0;
  103.  joystick_read();
  104.  jcenter_x = joyx;
  105.  jcenter_y = joyy;
  106.  return joystick_read();
  107. }
  108.  
  109.  
  110.  
  111. /* This routine returns two bits; bit 0 on => joystick 1 found, bit 1 => joystick 2 */
  112.  
  113. static int joystick_check(void)
  114. {
  115.   int c, cc, i, result;
  116.  
  117.   disable();
  118.   outportb(0x201,0xff); /* Trigger joystick */
  119.   c = inportb(0x201);
  120.   c = inportb(0x201);
  121.   c = inportb(0x201);
  122.   enable();
  123.  
  124.   cc = 0;
  125.   for(i=0;i<1000;i++)       /* wait a few milliseconds */
  126.    cc |= c ^ inportb(0x201);    /* and look for changes */
  127.  
  128.   result = 0;
  129.  
  130.   if (cc & 0x03) result |= 1;
  131.   if (cc & 0x0C) result |= 2;
  132.  
  133.   return result;
  134. }
  135.  
  136.  
  137. pconfig joy_pconfig = {
  138.     65536L, 65536L, 65536L,     /* position res: mm/tick in <16.16>  */
  139.     600, 600, 0, -600, -600, 0,     /* xyz ranges:                */
  140.     0, 0, 0, 0, 0, 0, 0, 0, 0,     /* no rotation                       */
  141.     640, 480,             /* mouse emulation limits (writable) */
  142.     P_HASB1 | P_HASB2 | P_HASX | P_HASY, /* databits  */
  143.     0, 0, 0,             /* modes, nullkey, flexnum           */
  144.     1, 10, 60,             /* delay, idelay, reads/sec          */
  145.     P_IS2DP | P_IS2D,     /* uses  */
  146.     "Joystick Driver for navigation"
  147. };
  148.  
  149. #define JTHRESHOLD 200
  150.  
  151. pconfig *joy_driver(int op, POINTER *p, int mode)
  152. {
  153.  union REGS r;
  154.  int type = FP_OFF(p); /* way to get integer arg. */
  155.  
  156.  switch(op)
  157.   {
  158.    case DRIVER_CMD:
  159.       if (!(type & P_CENTER)) break;
  160.       joystick_init();
  161.       break;
  162.    case DRIVER_INIT:
  163.       if(!joystick_check()) return NULL;
  164.       joystick_init();
  165.    case DRIVER_RESET:
  166.       joyx = joyy = joyb = 0;
  167.       break;
  168.  
  169.    case DRIVER_READ:        /* pointer (2DP) read */
  170.      if (mode == P_POINTER)
  171.        {
  172.      p->x = 0;            // first threshold for navigation...
  173.      p->y = 0;
  174.      if(!joy_ok) break;
  175.      joystick_read();
  176.      if (abs(joyx)<JTHRESHOLD && abs(joyy)<JTHRESHOLD) goto retbut;
  177.      if (joyx>JTHRESHOLD) joyx -= JTHRESHOLD;
  178.      else
  179.        {
  180.          if (joyx<-JTHRESHOLD) joyx += JTHRESHOLD;
  181.          else joyx = 0;
  182.        }
  183.     if (joyy > JTHRESHOLD) joyy -= JTHRESHOLD;
  184.     else
  185.       {
  186.         if (joyy<-JTHRESHOLD) joyy += JTHRESHOLD;
  187.         else joyy = 0;
  188.       }
  189.      p->x = joyx;
  190.      p->y = joyy;
  191. retbut:
  192.      p->z = 0;
  193.      p->buttons = joyb;
  194.        }
  195.      break;
  196.    case DRIVER_CHECK:
  197.       if(!joystick_check()) return NULL;
  198.     break;
  199.    case DRIVER_QUIT:
  200.     break;
  201.   }
  202.  return &joy_pconfig;
  203. }
  204.  
  205.  
  206.  
  207.  
  208. /************* USE MOUSE TO EMULATE JOYSTICK ***********/
  209.  
  210. static int oldalt = 0;
  211. static mjx = 0;
  212. static mjy = 0;
  213.  
  214. static int old_mjx = 0;
  215. static int old_mjy = 0;
  216.  
  217. #define MJOY_ENABLE   0x1000
  218. #define MJOY_VELOCITY 0x2000
  219.  
  220. static int mjoyx, mjoyy, mjoyb;
  221.  
  222. static imouse_joy(int mode)
  223. {
  224.   union REGS r;
  225.   int x,y,b;
  226.   int alt;
  227.  
  228.   if (0==(mode&MJOY_ENABLE))
  229.     {
  230.       r.h.ah = 2;
  231.       int86(0x16, &r, &r);
  232.       alt = r.h.al & 8;       // look for ALT key (temp mouse on)
  233.       if (alt == 0)
  234.     {
  235.       mjoyx = 0;           // no: clear data, exit
  236.       mjoyy = 0;
  237.       mjoyb = 0;
  238.       oldalt = 0;
  239.       return 0;
  240.     }
  241.       else
  242.     if (oldalt == 0)        // new alt: reset data
  243.       {
  244.         mjx = 0;
  245.         mjy = 0;
  246.         oldalt = alt;
  247.       }
  248.     }
  249.   r.x.ax = 3;             /* read button status */
  250.   int86(0x33, &r, &r);
  251.     {
  252.       int b=0;
  253.       if (r.x.bx & 1) b |= 2;
  254.       if (r.x.bx & 2) b |= 1;
  255.       mjoyb = b;
  256.     }
  257.  
  258.  r.x.ax = 11;             /* read motion counters */
  259.  int86(0x33, &r, &r);
  260.  if(0==(mode&MJOY_VELOCITY))
  261.    {
  262.      old_mjx = old_mjy = 0;
  263.      mjx = ((int) r.x.cx);     /* MOUSE STEP */
  264.      mjy = ((int) r.x.dx);
  265.  
  266.    }
  267.  else
  268.    {
  269.      if(mjoyb&1)    // go back to absolute for rotation
  270.        {
  271.      mjx = ((int) r.x.cx);
  272.      mjy = ((int) r.x.dx);
  273.        }
  274.      else
  275.        {
  276.      mjx = mjy = 0;
  277.      mjx = old_mjx;         /* save for reversion */
  278.      mjy = old_mjy;
  279.      mjx += ((int) r.x.cx)>>2;     /*  SPEED STEP */
  280.      mjy += ((int) r.x.dx)>>2;
  281.      if (mjx < -50) mjx = -50;
  282.      if (mjy < -50) mjy = -50;
  283.      if (mjx > 50) mjx = 50;
  284.      if (mjy > 50) mjy = 50;
  285.      old_mjx = mjx;
  286.      old_mjy = mjy;
  287.        }
  288.    }
  289.  mjoyx = mjx>>1;
  290.  mjoyy = mjy>>1;
  291.  return 1;
  292. }
  293.  
  294.  
  295. pconfig mjoy_pconfig = {
  296.     65536L, 65536L, 65536L,     /* position res: mm/tick in <16.16>  */
  297.     50, 50, 50, -50, -50, -50,     /* xyz ranges:                */
  298.     0, 0, 0, 0, 0, 0, 0, 0, 0,     /* no rotation                       */
  299.     640, 480,             /* mouse emulation limits (writable) */
  300.     P_HASB1 | P_HASB2 | P_HASX | P_HASY, /* databits  */
  301.     0, 0, 0,             /* modes, nullkey, flexnum           */
  302.     1, 10, 60,             /* delay, idelay, reads/sec          */
  303.     P_IS2DP | P_IS2D,     /* uses  */
  304.     "Mouse used for navigation"
  305. };
  306.  
  307. static int mjoy_mode = 0;
  308.  
  309. pconfig *mjoy_driver(int op, POINTER *p, int mode)
  310. {
  311.  union REGS r;
  312.  int type = FP_OFF(p); /* way to get integer arg. */
  313.  
  314.  switch(op)
  315.   {
  316.    case DRIVER_CMD:
  317.       mjoy_mode = type;
  318.       break;
  319.    case DRIVER_INIT:
  320.    case DRIVER_RESET:
  321.       mjoyx = mjoyy = mjoyb = 0;
  322.       mjx = mjy = old_mjx = old_mjy = 0;
  323.       break;
  324.  
  325.    case DRIVER_READ:        /* pointer (2DP) read */
  326.      if (mode == P_POINTER)
  327.        {
  328.      imouse_joy(mjoy_mode);
  329.      p->x = mjoyx;
  330.      p->y = mjoyy;
  331.      p->z = 0;
  332.      p->buttons = mjoyb;
  333.        }
  334.      break;
  335.    case DRIVER_CHECK:
  336.     break;
  337.    case DRIVER_QUIT:
  338.     break;
  339.   }
  340.  return &mjoy_pconfig;
  341. }
  342.  
  343.  
  344.  
  345. /************ USE KEY MONITOR TO FAKE JOYSTICK **********/
  346.  
  347. // NOTE: IF SHIFT SEEMS STUCK ON, TURN THE NUM LOCK OFF!
  348.  
  349. extern int use_keyjoy;
  350.  
  351. #define KJOY_SCALE 15
  352.  
  353. static int kmjoyx, kmjoyy, kmjoyb;
  354.  
  355. static int ikey_joy()
  356. {
  357.  int x, y, b;
  358.  union REGS regs;
  359.  
  360.  x = y = 0;
  361.  kmjoyx = x;
  362.  kmjoyy = y;
  363.  if(!use_keyjoy) return 0;
  364.  
  365.  if(is_key_down(UP_CURSOR_KEYCODE))    y = -KJOY_SCALE;
  366.  if(is_key_down(DOWN_CURSOR_KEYCODE))  y = KJOY_SCALE;
  367.  if(is_key_down(LEFT_CURSOR_KEYCODE))  x = -KJOY_SCALE;
  368.  if(is_key_down(RIGHT_CURSOR_KEYCODE)) x = KJOY_SCALE;
  369.  
  370.     // use BIOS for shift keys: tricky interactions in format
  371.  regs.h.ah = 2;                 // this will always work
  372.  int86(0x16, ®s, ®s);
  373.  b = (regs.h.al & 3);
  374.  
  375.  kmjoyx = x;
  376.  kmjoyy = y;
  377.  kmjoyb = b;
  378.  
  379.  if(x || y) return 1;
  380.  else return 0;
  381. }
  382.  
  383.  
  384.  
  385. pconfig keymon_pconfig = {
  386.     65536L, 65536L, 65536L,     /* position res: mm/tick in <16.16>  */
  387.     50, 50, 50, -50, -50, -50,     /* xyz ranges:                */
  388.     0, 0, 0, 0, 0, 0, 0, 0, 0,     /* no rotation                       */
  389.     640, 480,             /* mouse emulation limits (writable) */
  390.     P_HASB1 | P_HASB2 | P_HASX | P_HASY, /* databits  */
  391.     0, 0, 0,             /* modes, nullkey, flexnum           */
  392.     1, 10, 60,             /* delay, idelay, reads/sec          */
  393.     P_IS2DP | P_IS2D,     /* uses  */
  394.     "Key monitor for navigation"
  395. };
  396.  
  397.  
  398.  
  399. pconfig *keymon_driver(int op, POINTER *p, int mode)
  400. {
  401.  union REGS r;
  402.  int type = FP_OFF(p); /* way to get integer arg. */
  403.  
  404.  
  405.  switch(op)
  406.   {
  407.    case DRIVER_CMD:
  408.       break;
  409.    case DRIVER_INIT:
  410.     if(!keymon_on) return NULL;
  411.    case DRIVER_RESET:
  412.       kmjoyx = kmjoyy = kmjoyb = 0;
  413.       break;
  414.  
  415.    case DRIVER_READ:        /* pointer (2DP) read */
  416.      if (mode == P_POINTER)
  417.        {
  418.      ikey_joy();
  419.      p->x = kmjoyx;
  420.      p->y = kmjoyy;
  421.      p->z = 0;
  422.      p->buttons = kmjoyb;
  423.        }
  424.      break;
  425.    case DRIVER_CHECK:
  426.     if(!keymon_on) return NULL;
  427.     break;
  428.    case DRIVER_QUIT:
  429.     break;
  430.   }
  431.  return &keymon_pconfig;
  432. }
  433.  
  434.  
  435.  
  436. /************** KEY PRESSES: COMMANDS FROM KEYBOARD.C ******/
  437.  
  438.  
  439. #define KPRESS_SCALE 30
  440.  
  441. static int kjoyx, kjoyy, kjoyb;
  442.  
  443. // called from handle_motion_keys() in NAVJOY.C
  444.  
  445. void key_set_move(int x, int y, int b1, int b2)
  446. {
  447.   kjoyb = (b1?1:0) | (b2?2:0);
  448.   kjoyx = (!x)?0:((x>0)?KPRESS_SCALE:-KPRESS_SCALE);
  449.   kjoyy = (!y)?0:((y>0)?KPRESS_SCALE:-KPRESS_SCALE);
  450. }
  451.  
  452. pconfig key_pconfig = {
  453.     65536L, 65536L, 65536L,     /* position res: mm/tick in <16.16>  */
  454.     50, 50, 50, -50, -50, -50,     /* xyz ranges:                */
  455.     0, 0, 0, 0, 0, 0, 0, 0, 0,     /* no rotation                       */
  456.     640, 480,             /* mouse emulation limits (writable) */
  457.     P_HASB1 | P_HASB2 | P_HASX | P_HASY, /* databits  */
  458.     0, 0, 0,             /* modes, nullkey, flexnum           */
  459.     1, 10, 60,             /* delay, idelay, reads/sec          */
  460.     P_IS2DP | P_IS2D,     /* uses  */
  461.     "Default Key Press for navigation"
  462. };
  463.  
  464.  
  465.  
  466. pconfig *key_driver(int op, POINTER *p, int mode)
  467. {
  468.  union REGS r;
  469.  int type = FP_OFF(p); /* way to get integer arg. */
  470.  
  471.  switch(op)
  472.   {
  473.    case DRIVER_CMD:
  474.       break;
  475.    case DRIVER_INIT:
  476.    case DRIVER_RESET:
  477.       kjoyx = kjoyy = kjoyb = 0;
  478.       break;
  479.  
  480.    case DRIVER_READ:        /* pointer (2DP) read */
  481.      if (mode == P_POINTER)
  482.        {
  483.      p->x = kjoyx;
  484.      p->y = kjoyy;
  485.      p->z = 0;
  486.      p->buttons = kjoyb;
  487.      kjoyx = kjoyy = 0;
  488.        }
  489.      break;
  490.    case DRIVER_CHECK:
  491.     break;
  492.    case DRIVER_QUIT:
  493.     break;
  494.   }
  495.  return &key_pconfig;
  496. }
  497.  
  498.