Newsgroups: comp.sys.apple2
Subject: Re: PS to mousetext & hyperc
From: David.Empson@bbs.actrix.gen.nz
Date: Fri, 24 Jul 1992 13:43:58 GMT
Organization: Actrix Information Exchange

In article <9207231157.AA10723@aitgw.ge.com> TEFFTA@TSENGR.dnet.ge.com (Andrew Tefft) writes:
>
> [snip]
> 
> The next obvious question is "how can I tell if a character on the screen
> is mousetext?" 
> 
> One would need this if they were going to print a pointer-type mouse cursor,
> since they would need to restore the character they obliterated after moving
> the pointer, and mousetext would probably be used in such displays.
> 
> It seems that there must be some way to preserve the mousetext-ness of
> characters on the screen, since mousetext stays mousetext when the screen
> scrolls... so there must also be some way to query the mousetext-ness
> of a character on the screen, too, no?

How do you intend to read characters directly off the screen?  There is
no way to do this using the 80-column firmware.  As far as I know,
you'll have to access the screen yourself.  You'll therefore need a
routine that calculates the address of a screen character, including
handling switching between page 1 and 2 for 80-column mode.

The following code is (roughly) how you might implement a mouse cursor
in ORCA/C on the IIgs.  You should be able to adapt this to Hyper C
without much trouble (the screen addressing is identical).

E-Mail me if you have any questions. 

You may have difficulty understanding open_screen and close_screen
unless you understand how the text screen is addressed.

I'm assuming that HyperC will only access a single byte when a
character pointer is dereferenced.  If it always accesses two bytes,
and discards the high byte, then the soft-switch accesses won't work.

To use the routines, make an initial call to init_mouse(), then to
show_mouse(), hide_mouse() and move_mouse() as appropriate.
No routines in your own program should call open_screen() or
close_screen(), but other routines may call peek_screen() and
poke_screen().

IMPORTANT: make sure the mouse is hidden before you output any text to
the screen (or use an input routine), or it may cause the old
characters to reappear when the mouse moves.

Another point: all of these routines deal with X coordinates in the
range 0 to 79 and Y coordinates in the range 0 to 23.  Using X or Y
values outside these ranges could trash memory at random.  Don't try it!
If HyperC normally uses 1 to 80 and 1 to 24, you'll need to make some
changes to these routines.

/********************  Mouse cursor handling routines  ****************/

static int mouse_visible;	/* TRUE if mouse cursor is on screen */
static int mouse_x, mouse_y;	/* mouse cursor coordinates */
static int oldchar;		/* the character "under" the cursor */

/* These four macros define the soft-switches used to control the
   80-column display. */
#define	PAGE1		*((char *)0xC054)
#define	PAGE2		*((char *)0xC055)
#define	ON_80STORE	*((char *)0xC001)
#define	OFF_80STORE	*((char *)0xC000)

#define	SCREEN		0x0400

static char *open_screen(int x, int y) {
	int base, dummy;
	/* Calculate base address of the line */
	base = SCREEN + (y >> 3) * 0x28 + (y & 7) * 0x80;
	/* Enable 80-column store and select the appropriate page */
	ON_80STORE = 0;		/* Must WRITE */
	if (x & 1)	/* Least significant bit set, i.e. ODD number */
		dummy = PAGE1;	/* odd columns: main memory (page 1) */
	else
		dummy = PAGE2;	/* even columns: aux memory (page 2) */
	/* Return the address of the character */
	return (char *)(base + (y >> 1));
}

static void close_screen(void) {
	int dummy;
	dummy = PAGE1;		/* Reselect page 1 (just in case) */
	OFF_80STORE = 0;	/* Turn off 80-column store */
}

int peek_screen(int x, int y) {
	int ch;
	ch = *open_screen(x, y);
	close_screen();
	return ch;
}

void poke_screen(int x, int y, int ch) {
	*open_screen(x, y) = ch;
	close_screen();
}

void hide_mouse(void) {
	if (mouse_visible) {
		poke_screen(mouse_x, mouse_y, oldchar);
		mouse_visible = FALSE;
	}
}

void show_mouse(void) {
	if (!mouse_visible) {
		oldchar = peek_screen(mouse_x, mouse_y);
		poke_screen(mouse_x, mouse_y, 0x42);	/* Mouse arrow */
		mouse_visible = TRUE;
	}
}

void move_mouse(int x, int y) {
	int old_visible;
	old_visible = mouse_visible;
	if (old_visible)
		hide_mouse();
	mouse_x = x;
	mouse_y = y;
	if (old_visible)
		show_mouse();
}

void init_mouse(void) {
	/* I'm assuming you've already initialized the mouse hardware,
	   clamping, etc. */
	mouse_visible = FALSE;
	mouse_x = mouse_y = 0;
}
-- 
David Empson

Internet: David.Empson@bbs.actrix.gen.nz    EMPSON_D@kosmos.wcc.govt.nz
Snail mail: P.O. Box 27-103, Wellington, New Zealand