Robert Hartmann
2010-09-21 14:34:35 UTC
Hallo zusammen,
den blinkenden Cursor komplett auszuschalten oder ihn auch wieder an
zuschalten ging ganz einfach.
Nun will ich zwischen dem blinkenden Unterstrich bzw der Box hin und her
schalten.
Das Abfragen der Cursorfüllhöhe also die benutzten Scanlines
geht mit
/*
* VIDEO - GET CURSOR POSITION AND SIZE [int 10/AH=03h]
* http://www.ctyme.com/intr/rb-0088.htm
*
* AH = 03h
* BH = page number
* 0-3 in modes 2&3
* 0-7 in modes 0&1
* 0 in graphics modes
*
* Return:
* AX = 0000h (Phoenix BIOS) CH = start scan line CL = end scan line
* DH = row (00h is top) DL = column (00h is left)
*
*/
Mit der Information über die Anzahl der Scanlines,
die für ein Zeichen benutzt werden, -- die Anzahl mit 2 Byte
findet man in der BIOS-DATA-AREA bei 0040:0000h + 85h Offset
[vgl. http://www.bioscentral.com/misc/bda.htm ] --
kann man leicht die prozentuale Befüllung der Zelle durch den
Cursor berechnen:
procent = ((regs.h.cl - regs.h.ch)*100)/NumberOfScanlinesPerCharacter;
Soweit so gut.
Nun probiere ich den Weg andersherum. Aus einer prozentualen Füllhöhe
möchte ich die notwendigen ScanLines bestimmen, damit ich alle Parameter
zusammen habe, um folgendes auszuführen.
/* VIDEO - SET TEXT-MODE CURSOR SHAPE [Int 10/AH=01h]
* http://www.ctyme.com/intr/rb-0086.htm
*
* AH = 01h
* CH = cursor start and options [options see below]
* CL = bottom scan line containing cursor (bits 0-4)
*
*
* Bitfields for cursor start and options:
* Bit(s) Description (Table 00013)
* 7 should be zero
* 6,5 cursor blink.
* (00=normal, 01=invisible, 10=erratic, 11=slow).
* (00=normal, other=invisible on EGA/VGA)
* 4-0 topmost scan line containing cursor
*
*/
/* Befüllung der Scanline von start(unten,bottom) nach end(oben,top).*/
Was mich stutzig macht, nachdem mein Code (s.u.) nicht so funktioniert
wie ich es dachte, ist :
Man hat der Beschreibung nach jeweils 4 Bit um Start- und End-Scanline
des Cursors festzulegen.
Die Anzahl der Scanlines eines Zeichen jedoch brauchen 2Byte (2*8 Bit =
16 Bit)
Die Rückgabe der ScanLines sind jeweils 2 8bit (unsigned char) Werte.
Irgendwie passt das nicht alles zusammen ...
Und hier ist mein Code. Wo ist der algorithmische oder Wertebereichsfehler?
Danke und Gruß Robert
/********* CODE hier **********/
#include<stddef.h>
#include<stdlib.h>
#include<assert.h>
#ifdef __STRICT_ANSI
#error For some reasons you cannot compile this code in strict_ansi_c
#endif
#include<stdio.h>
#include<string.h>
#include<limits.h>
#ifdef __MSDOS__
#include<dos.h>
#ifdef __DJGPP__
#include<dpmi.h>
#include<go32.h>
#include<sys/farptr.h>
#include<sys/segments.h>
#endif /*DJGPP*/
#elif defined(__WIN32__) || defined(_MSC_VER)
#include<windows.h>
#include<malloc.h>
#elif defined(__unix__) && !defined(__MSDOS__) && !defined(__WIN32__)
#error kommt spaeter dran :-)
#else
#error Code for your system or compiler is not implemented jet. feel
free to do :-)
#endif
enum CURSORMODE {_NOCURSOR = 0,
_SOLIDCURSOR = 1,
_NORMALCURSOR = 2};
typedef enum CURSORMODE CURSORMODE;
struct CURSOR_INFO {
unsigned long procent;
CURSORMODE mode;
};
typedef struct CURSOR_INFO CURSOR_INFO;
void setCursorMode(CURSOR_INFO cmode){
#ifdef __MSDOS__
#if ((CHAR_BIT != 8)||(UCHAR_MAX != 0xFF))
#error the size of unsigned char must be 1 byte with 8 bit
#endif
#if (USHRT_MAX != 0xFFFF)
#error the size of unsigned short must be 2 byte
#endif
/* BasePointer for BiosDataArea access*/
unsigned BDA_seg;
unsigned BDA_off;
#ifdef __TURBOC__
/*Because we must use a 2-byte-block of BIOS-DATA-AREA as value: */
unsigned short far* BiosDataArea_ShortPointer = NULL;
#elif __DJGPP__
/* in DJGPP we solve it without a special pointer */
/* unsigned short * BiosDataArea_Pointer = NULL; */
#else
#error your compiler has not been testet ... you must modify souce code
here.
#endif
unsigned short NumberOfScanlinesPerCharacter,startline,endline;
unsigned long top;
union REGS regs;
NumberOfScanlinesPerCharacter = startline = endline = 0;
top = 0;
/* set BasePointer to BiosDataArea segment:offset = 0040h:0000h*/
BDA_seg = 0x0040;
BDA_off = 0x0000;
/*
we must use a pointer to 0040:0000h + 85h Offset
(and optain the next 2 bytes as value for NumberOfScanlinesPerCharacter)
*/
BDA_off += 0x0085;
#ifdef __TURBOC__
BiosDataArea_ShortPointer = (unsigned short far*) MK_FP(BDA_seg,BDA_off);
if (BiosDataArea_ShortPointer)
NumberOfScanlinesPerCharacter = BiosDataArea_ShortPointer[0];
#elif __DJGPP__
/* Use _farpeekw to peek at 16-bit shorts and _farpeekl to peek at
32-bit longs.*/
NumberOfScanlinesPerCharacter = _farpeekw( _dos_ds, BDA_seg*16 + BDA_off );
#endif
/* get current information about cursor scanlines: start and end */
regs.h.ah = 3; /* get cursor position and size */
regs.h.bh = 0; /* video page #0 */
int86(0x10, ®s, ®s);
startline = regs.h.ch; /* start scan line (bottom)*/
endline = regs.h.cl; /* end scan line (top) */
/* ... just for documentation
*
* procent = ((top-start)*100) / NumberOfScanlinesPerCharacter
*
* => top = ((procent * NumberOfScanlinesPerCharacter) / 100 ) + start
*
*/
/* VIDEO - SET TEXT-MODE CURSOR SHAPE [Int 10/AH=01h]
* http://www.ctyme.com/intr/rb-0086.htm
*
* AH = 01h
* CH = cursor start and options [options see below]
* CL = bottom scan line containing cursor (bits 0-4)
*
*
* Bitfields for cursor start and options:
* Bit(s) Description (Table 00013)
* 7 should be zero
* 6,5 cursor blink.
* (00=normal, 01=invisible, 10=erratic, 11=slow).
* (00=normal, other=invisible on EGA/VGA)
* 4-0 topmost scan line containing cursor
*
*
* Befüllung der Scanline von start(unten,bottom) nach end(oben,top).
*/
/* Algorithmus:
* StartScanLine (bottom) bleibt erhalten
* EndSanLine (top) wird entsprechend der Prozentangabe modifiziert
* CursorBlink wird entsprechend cmode.mode verändert
*/
top = ((cmode.procent * NumberOfScanlinesPerCharacter) / 100 ) +
startline ;
endline = (top<=0x0F? (unsigned short)top : 0x0F );
/* 1000 0000 = 0x80 */
/* 0111 1111 = 0x7F */
/* CURSOR BLINK NORMAL */
/* 0001 0000 = 0x10 */
/* CURSOR BLINK INVISIBLE */
/* 0011 0000 = 0x30 */
/*determine the correct bits for option */
if(cmode.mode == _NOCURSOR){
regs.h.ch = 0x7F & 0x30 ; /* option: cursor invisible */
} else {
regs.h.ch = 0x7F & 0x10 ; /* option: cursor blink normal */
}
regs.x.ax = 0;
regs.x.bx = 0;
regs.h.ah = 1; /* SET TEXT-MODE CURSOR SHAPE */
regs.h.ch = regs.h.ch | ( 0x0F & endline); /* options + top*/
regs.h.cl = (0x0F & startline); /* bottom */
assert((regs.h.ch<=0xFF)&&(regs.h.ch>0x00));
assert((regs.h.cl<=0xFF)&&(regs.h.cl>0x00));
int86(0x10, ®s, ®s);
/* TODO: warum macht es nicht das,
was ich dachte, dass es soll ?? !*/
#elif defined(__WIN32__) || defined(_MSC_VER)
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &CursorInfo);
switch(cmode.mode){
case _NOCURSOR: setCursorOff(); break;
case _SOLIDCURSOR: CursorInfo.dwSize=100;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
case _NORMALCURSOR: CursorInfo.dwSize=25;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
default: CursorInfo.dwSize = cmode.procent;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
}
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &CursorInfo);
#elif defined(__unix__) && !defined(__MSDOS__) && !defined(__WIN32__)
#error kommt spaeter dran
#else
#error setCursorColor(CURSORMODE): Code for your system or compiler is
not implemented jet. feel free to do :-)
#endif
}
/********* CODE endet hier **********/
den blinkenden Cursor komplett auszuschalten oder ihn auch wieder an
zuschalten ging ganz einfach.
Nun will ich zwischen dem blinkenden Unterstrich bzw der Box hin und her
schalten.
Das Abfragen der Cursorfüllhöhe also die benutzten Scanlines
geht mit
/*
* VIDEO - GET CURSOR POSITION AND SIZE [int 10/AH=03h]
* http://www.ctyme.com/intr/rb-0088.htm
*
* AH = 03h
* BH = page number
* 0-3 in modes 2&3
* 0-7 in modes 0&1
* 0 in graphics modes
*
* Return:
* AX = 0000h (Phoenix BIOS) CH = start scan line CL = end scan line
* DH = row (00h is top) DL = column (00h is left)
*
*/
Mit der Information über die Anzahl der Scanlines,
die für ein Zeichen benutzt werden, -- die Anzahl mit 2 Byte
findet man in der BIOS-DATA-AREA bei 0040:0000h + 85h Offset
[vgl. http://www.bioscentral.com/misc/bda.htm ] --
kann man leicht die prozentuale Befüllung der Zelle durch den
Cursor berechnen:
procent = ((regs.h.cl - regs.h.ch)*100)/NumberOfScanlinesPerCharacter;
Soweit so gut.
Nun probiere ich den Weg andersherum. Aus einer prozentualen Füllhöhe
möchte ich die notwendigen ScanLines bestimmen, damit ich alle Parameter
zusammen habe, um folgendes auszuführen.
/* VIDEO - SET TEXT-MODE CURSOR SHAPE [Int 10/AH=01h]
* http://www.ctyme.com/intr/rb-0086.htm
*
* AH = 01h
* CH = cursor start and options [options see below]
* CL = bottom scan line containing cursor (bits 0-4)
*
*
* Bitfields for cursor start and options:
* Bit(s) Description (Table 00013)
* 7 should be zero
* 6,5 cursor blink.
* (00=normal, 01=invisible, 10=erratic, 11=slow).
* (00=normal, other=invisible on EGA/VGA)
* 4-0 topmost scan line containing cursor
*
*/
/* Befüllung der Scanline von start(unten,bottom) nach end(oben,top).*/
Was mich stutzig macht, nachdem mein Code (s.u.) nicht so funktioniert
wie ich es dachte, ist :
Man hat der Beschreibung nach jeweils 4 Bit um Start- und End-Scanline
des Cursors festzulegen.
Die Anzahl der Scanlines eines Zeichen jedoch brauchen 2Byte (2*8 Bit =
16 Bit)
Die Rückgabe der ScanLines sind jeweils 2 8bit (unsigned char) Werte.
Irgendwie passt das nicht alles zusammen ...
Und hier ist mein Code. Wo ist der algorithmische oder Wertebereichsfehler?
Danke und Gruß Robert
/********* CODE hier **********/
#include<stddef.h>
#include<stdlib.h>
#include<assert.h>
#ifdef __STRICT_ANSI
#error For some reasons you cannot compile this code in strict_ansi_c
#endif
#include<stdio.h>
#include<string.h>
#include<limits.h>
#ifdef __MSDOS__
#include<dos.h>
#ifdef __DJGPP__
#include<dpmi.h>
#include<go32.h>
#include<sys/farptr.h>
#include<sys/segments.h>
#endif /*DJGPP*/
#elif defined(__WIN32__) || defined(_MSC_VER)
#include<windows.h>
#include<malloc.h>
#elif defined(__unix__) && !defined(__MSDOS__) && !defined(__WIN32__)
#error kommt spaeter dran :-)
#else
#error Code for your system or compiler is not implemented jet. feel
free to do :-)
#endif
enum CURSORMODE {_NOCURSOR = 0,
_SOLIDCURSOR = 1,
_NORMALCURSOR = 2};
typedef enum CURSORMODE CURSORMODE;
struct CURSOR_INFO {
unsigned long procent;
CURSORMODE mode;
};
typedef struct CURSOR_INFO CURSOR_INFO;
void setCursorMode(CURSOR_INFO cmode){
#ifdef __MSDOS__
#if ((CHAR_BIT != 8)||(UCHAR_MAX != 0xFF))
#error the size of unsigned char must be 1 byte with 8 bit
#endif
#if (USHRT_MAX != 0xFFFF)
#error the size of unsigned short must be 2 byte
#endif
/* BasePointer for BiosDataArea access*/
unsigned BDA_seg;
unsigned BDA_off;
#ifdef __TURBOC__
/*Because we must use a 2-byte-block of BIOS-DATA-AREA as value: */
unsigned short far* BiosDataArea_ShortPointer = NULL;
#elif __DJGPP__
/* in DJGPP we solve it without a special pointer */
/* unsigned short * BiosDataArea_Pointer = NULL; */
#else
#error your compiler has not been testet ... you must modify souce code
here.
#endif
unsigned short NumberOfScanlinesPerCharacter,startline,endline;
unsigned long top;
union REGS regs;
NumberOfScanlinesPerCharacter = startline = endline = 0;
top = 0;
/* set BasePointer to BiosDataArea segment:offset = 0040h:0000h*/
BDA_seg = 0x0040;
BDA_off = 0x0000;
/*
we must use a pointer to 0040:0000h + 85h Offset
(and optain the next 2 bytes as value for NumberOfScanlinesPerCharacter)
*/
BDA_off += 0x0085;
#ifdef __TURBOC__
BiosDataArea_ShortPointer = (unsigned short far*) MK_FP(BDA_seg,BDA_off);
if (BiosDataArea_ShortPointer)
NumberOfScanlinesPerCharacter = BiosDataArea_ShortPointer[0];
#elif __DJGPP__
/* Use _farpeekw to peek at 16-bit shorts and _farpeekl to peek at
32-bit longs.*/
NumberOfScanlinesPerCharacter = _farpeekw( _dos_ds, BDA_seg*16 + BDA_off );
#endif
/* get current information about cursor scanlines: start and end */
regs.h.ah = 3; /* get cursor position and size */
regs.h.bh = 0; /* video page #0 */
int86(0x10, ®s, ®s);
startline = regs.h.ch; /* start scan line (bottom)*/
endline = regs.h.cl; /* end scan line (top) */
/* ... just for documentation
*
* procent = ((top-start)*100) / NumberOfScanlinesPerCharacter
*
* => top = ((procent * NumberOfScanlinesPerCharacter) / 100 ) + start
*
*/
/* VIDEO - SET TEXT-MODE CURSOR SHAPE [Int 10/AH=01h]
* http://www.ctyme.com/intr/rb-0086.htm
*
* AH = 01h
* CH = cursor start and options [options see below]
* CL = bottom scan line containing cursor (bits 0-4)
*
*
* Bitfields for cursor start and options:
* Bit(s) Description (Table 00013)
* 7 should be zero
* 6,5 cursor blink.
* (00=normal, 01=invisible, 10=erratic, 11=slow).
* (00=normal, other=invisible on EGA/VGA)
* 4-0 topmost scan line containing cursor
*
*
* Befüllung der Scanline von start(unten,bottom) nach end(oben,top).
*/
/* Algorithmus:
* StartScanLine (bottom) bleibt erhalten
* EndSanLine (top) wird entsprechend der Prozentangabe modifiziert
* CursorBlink wird entsprechend cmode.mode verändert
*/
top = ((cmode.procent * NumberOfScanlinesPerCharacter) / 100 ) +
startline ;
endline = (top<=0x0F? (unsigned short)top : 0x0F );
/* 1000 0000 = 0x80 */
/* 0111 1111 = 0x7F */
/* CURSOR BLINK NORMAL */
/* 0001 0000 = 0x10 */
/* CURSOR BLINK INVISIBLE */
/* 0011 0000 = 0x30 */
/*determine the correct bits for option */
if(cmode.mode == _NOCURSOR){
regs.h.ch = 0x7F & 0x30 ; /* option: cursor invisible */
} else {
regs.h.ch = 0x7F & 0x10 ; /* option: cursor blink normal */
}
regs.x.ax = 0;
regs.x.bx = 0;
regs.h.ah = 1; /* SET TEXT-MODE CURSOR SHAPE */
regs.h.ch = regs.h.ch | ( 0x0F & endline); /* options + top*/
regs.h.cl = (0x0F & startline); /* bottom */
assert((regs.h.ch<=0xFF)&&(regs.h.ch>0x00));
assert((regs.h.cl<=0xFF)&&(regs.h.cl>0x00));
int86(0x10, ®s, ®s);
/* TODO: warum macht es nicht das,
was ich dachte, dass es soll ?? !*/
#elif defined(__WIN32__) || defined(_MSC_VER)
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &CursorInfo);
switch(cmode.mode){
case _NOCURSOR: setCursorOff(); break;
case _SOLIDCURSOR: CursorInfo.dwSize=100;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
case _NORMALCURSOR: CursorInfo.dwSize=25;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
default: CursorInfo.dwSize = cmode.procent;
CursorInfo.bVisible=(cmode.mode!=_NOCURSOR); break;
}
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &CursorInfo);
#elif defined(__unix__) && !defined(__MSDOS__) && !defined(__WIN32__)
#error kommt spaeter dran
#else
#error setCursorColor(CURSORMODE): Code for your system or compiler is
not implemented jet. feel free to do :-)
#endif
}
/********* CODE endet hier **********/