Cursor Positioning from ARexx

In hexadecimal a general cursor positioning sequence takes the form... 9b [R] [3b C] 48. The first value, 9b hex, is known as the control sequence introducer (CSI) and you'll notice in my example sequences that I tend to define this value as the variable CSI and then use this term rather than the numerical value itself (helps make the resulting scripts easier to read). R represents the display row and C the display column whilst the 3b hex value is a 'separator' that allows the console device to distinguish between the two real row and column parameters. The brackets indicate items that can be treated as optional and this means that not only can either row or column positions be omitted but the 3b hex separator (which is in fact an ASCII semicolon character) only need be provided when either both row and column values are given or when just a column value is specified. In other words a row position on its own can be moved to by sending the simplified three character sequence... 9b R 48.

With any script that makes more than passing use of cursor positioning the best idea is to create an isolated SetCursor() function that takes a pair of row/column co-ordinates and sends the appropriate command sequence to the console window. Listing 1 shows a typical function and you'll notice how the actual row (r) and column (c) values passed to the function are easily embedded into the general form of the sequence by using the ARexx '||' string concatenation operator. The benefit here is that by isolating the cursor positioning code into a separate function the main body of your script will be 'cleaner', ie tidier, and therefore more understandable to both yourself and anyone else reading your code. Cursor position is then performed using statements such as...

 
        call SetCursor(10,0)...

Of course it's possible to go one better than this and create a function that takes both the cursor position and the text to be displayed as function arguments. Listing 2 shows a typical routine called CursorWrite() which would, for example, allow you to position and write error messages, incidental text and so on using statements in the form...

        call CursorWrite(10,0,SIGN_ON_MESSAGE)

Generalising The Code

It's best to try and generalise the routines as much as possible. With the listing 2 CursorWrite() routine for example improvements could be made. Rather than have the window handle explicitly embedded in the function code we could, for instance, pass the window handle to the routine as a parameter. Similarly ARexx's Procedure keyword could be used to isolate the workings of the routine from any script that the routine was finally used in.

Listing 3 shows the results of such changes and the benefit is that this function can now be incorporated and used in your own code without you needing to worry about how it works. Simply make a call to the CursorWrite() routine passing your window handle, the row/column screen co-ordinates, and text to be printed as function call parameters and your text will be duly printed at the specified position. The program shown in listing 4 should help get you started. It opens a window and then just prints a couple of text messages!

.

SetCursor: parse arg r,c call Writech(raw_window,CSI||r||'3b'x||c||'48'x) return Listing 1: A simple cursor positioning function
CursorWrite: parse arg r,c,text$ call Writech(raw_window,CSI||r||'3b'x||c||'48'x) call Writech(raw_window,text$) return Listing 2: Text writing with cursor positioning
CursorWrite: Procedure parse arg window,r,c,text$ CSI = '09'x call Writech(window,CSI||r||'3b'x||c||'48'x) call Writech(window,text$) return Listing 3: A more general form of the CursorWrite() function.
/* ------------------------------------------------ */ /* example.rexx */ MESSAGE1 = 'Just some example text' MESSAGE2 = 'Hit ANY key to quit program!' /* ------------------------------------------------ */ call Open(raw_window,'RAW:40/40/480/200/example.rexx') call CursorWrite(raw_window,10,10,MESSAGE1) call CursorWrite(raw_window,14,10,MESSAGE2) keypress$=Readch(raw_window,1) /* wait for keypress */ call Close(raw_window) exit /* logical end of program */ /* ------------------------------------------------ */ CursorWrite: Procedure parse arg window,r,c,text$ CSI = '9b'x call Writech(window,CSI||r||'3B'x||c||'48'x) call Writech(window,text$) return /* ------------------------------------------------ */ Listing 4: Some runable example code!


Page last updated