Character Devices

 

An important feature of GS/OS is that you can use its commands to communicate with

character devices, not just block-structured disk devices. For example, to get keyboard

input, you open the keyboard, read data from it, then close it, just as if it were a file on

a disk drive. Under ProDOS 8, you must use completely different techniques to access

character devices, such as accessing memory-mapped hardware addresses or calling

firmware subroutines.

 

The character FST is responsible for translating standard GS/OS commands into

commands that the driver for a character device understands. It resides in a file called

CHAR.FST in the SYSTEM/FSTS/ subdirectory of the boot disk.

 

In this chapter, we see how to use GS/OS commands to communicate with two

particularly important character devices: the keyboard and the video display screen.

The device driver that controls these devices is called the Console Driver; we also

investigate the commands this driver understands.

 

Note: The Apple IIC has a tool set, called the Text Tool Set, that you can also use

to access character devices. But you should use the GS/OS commands since they

are more powerful and easier to use.

 

GS/OS COMMANDS FOR CHARACTER DEVICES

 

The character FST works with a small subset of GS/OS commands: Open, NewLine,

Read, Write, Close, and Flush. (You shouldn't use NewLine, however, because the

Console Driver supports a more powerful way of terminating input prematurely; see

the discussion of terminator characters below.) You can also use the GS/OS device

commands, DInfo, DControl, DRead, DStatus, and DWrite, to communicate directly

with any character-based device driver, including the Console Driver.

 

329

 

The name of the Console Driver is usually CON SOLE, but the user may be -

change it when a GS/OS driver configuration program becomes available. To deter--

mine the actual name, call the DInfo command with successively higher device

numbers (starting with 1) until DInfo returns a device - ID - num of $000A. The

name that DInfo returns for the device with this device - ID - num is the actual name

of the Console Driver.

DControl and DStatus are important for setting and returning various parameters

and operating mode flags the Console Driver uses. We summarize the DControl and

DStatus commands near the end of this chapter.

 

You won't need to use DRead and DWrite to communicate with the Console

Driver (you can use Read and Write instead), so they are not described here.

 

KEYBOARD INPUT

 

The Console Driver deals with character input from the Apple IIC keyboard. It reads

data directly from the keyboard hardware or, if the IIC Event Manager is active, from

the operating system event queue. The Console Driver returns standard ASCII

character codes (bit 7 of each code is zero).

 

The Console Driver supports two main input modes: raw mode and user input mode.

In raw mode, the driver continuously polls for keyboard data until it has read in the

number of characters requested in the Read command parameter table or until the

user enters a terminator character. (More on terminator characters below.) It then

returns these characters, including any terminator character, in the Read command's

data buffer. During a raw mode input operation, no cursor appears on the screen, and

characters are not echoed on the screen. Raw mode is useful for programs that wish to

implement their own user. input and editing routines.

 

In user input mode, the driver uses an intelligent User Input Routine (UIR) to

return keyboard input. The UIR displays an input field and a cursor, echoes input, and

permits editing according to Apple's human-interface guidelines. An input operation

ends when the user enters a terminator character.

 

To begin a keyboard input operation, you must first open the "file" called .CON-

SOLE using the GS/OS Open command. After doing this, set up various input

parameters and the appropriate input mode, as follows:

 

1. Select wait or no-wait mode. When wait mode is active, GS/OS keeps processing

a Read command until the user has typed in the specified number of characters

from the keyboard (in raw mode) or until the user enters a terminator character

(in raw or UIR mode). When no-wait.raw mode is active, GS/OS returns control

to the application as soon as it determines there is no keyboard input available.

(The UIR always operates in wait mode, so control never returns until the user

enters a terminator character.) This gives the application a chance to perform

other tasks during a keyboard input operation, but the application must keep

making Read calls until the user enters a terminator character. The default mode

is wait mode; to switch to no-wait mode, use the GS/OS DControl command.

 

330 GS/OS Character Devices

 

2. Set up the input port. The input port is a 17-byte record that keeps track of the status

of a UIR input operation. When you open the Console Driver, GS/OS sets up a

default input port suitable for most input operations. If you want to change some of

the entries in the port, for example, to set the initial cursor position and mode, now is

the time to do it. The procedure to follow is to read in a copy of the current input port

(with DStatus), change the desired fields, and then set the new input port (with

DControl). A description of the fields in the input port appears below.

 

3. Set up the terminator characters. A terminator character is one that, when entered,

causes a Read operation to end. The Console Driver lets you specify' the termini-

tor character and the combination of modifier keys that must be held down when

the user enters it. When using the UIR, the application must set up a termini-

tor character, typically the Return key, or the user won't be able to end an

input operation. You can set up a list of terminator characters with the DControl

command.

 

4. Set up the default string. The UIR displays a default string in the input field when

you call the Read command for the first time after an Open. Use the DControl

command to set up the default string.

 

Once these preliminary steps are out of the way, use the Read command (with the

reference number set to the one returned by Open) to return the number of characters

specified in the request - count field of its parameter table.

 

On return from the Read command, use DStatus to get a copy of the input port.

The exit - type field of this port (see below) indicates the reason for the return of

control. In normal raw mode, a $00 value indicates that the specified number of

characters has been returned, so input processing can end. In no-wait raw mode, a $00

indicates a no-wait return, and the application must inspect the transfer - count field

to determine if any more characters have to be processed; if so, it must process them,

then call the Read command again (after reducing request - count) until the desired

number of characters have been returned.

 

Any other value for exit - type, in raw mode or UIR mode, indicates that a

terminator character was pressed. If the value corresponds to an application-defined

interrupt key (see below), you should process it without disturbing the current UIR

environment, and then call the Read command again. (When you call Read again in

UIR mode, you don't have to make any adjustments to the parameter table because

the Console Driver keeps track of the state of the input operation when it was last

exited.) If you wish to abort the input operation instead, use DControl's Abort Input

subcommand. This subcommand zeroes the entry - type field of the input port (see

below) so that the next Read command will not be interpreted as a continuation of the

previous one.

 

If a non-zero exit-type value does not correspond to an interrupt key, the input

operation is complete. The Console Driver handles the next Read command as an

initial entry to UIR mode.

 

Keyboard Input 331

 

When you're through reading keyboard input, call the Close command. This is not

necessary, however, if you still need the Console Driver to process video output or

more input.

 

The Input Port

 

As we mentioned, the Console Driver maintains an input port to keep track of the input

environment. The fields in the 17-byte input port are arranged in the following order:

 

fillchar

defcursor

cursor-mode

beepflag

entry-type

exittype

lastchar

lastmod

 

last~term~ch

lasttermmod

eursorpos

input - length

input-field

origin~h

originx1

originx2

originv

 

The values in these fields completely describe the input environment. Here is what

each field means:

 

fill~char This is the character code that UIR sends to the Console Driver when it

wants to display an empty position in the input field. The default value is $20 (a space).

 

deft cursor. Three bits in this byte indicate the default cursor mode at the begin-

ning of a UIR session:

 

332 GS/OS Character Devices

 

bit 7 0 = put cursor at end of default string

 

1 = put cursor at beginning of default string

bit 6 0 = don't allow the entry of control characters

 

1 = allow the entry of control characters

bit 0 0 = use an insert cursor

 

1 = use an overstrike cursor

 

The default value is $00.

 

cursor mode. One bit in this byte indicates the current cursor status in UIR mode:

 

bit 0 0 = an insert cursor is active

 

1 = an overstrike cursor is active

 

beep -~g If this byte is nonzero (the default value), the UIR beeps if the user

attempts an illegal operation. If this byte is zero, there is no beep.

 

entry - type. When the application calls the Read command, the Console Driver

inspects this byte to determine the current input status. The possible values are

 

$00 this is the initial entry

$01 this is an interrupt key reentry

$02 this is a no-wait mode reentry (raw mode only)

 

The Console Driver adjusts this byte whenever it relinquishes control to the applica-

tion, setting it to $00 if a noninterrnpt terminator character was entered. This enables

the Console Driver to properly restart a Read operation that is already in progress.

 

exit - type. This byte indicates the reason for the exit from the Read request:

$00 a raw-mode exit, because the maximum number of

characters have been read, or a no-wait raw mode

exit

 

A nonzero value indicates a terminator key was pressed. The value is the entry number of

the terminator character in the terminator table. If the terminator is not an interrupt key,

the Console Driver zeroes the entry - type field so that the next Read operation will begin

from scratch; otherwise, it puts a $01 there so that the Console Driver will continue the

same input operation the next time the application calls Read.

 

iastcbar. The ASCII code of the most recently typed key. The high-order bit is

always 0.

 

ia#t - mad. The modifier byte of the most recently typed key. The meanings of the

bits in the modifier byte are the same as those for the bits in the high-order byte of a

terminator modifier (see Figure 9-1).

 

Keyboard Input 333

 

Figure 9-1 The format of the terminator mask and the terminator modifier wor;l

 

~ CSoh~ft key down

 

ntrol key down

 

Caps Lock key down

[reserved; must be zero]

Keypad key down

 

Interrupt key designator

Option key down

Open-Apple down

 

lastte~ch. The ASCII code of the most recently typed terminator key. i

high-order bit is always 0.

 

last - tea - mod. The modifier byte of the most recently typed terminator key.

meanings of the bits in the modifier byte are the same as those for the bits in the

high-order byte of a terminator modifier (see Figure 9-1).

 

cursor pos. The position of the cursor relative to the start of the UIR input field. &

$00 value means the cursor is over the first character in the field. The maximum value

is the length of the field, meaning the cursor can move to the first character past the

end of the field.

 

input - length. The current length of the string being edited. This is the same as the

number returned in the transfer - count field of the Read command.

 

input field. This value is for the Console Driver's private use.

originh. The horizontal position of the cursor in UIR mode.

origin x1. This value is for the Console Driver's private use.

origin x2. This value is for the Console Driver's private use.

origin 0. The vertical position of the cursor in UIR mode.

UIR Editing

 

The UIR supports several standard commands for editing the characters in the input field:

 

334 GS/OS Character Devicesleft-arrow

* -left-arrow

 

right-arrow

*-right-arrow

 

or

* - < or *

* -E or Control-E

 

Delete or Control-D

or Control-Delete or

*-Delete or *-D

 

* -F or Control-F

* -X or Control-X

or Clear

 

* -Y or Control-Y

 

* -Z or Control-Z

* -Control- <char>

 

Terminator Characters

 

Move the cursor one position to the left.

Move the cursor to the start of the previous word (if it's

currently over a space) or to the start of the current word (if

it's not).

 

Move the cursor one position to the right.

Move the cursor to the end of the next word (if it's currently

over a space) or to the end of the current word (if it's not).

Move the cursor to the end of the input field.

Move the cursor to the beginning of the input field.

Toggle the cursor between insert mode (blinking under-

score) and overstrike mode (blinking box).

 

Erase the character to the left of the cursor and move the

characters beneath and to the right of the cursor one position

to the left. The cursor also moves one position to the left.

Erase the character underneath the cursor and move the

characters to the right of the cursor one position to the left.

The cursor stays put.

 

Erase the entire input field.

 

Erase the characters from the current cursor position to the

end of the input field.

Restore the default input string.

 

Enter a control character. You can do this only if control

character entry is enabled by setting bit 6 of the def cursor

field in the input port record.

 

A terminator character is one that when entered, causes a raw mode Read operation to

end even if the user has not yet entered the number of characters specified in the

request - count field of the Read command. Entering a terminator character also

forces a UIR operation to end right away. (In fact, the user must end a UIR operation

by entering a terminator character, so the application must define at least one such

character.) The transfer - count field in the Read parameter table contains the actual

number of characters that Read has returned in the data - buffer field.

 

When the user enters a terminator character, the exit - type field in the input port

 

is set to the position number of the terminator character in the terminator list. The

position number of the first item in the list is $01.

 

The Console Driver lets you specify the terminator character itself, as well as the

modifier keys (Open Apple, Shift, Caps Lock, and so on) that the user must hold down

while entering the character. It uses a data structure called a terminator list to hold

 

Keyboard Input 335

 

the definitions of up to 254 terminator characters and their modifiers. The list

with a terminator mask and a terminator count and is followed by the ter

characters and their modifiers.

 

Here is the meaning of each entry in a terminator list:

 

Ter'ninator Mask (word). When the user enters a keystroke, the Console

logically ANDs the keystroke data with the terminator mask before checking the list

terminator modifiers for a match. By setting bits of the mask to zero, you can

matches even if the associated modifier keys are being pressed. (Figure 9-1 shows

meaning of the bits in a terminator mask.) If the state of the Caps Lock key

unimportant to your application, for example, you would speci~ a mask of $FBFF (bit

10 = 0).

 

'Ie~nator Count (word). This word contains the number of entries in the list of

terminator modifiers. If there are no terminators, this word should be set to zero.

 

Ter'ninator Modifiers (words). A terminator modifier is a 2-byte value describing

the ASCII code of the terminator (low byte) and the modifiers themselves (high byte).

Figure 9-1 shows the meaning of each of the bits in a terminator modifier.

 

If bit 13, the interrupt bit, of a terminator modifier is set to 1, the terminator

character is considered an interrupt key. When the user enters an interrupt key, the

Read command ends, but the entry - type byte in the input port is set to $01. The next

time the same Read command is called, input processing continues from where the

interruption took place.

 

One reason Jo define an interrupt key is to implement a help command. To include

 

a standard * -? help key, for example, set bits 15 and 13 in the modifiers byte and put

the ASCII code for a question mark in the low-order byte. You should also assign * -I

as an interrupt key so that the user can get help without having to press a Shift key

(and I share the same keycap).

 

VIDEO OUTPUT

 

The Console Driver also manages all activities related to the display of characters on

the Apple IIC text screen. There are actually two text screens: an 80-column, 24-line

screen and a 40-column, 24-line screen; you can switch between them by sending

control codes to the Console Driver with the GS/OS Write command.

 

The Console Driver stores video data directly to the video RAM buffers located at

$040~$07I'I' in banks $E0 and $E 1 of memory. As a result, applications that want to

access the screen bytes directly should not look at the "traditional" video RAM buffers

in banks $00 and $01 even if these areas are set up to shadow to banks $E0 and $E1.

See Exploring the Apple tics for a discussion of text screen shadowing.

 

The Console Driver lets you confine video output operations to any rectangular

window within the fall hardware screen; this window is called a text port. When you first

 

336 GS/OS Character Devices