Read or calculate cursor position on Glulx text grid window?

I’m trying to get something done in Glulx (with the Flexible Windows extension by Jon Ingold), and this is the first time I’m really tangling with things like streams and windows and rocks.

My main goal is to try to figure out where the cursor is on a text grid window after printing something to it. Although it is possible to move the cursor to a set of specified screen coordinates, it does not seem possible to ask for the coordinates where the cursor currently is. Am I missing something in the Glk spec?

If it’s not possible to obtain the position directly, the next option seems to be to try to calculate it. Echo streams to memory can capture the text going to the text grid window, and it’s possible to read the stream position and inspect the characters streamed so far. I have some code that is (more or less) working on the 6M62 IDE interpreter, but it’s not working on Git 1.3.5 (Gargoyle 2019) or Git 1.3.7 (Gargoyle 2023).

The specific issue with Git is that attempting to read the contents of the memory array to which the echo stream is pointed is always returning zero instead of the expected captured character. Manual inspection of the target array after printing shows only zero-value bytes for the first several locations. Before reading, the code does check that the echo stream exists and is set as the echo stream for the window in question. The captured characters are returned correctly by the IDE interpreter, so I’m not sure what the cause is.

Does Git support echo streams for text grid windows?

Here’s some test code illustrating the difference:

test code
"Echo?"

Include Flexible Windows by Jon Ingold.

Include (-

Constant gg_TMP_ARRAY_LEN = 200;
Array gg_strtmparray -> gg_TMP_ARRAY_LEN;

Global gg_countingechostream;
Constant gg_COUNTING_ECHO_ROCK = 999;

Array gg_streamcharcount --> 2; ! -->0 = readcount, -->1 = writecount
Global gg_echostreammark;

[ RetrieveEchoRock    chk_strm rockval;
	chk_strm = glk_stream_iterate(0, 0);
	while (chk_strm) {
		rockval = glk_stream_get_rock(chk_strm);
		if (rockval == gg_COUNTING_ECHO_ROCK)
			return chk_strm; 
		chk_strm = glk_stream_iterate(chk_strm, 0);
	}
	rfalse;
];


[ EstablishEchoStream win ;
	gg_countingechostream = RetrieveEchoRock();

	if (gg_countingechostream) {
		glk_stream_close(gg_countingechostream, gg_streamcharcount);
	}

	gg_countingechostream = glk_stream_open_memory(gg_strtmparray, gg_TMP_ARRAY_LEN, filemode_Write, gg_COUNTING_ECHO_ROCK);
	
	glk_window_set_echo_stream(win, gg_countingechostream);
	gg_echostreammark = 0;
];

[ CheckEchoStream    strm_pos;
	strm_pos = glk_stream_get_position(gg_countingechostream); 
	print "^<", strm_pos,  " chars streamed, first 4 array values are: ", gg_strtmparray->0, " ", gg_strtmparray->1, " ", gg_strtmparray->2, " ", gg_strtmparray->3, ">^"; ! should reflect "TEST"
];

-)

To establish echo stream for (win - g-window):
	(- EstablishEchoStream( {win}.(+ ref number +) ); -).


To check echo stream:
	(- CheckEchoStream(); -).

When play begins:
	establish echo stream for main window;
	say "TEST";
	check echo stream.

Place is a room.
1 Like

It doesn’t seem to be possible, and that seems to be a deliberate acknowledgement of it not actually being a well-defined concept. Grid windows do maintain values for xpos and ypos, but Glk is event driven, and among those events is resizing the window. So, at any given moment external events could render the stored xpos and ypos values to be meaninglessly outside the size of the grid. Knowing this, the implementations canonicalize the values into something within the window before printing anything.

It’d be straightforward to add a function that would get the xpos and ypos values… but, as noted, one or both might be unhelpfully outside the window grid range. Or you could canonicalize and then get them… but then you’re not really getting the answer to the question “where is the cursor?”, you’re getting the answer to the question “if I were to stream a character to this window right now, where would the cursor be in the moment before the character was output?” And that answer could be wrong by the time you try to act on it.

1 Like

There is spec-defined behavior with respect to things already printed on a text grid screen, i.e. after resizing any newly-added areas are left blank and any formerly-present areas are discarded.

If the text grid window were to maintain a coordinate location, it could just set the coordinate for a changed dimension at the new maximum (if the old value would end up off-screen after resize) or just leave it as-is if the value is still legal after resizing. Maybe there are additional complications that can be anticipated with respect to Unicode characters – I don’t know much about what goes on under the covers for those.

Regardless, I’m OK with the fact that reading the cursor position is not supported and recognize that what I’m trying to do might not always be straightforward, but in the simple case of fixed width font in a text grid window it seems like it should be possible to derive the cursor position this way.

Note that I’ve updated the test code to show that the echo stream is registering the captured characters inasmuch as it is updating its stream position to reflect them, so it seems like Git is just not actually writing the echoed characters to the target array?

Are you closing the stream? The interpreter may not fill in the memory array until the stream closes. (At that point it also fills in the streamcount pair of words, which may also be helpful for you.)

Your sample code has a glk_stream_close() call but it’s in the Establish function so I’m not sure if it’s in the right place.

1 Like

Yeah, it’s deliberate that you can’t do this. It seemed (to me) that the game could keep track of what it wanted; relying on the implementation’s memory seemed like an unnecessary source of bugs.

(The idea of the cursor position is not as straightforward as you might think. Specifying what happens after a line-wrap or a window resize is a headache. If the game was able to query this, it would mean writing all of that behavior up in the spec, and I really didn’t want to.)

(EDIT: Zed already said this better…)

By far the most sensible behavior for the game is to redraw the whole status window every turn. The next most sensible behavior is to be fussy about which parts to redraw every turn, but still redraw the whole thing every time the window is resized. :)

For what it’s worth, it’s not just git that does the fill-in-on-close thing. If I recall correctly, my C implementations handle 8-bit memory streams in place (in VM memory) but 32-bit (Unicode) memory streams are not handled in place. (They may have to be stored endian-flipped, so it’s easier to keep a separate array of ints and store it back at close time.)

1 Like

That’s the root cause. If the stream is closed, then the expected values are there. And the spec does say that not putting them there until the stream is closed is valid:

Whether reading or writing, the contents of the buffer are undefined until the stream is closed. The library may store the data there as it is written, or deposit it all in a lump when the stream is closed.

I do remember reading that at one point, but I must have forgotten about it after seeing that the IDE intepreter was writing as it goes. Thank you!

What I’m discovering is that it isn’t actually very easy for the game to keep track of this on its own. Did you have any particular method(s) in mind as to how that could be accomplished?

FWIW, I was discussing this issue with someone else, and that person pointed out that it seems like any implementation must already be tracking a cursor position internally in order to know when to wrap a (non-final) line while printing to a text grid window. This supposition seems to be borne out by what is already in the spec:

A text grid window supports output. It maintains knowledge of an output cursor position…

When you print, the characters of the output are laid into the array in order, left to right and top to bottom. When the cursor reaches the end of a line, or if a newline (0x0A) is printed, the cursor goes to the beginning of the next line. The library makes no attempt to wrap lines at word breaks. If the cursor reaches the end of the last line, further printing has no effect on the window until the cursor is moved.

If you move the cursor right past the end of a line, it wraps; the next character which is printed will appear at the beginning of the next line.

If you move the cursor below the last line, or when the cursor reaches the end of the last line, it goes “off the screen” and further output has no effect. You must call glk_window_move_cursor() or glk_window_clear() to move the cursor back into the visible region.

What would be ideal for my purposes (which is limited to text grid windows) would be the ability to read that maintained knowledge about the cursor position, even if it is not 100% guaranteed to do what is expected in every situation. It seems fair for it to be the author’s responsibility to check the position immediately prior to use so that the observed coordinates aren’t stale.