/********************************************
 * MOUSE.C
 *
 * Adjusts settings of the internal mouse driver of DOSEMU
 *
 * Written by Kang-Jin Lee (lee@tengu.in-berlin.de) at 3/20/95
 * based on MOUSE.C in dosemu0.53.51 by ...
 *
 * Note:
 *   There are some incompatible changes in arguments
 *   - Arguments to switch between 2 and 3 button mouse mode has
 *     changed from m to 2 and p to 3
 *   - Mouse speed value ranges from 1 to 31 and is not multiplied by 8
 *   - Arguments are case insensitiv
 *   - Added argument h for help screen
 ********************************************/

#include <dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef unsigned int  uint16;

union REGS regs;

#define DOS_HELPER_INT           0xE6
#define DOS_HELPER_DOSEMU_CHECK  0x00

void (far * dosemu_id_proc)(void) = (void (far *)(void))MK_FP(0xfc00, 0x0000);
void (far * mouse_helper)(void)   = (void (far *)(void))MK_FP(0xfc00, 0x0ff5);

static uint16 version;

void MHLP(union REGS *regs)
{
  if (version > 61) {
    _AX = regs->x.ax;
    _BX = regs->x.bx;
    _CX = regs->x.cx;
    mouse_helper();
    regs->x.ax = _AX;
    regs->x.bx = _BX;
    regs->x.cx = _CX;
  }
  else {
    int86(0xe6, regs, regs);
  }
}

/* Show help screen */
void usage(void)
{
  printf("Usage: MOUSE [option]\n");
  printf("Utility to control the internal mousedriver of DOSEMU\n\n");
  printf("Options:\n");
  printf("  r       - Reset IRET.\n");
  printf("  i       - Inquire current configuration.\n");
  printf("  2       - Select 2 button mouse mode (Microsoft).\n");
  printf("  3       - Select 3 button mouse mode (e.g. Mousesystems, PS2).\n");
  printf("  x value - Set horizontal speed.\n");
  printf("  y value - Set vertical speed.\n");
  printf("  a       - Ignore application's setting of vert/horz speed settings.\n");
  printf("  b       - Take application's settings of vert/horz speed settings.\n");
  printf("  h       - Display this screen.\n\n");
  printf("Valid range for \"value\" is from 1 (slowest) to 31 (fastest).\n\n");
  printf("Example: MOUSE r a x 10 i\n");
  printf("reset, fixed speed setting, set horizontal speed to 10 and show current\n");
  printf("  configuraton of the mouse\n\n");

  exit(1);
}

/* returns non-zero major version number if DOSEMU is loaded */
uint16 CheckForDOSEMU(void)
{
    char far * id_string;

    _AH = 0xC0;
    geninterrupt(0x15);
    id_string = (char far *)MK_FP(_ES, _BX+10);
    if (_fstrncmp(id_string, "DOSEMU ", 7) == 0) {
       dosemu_id_proc();
       if (_AX == 0xaa55)
          return _BX;
    }

    _AH = 0x35;
    _AL = DOS_HELPER_INT;
    geninterrupt(0x21);
    if (_ES != 0 || _BX != 0) {
       _AL = DOS_HELPER_DOSEMU_CHECK;
       geninterrupt(DOS_HELPER_INT);
       if (_AX == 0xaa55)
          return _BX;
    }

    return (0);
}

/* Detect internal mouse driver of Linux */
void detectInternalMouse(void)
{
  regs.x.ax = 0x0033;
  regs.x.bx = 0x00ff;
  MHLP(&regs);
  if (regs.x.ax == 0xffff) {
    printf("ERROR! Internal driver option not set, enable internal driver\n");
    printf("       in /etc/dosemu.conf.\n");
    exit(1);
  }
}

main(int argc, char **argv)
{
  int i, value;

  if (argc == 1)
    usage();

  switch (argv[1][0]) {
    case '?':
    case 'H':
    case 'h':
      usage();
      break;
    default:
      break;
  }

  if ((version = CheckForDOSEMU()) == 0) {
    printf("ERROR: this program requires DOSEMU\n");
    exit(1);
  }
  detectInternalMouse();

  i = 1;

  while (i < argc)
  {
    switch(argv[i][0]) {

      case 'A':
      case 'a':
        printf("Fixed speed settings.\n");
        regs.h.cl = 0x0001;
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0006;
        MHLP(&regs);
        break;

      case 'B':
      case 'b':
        printf("Variable speed settings.\n");
        regs.h.cl = 0x0000;
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0006;
        MHLP(&regs);
        break;

      case 'R':
      case 'r':
        printf("Resetting iret.\n");
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0000;
        MHLP(&regs);
        break;

      case 'I':
      case 'i':
        printf("\nCurrent mouse setting:\n");
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0003;
        MHLP(&regs);
        if (regs.h.bh == 0x10)
          printf("  2 button mouse mode (Microsoft)\n");
        else
          printf("  3 button mouse mode (e.g. Mousesystems, PS2)\n");
        printf  ("  Horizontal Speed (X) - %d\n", regs.h.cl / 8);
        printf  ("  Vertical Speed   (Y) - %d\n", regs.h.ch / 8);
        printf  ("  Speed Setting        - %s\n\n", regs.h.dl ? "fixed" : "variable");
        break;

      case '3':
        printf("Selecting 3 button mouse mode (e.g. Mousesystems, PS2).\n");
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0002;
        MHLP(&regs);
        if (regs.h.al == 0xff) {
          printf("ERROR! Cannot select 3 button mouse mode, \"emulate3buttons\" not set\n");
          printf("       in /etc/dosemu.conf, try e.g.\n");
          printf("       'mouse { ps2 device /dev/mouse internaldriver emulate3buttons }'\n");
          exit (1);
        }
        break;

      case '2':
        printf("Selecting 2 button mouse mode (Microsoft).\n");
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0001;
        MHLP(&regs);
        break;

      case 'Y':
      case 'y':
        i++;
        if (i == argc) {
          printf("ERROR! No value for \"y\" found.\n");
          exit(1);
        }
        value = atoi(argv[i]);
        printf("Selecting vertical speed to %d.\n", value);
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0004;
        regs.h.cl = value;
        MHLP(&regs);
        if (regs.x.ax == 1) {
          printf("ERROR! Selected speed is out of range. Unable to set speed.\n");
          exit(1);
        }
        break;

      case 'X':
      case 'x':
        i++;
        if (i == argc) {
          printf("ERROR! No value for \"x\" found.\n");
          exit(1);
        }
        value = atoi(argv[i]);
        printf("Selecting horizontal speed to %d.\n", value);
        regs.x.ax = 0x0033;
        regs.x.bx = 0x0005;
        regs.h.cl = value;
        MHLP(&regs);
        if (regs.x.ax == 1) {
          printf("ERROR! Selected speed is out of range. Unable to set speed.\n");
          exit(1);
        }
        break;

      default:
        printf("ERROR! Unknown option \"%s\".\n\n", argv[i]);
        usage();
        /* never reached */
        break;

    } /* switch */

    i++;

  } /* while */

  return (0);

}
