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

int write_buf(void);

extern unsigned keycode;
int name_counter = 0;

// ========================================
// application(void)
// Вызывается при активизации TSR. Из этой
// функции можно вызывать прерывания MS-DOS
// ========================================
void application(void)
{
  if(keycode == HotKeyRecording)
  {
      write_buf();
      Beep();
  }
}

// ========================================
// Beep
// Выдача звукового сигнала.
// ========================================
void Beep(void)
{
  union REGS regs;
  regs.x.ax = 0x0e07;
  regs.x.bx = 0x0000;
  int86(0x10, &regs, &regs);
}

// ========================================
// get_vmode
// Функция возвращает номер
// текущего видеорежима
// ========================================
int get_vmode(void)
{
  char far *ptr;

  // Получаем указатель на байт, содержащий
  // номер текущего видеорежима
  ptr = (char far*)MK_FP(0x40, 0x49);
  return(*ptr);
}

// ========================================
// get_vbuf
// Функция возвращает сегментный адрес
// видеопамяти. Учитывается содержимое
// регистров смещения адреса видеобуфера.
// ========================================
int get_vbuf(int vmode)
{
  unsigned vbase;
  unsigned adr_6845;
  unsigned high;
  unsigned low;
  unsigned offs;

  // В зависимости от видеорежима базовый адрес
  // видеопамяти может быть 0xb000 или 0xb800
  vbase = (vmode == 7) ? 0xb000 : 0xb800;

  // Получаем адрес порта видеоконтроллера
  adr_6845 = *(unsigned far*)(MK_FP(0x40, 0x63));

  // Считываем содержимое регистров 12 и 13
  // видеоконтроллера
  outp(adr_6845, 0xc);
  high = inp(adr_6845 + 1);

  outp(adr_6845, 0xd);
  low = inp(adr_6845 + 1);

  offs = ((high << 8) + low) >> 4;

  // Добавляем к базовому адресу видеопамяти
  // смещение, взятое из регистров видеоконтроллера
  vbase += offs;

  return(vbase);
}

// ========================================
// get_column
// Функция возвращает количество символов в строке
// для текущего видеорежима
// ========================================
int get_column(void)
{
  return(*(int _far *)(MK_FP(0x40, 0x4a)));
}

// ========================================
// get_row
// Функция возвращает количество строк
// для текущего видеорежима
// ========================================
int get_row(void)
{
  unsigned char ega_info;
  ega_info =
    *(unsigned char far*)(MK_FP(0x40, 0x87));

  // Если тип контроллера не EGA, то размер
  // экрана по вертикали составляет 25 строк.
  // Если установлен контроллер EGA, число
  // строк находится в области данных
  // BIOS по адресу 0040:0084.

  if(ega_info == 0 || ( (ega_info & 8) != 0) )
  {
    return(25);
  }
  else
  {
    return((*(unsigned char far *)
      (MK_FP(0x40, 0x84))) + 1);
  }
}

// ========================================
// write_buf
// Функция записи содержимого видеобуфера в
// файл
// ========================================
int write_buf(void)
{
  // Видеопамять состоит из байтов символов и байтов
  // атрибутов. Нам нужны байты символов chr.
  typedef struct _VIDEOBUF_
  {
    unsigned char chr;
    unsigned char attr;
  } VIDEOBUF;

  VIDEOBUF far *vbuf;
  int i, j, k, max_col, max_row;
  FILE *out_file;
  char fname[20], ext[8];

  // Определяем видеорежим
  i = get_vmode();

  // Для графического режима ничего не записываем
  if(i > 3 && i != 7) return(-1);

  // Устанавливаем указатель vbuf на видеобуфер
  vbuf = (VIDEOBUF far *)MK_FP(get_vbuf(i), 0);

  // Определяем размеры экрана
  max_col = get_column();
  max_row = get_row();

  // Формируем имя файла для записи образа экрана

  itoa(name_counter++, ext, 10);
  strcpy(fname,"!grab");
  strcat(fname, ext);
  strcat(fname,".scr");

  out_file = fopen(fname,"wb+");

  // Записываем содержимое видеобуфера в файл
  for(i = 0; i < max_row; i++)
  {
    for(j = 0; j < max_col; j++)
    {
      fputc(vbuf->chr, out_file);
      vbuf++;
    }

    // В конце каждой строки добавляем
    // символы перевода строки и
    // возврата каретки
    fputc(0xd, out_file);
    fputc(0xa, out_file);
  }
  fclose(out_file);
  return(0);
}
