Jump to content











Photo
- - - - -

Writing to the Grub4dos' keyboard buffer possible?

grub4dos

  • Please log in to reply
110 replies to this topic

#1 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 13 March 2021 - 09:16 PM

I'd like to know if it's possible to write a string directly to the Grub4dos' 'keyboard-buffer'? Or something like that. My goal is to 'recreate' the written string to the Grub4dos command-line with the up/down arrow's.

#2 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 14 March 2021 - 03:24 PM

I am not sure to understand.

 

Grub4dos already has that (sort of doskey) feature, at least version 0.4.6 2017-08-30 onwards.

 

Test performed:

typed:

echo "pippo"

[ENTER]

echo "mickey"

[ENTER]

 

then pressed up key once and on command line appeared:

echo "mickey"

ready for pressing ENTER

pressed again up key and on command line appeared:

echo "pippo"

ready for pressing ENTER

pressed down key and on command line appeared (again):

echo "mickey"

ready for pressing ENTER

 

These command strings must have been written somewhere in memory, probably :unsure: around:

https://www.rmprepus...s-and-functions

0x0007000 CMD line buffer

 

Very likely it is possible to peek/poke the memory with read/write or cat --hex or one of the variou functions. :dubbio:

 

:duff:

Wonko



#3 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 14 March 2021 - 09:14 PM

Thanks a lot, I will study the CMD-buffer!

I am aware of the Doskey-like functionality on the Grub4dos command-line.

At the moment I am working on a script to read/write/edit text-files inside Grub4dos. Although the script can perform most functions, I can not edit lines saved earlier. Only delete or replace. During writing I can re-use lines typed earlier with the up/down arrows, as long they are in the CMD-buffer. Only these lines are editable with my script.

If I could write a saved line to the CMD-buffer, I could (try) to 'get it back' to the command-line for editing (before replacement).

#4 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 18 March 2021 - 11:58 PM

I made some progress. But the Keyboard Buffer seems to have another address in memory.

With following script it's possible to view the changes in the Keyboard buffer, to empty the Keyboard Buffer and empty & write one variable ('listens' afterwards to the up-arrow).

--------------------------------
KEYBUFF.G4B
--------------------------------
!BAT
## KEYBUFF.G4B by deomsh
## Keyboard Buffer starts at 0x3EA4C0 and ends at 0x3EC4BF. Total length=0x2000 - just inside (md)0x0+0x1F63
## Each entry in Keyboard Buffer starts with length of keys+3, in hex. Before and after keys: 00 (in hex).
## Each new entry starts at 0x3EA4C0 (buffer shifts 'up')
echo
echo Test Keyboard buffer
echo
:loop1
cat --hex --skip=0x3EA4C0 --length=0x80 (md)0x0+0x1F63 && echo
set key=zyx
echo Insert keys and view Keyboard Buffer or Enter=Continue
set /p "key=>" && echo
if not "%key%"=="zyx" && goto :loop1
if "%key%"=="zyx" && echo && set key= && set clean=zyx
set /p "clean= C=Clean Keyboard Buffer or I=Insert or Enter= continue >" && echo
if %clean%==C && goto :cleanbuf
if %clean%==I && goto :loop1
echo
set key=zyx
set "var=Variable with spaces"
set /A varlen=%@retval% > nul
set /A varlen=%varlen%+3 > nul
echo W=Write variable to Keyboard Buffer or Enter=Quit
set /p "key=>" && echo
if %key%==W && goto :writebuf
echo
echo
goto :eof

:cleanbuf
call Fn.24 0x3EA4C0 0x00 0x2000
cat --hex --skip=0x3EA4C0 --length=0x80 (md)0x0+0x1F63 && echo
set key=zyx
set /p "key=Insert and view Keyboard Buffer or Enter to Quit >" && echo
if "%key%"=="zyx" && echo
if not "%key%"=="zyx" && goto :loop1
echo
echo
goto :eof

:writebuf
call Fn.24 0x3EA4C0 0x00 0x2000
cat --hex --skip=0x3EA4C0 --length=0x80 (md)0x0+0x1F63 && echo
write --offset=0x3EA4C0 (md)0x0+0x1F63 \x%varlen:~2%\x00%var%\x00 > nul
goto :loop1

:eof

--------------------------------

Edited by deomsh, 19 March 2021 - 12:00 AM.


#5 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 19 March 2021 - 12:55 PM

Good that you have found it :).

 

About:

 

Before and after keys: 00 (in hex).

 

A C programmer would say "strings in C are 00 terminated" (it's the same thing, but it sounds a lot more professional ;)).

And these:

 

Buffer and empty & write one variable ('listens' afterwards to the up-arrow).

...

 

Each new entry starts at 0x3EA4C0 (buffer shifts 'up')

 

would be described as "a simple implementation of a LIFO (Last In First Out) stack" (again the same thing, but a lot cooler :rolleyes: ).

 

:lol:

 

:duff:

Wonko



#6 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 19 March 2021 - 04:20 PM

Thanks a lot, the G4B-programmers will be happy.

With help of 'dd' I managed to write a variable before the existing buffer 'entrances'.

It would be nice if I could run commands with some key.
As far as I can see, the Grubutils program 'hotkey' works inside the Grub4Dos menu-environment only!?

--------------------------------
KEYBUFF.G4B
--------------------------------
!BAT
## KEYBUFF.G4B by deomsh (descriptions 'cooler' thanks to Wonko the Sane)
## Goal is testing if a variable writing to the Keyboard Buffer can be 'called' afterwards on the command-line with the 'arrow-up'-key
## Keyboard Buffer starts at 0x3EA4C0 and ends at 0x3EC4BF. Total length=0x2000 - just inside (md)0x0+0x1F63
## Each entry in Keyboard Buffer starts with length of keys+3, in hex. strings in C are 00 terminated
## Each new entry starts at 0x3EA4C0 a simple implementation of a LIFO (Last In First Out) stack
## Maximum variable length = 0xFF - 0x03 = 0xFX = 252; else a rhombus-symbol is diplayed if variable is 'called' to the command-line
## Seems not fully safe to copy variables with length above 252 chars?
## If Keyboard Buffer is full, there is no end-mark visible inside the buffer
## After reboot to MS-DOS => back to Grub4Dos command-line, old Keyboard Buffer entries still visiblble, but always INACTIVE
## So there is somewere a "adminstration" of the 'active' Keyboard Buffer!
echo
echo Test Keyboard buffer
echo

:loop1
cat --hex --skip=0x3EA4C0 --length=0x100 (md)0x0+0x1F63 && echo
set key=zyx
echo "Insert keys and view Keyboard Buffer" or give "Enter" to Quit
set /p "key=>" && echo
if not "%key%"=="zyx" && goto :loop1
if "%key%"=="zyx" && echo && set key= && set clean=zyx
set /p "clean= C=Clean Keyboard Buffer or I=Insert or Enter=Continue >" && echo
if %clean%==C && goto :cleanbuf
if %clean%==I && goto :loop1
echo
set key=zyx
set "var=Variable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla bVariable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla b Variable with spaces blabla blublu blauwwen. Gauw even weggaan voor we weer naar huis terug moeten"
#set "var=Variable with spaces"
set /A varlen=%@retval% > nul
set /A varlen=%varlen%+3 > nul
echo W=Write variable to Keyboard Buffer or Enter=Quit
set /p "key=>" && echo
if %key%==W && goto :writebuf
echo
echo Keyboard Buffer will be soon showed entirely!
set key=zyx
set /p "key= O=pager Off or P=Pager on >" && echo
if %key%==P && pager on
if not %key%==P && pager off
cat --hex --skip=0x3EA4C0 --length=0x2000 (md)0x0+0x1F63 && echo
pager on
goto :eof

:cleanbuf
call Fn.24 0x3EA4C0 0x00 0x2000
cat --hex --skip=0x3EA4C0 --length=0x100 (md)0x0+0x1F63 && echo
set key=zyx
echo "Insert keys and view Keyboard Buffer" or give "Enter" to Quit
set /p "key=>" && echo
if "%key%"=="zyx" && echo
goto :loop1

:writebuf
if %varlen%>=0x100 && set /A varlen=0xFF > nul
set /A bufflen=0x2000-%varlen% > nul
echo -n > (md)0x3000+16
write (md)0x3000+16 \x%varlen:~2%\x00%var:~0,252%\x00 > nul
## > 252 chars 'rhombus'-sign showed by Grub4Dos. Status NOT clear
#write (md)0x3000+16 \x%varlen:~2%\x00%var%\x00 > nul
dd if=(md)0x0+0x1F63 of=(md)0x3000+16 bs=1 count=%bufflen% skip=0x3EA4C0 seek=%varlen% > nul
call Fn.24 0x3EA4C0 0x00 0x2000
dd if=(md)0x3000+16 of=(md)0x0+0x1F63 bs=1 count=0x2000 skip=0 seek=0x3EA4C0 > nul
cat --hex --skip=0x3EA4C0 --length=0x100 (md)0x0+0x1F63 && echo
goto :loop1

:eof

--------------------------------

#7 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 21 March 2021 - 02:20 PM

Yep :) , hotkey is menu only :(.

 

There is still the poor man's way (that I use sometimes in DOS/command line prompt).

 

On Italian keyboard there is the (very rarely used but easily accessible) § character (as Shift+ù), I presume that similar rarely used but directly accessible characters exist also in Dutch and other languages.

 

What I have is (in PATH) a batch called  "§.cmd" that basically consists in:

 

CALL :%1

GOTO :EOF

:a

::do something

GOTO :EOF

:b

::do something else

GOTO :EOF

...

 

So I can input on command line:

§[SPACE]a[ENTER] to do something or 

§[SPACE]b[ENTER] to do something else, etc.

 

In grub4dos one can do the same or use the pause command.

The batch could be still called §.g4d, the contents could be like:

pause

goto :%@retval%

 

:97
#this is a

 

...

etc.

 

This way you save the final [ENTER], i.e it should work with:

§[ENTER]a

 

Three key presses, still much better than nothing ;) ...

 

:duff:

Wonko

 

 

 

 

 

 

 



#8 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 22 March 2021 - 02:07 AM

Interesting, never thought about to insert a 'label' with a variable.

It's sad I can do nothing with function keys during running a G4B-script.

So I have to stick to my 'set /p'-menu's.

#9 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 22 March 2021 - 04:24 PM

Or you can use a configfile directive.

 

I.e. you can have your (hypothetical) §.g4d consist of:

configfile /§.mnu (or *whatever)

and then have in the menu the commands actually visible and invokable via hotkey.

 

As a side note I don't see why you cannot use Fkeys from within a running G4B script, you can spawn periodically a child batch or a subroutine getting the scancode of a pressed key, this way you will however probably introduce a delay or hog the CPU, but the issue as I see it  is more that scancodes of Function keys are (for some reasons) not "universal across *all* keyboards", particularly laptop ones.

 

:duff:

Wonko



#10 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 23 March 2021 - 06:40 PM

Or you can use a configfile directive.
 
I.e. you can have your (hypothetical) §.g4d consist of:
configfile /§.mnu (or *whatever)
and then have in the menu the commands actually visible and invokable via hotkey.
 
As a side note I don't see why you cannot use Fkeys from within a running G4B script, you can spawn periodically a child batch or a subroutine getting the scancode of a pressed key, this way you will however probably introduce a delay or hog the CPU, but the issue as I see it  is more that scancodes of Function keys are (for some reasons) not "universal across *all* keyboards", particularly laptop ones.
 
:duff:
Wonko


Is configfile not only ment for the Grub4Dos menu.lst?

Or you can use a configfile directive.
 
I.e. you can have your (hypothetical) §.g4d consist of:
configfile /§.mnu (or *whatever)
and then have in the menu the commands actually visible and invokable via hotkey.
 
As a side note I don't see why you cannot use Fkeys from within a running G4B script, you can spawn periodically a child batch or a subroutine getting the scancode of a pressed key, this way you will however probably introduce a delay or hog the CPU, but the issue as I see it  is more that scancodes of Function keys are (for some reasons) not "universal across *all* keyboards", particularly laptop ones.
 
:duff:
Wonko


Interesting. Does this mean the 'scancodes' must be watched periodically to 'see' if they were 'active' after pressing let's say F3?

#11 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 25 March 2021 - 01:29 PM

You need to see it a bit more "widely".

Grub4dos can read the contents of a configuration file that has a given syntax and by convention has a .lst extension (but this latter is not "necessary") this is essentially a i.e. menu system (the default name of menu.lst should mean something ;)).

The syntax leads to a number of entries that are normally selectable by using the direction keys but also - via the hotkey utility - selectable/choosable pressing the appropriate hot keys.

Each entry is defined by the leading "title" keyword followed by an actual title string.

The following lines (up to the next "title" keyword or to the EOF) are one or more commands that will be executed once the entry is chosen.

It is written nowhere in stone (and not even on sand) that each entry is a boot entry, the fact that .lst files are essentially used for this kind of use does not mean that it is the only possible one, and if you check the default menu.lst that comes with grub4dos, you will notice the entries:

title commandline

commandline

and

title halt

halt

that definitely are non-booting ones

 

So you can have (say) a dos.txt file containing something *like*:

insmod /hotkey

timeout 0

default 0

title ^F1 DIR

ls

title ^F2 type self

cat /dos.txt

title ^F3 run test.g4b

/test.g4b

title ^F4 commandline

commandline

title ^F5 halt

halt

 

Otherwise yes, AFAIK you need to periodically "wait" for the scan code, i.e. with pause (that may introduce delays) or by looping to a (I believe it exists a Fn. function, Fn.20  that can read pressed keys) with the risk of hogging the CPU.

And again F1-F12 keys are "risky" as particularly on notebooks they are sometimes non-standard or non-working.

 

See also here:

http://reboot.pro/to...ub4dos-command/

 

You can invoke a configuration file, that can have no entries but a number of hotkey commands.

 

Maybe if you post a real life example of what you want to actually achieve, a better/more suitable idea may come out :dubbio:

 

:duff:

Wonko 



#12 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 25 March 2021 - 10:37 PM

Thanks a lot!

 

I think I begin to grasp the idea. So far my understanding of your 'configfile'-method seems to imply each separate key is associated to one unique command. The 'changed' .lst-file delivers these associations? :blink:

 

My idea was to use function-keys in my editor, say like F3 in case finding a next instance in a text (keys like MS-DOS' EDIT.COM). So the running script should become somehow 'aware' of pressing a (function-)key.

 

If everything has gone well, I inserted a working link after this sentence to a print-screen from my project (I see a message I am not allowed to upload media directly in my reply-box, if I tried posteimg.cc). I am not sure which link is good, so I tried a direct link:

 

https://i.postimg.cc...CHO-0x-F0-S.png

 

In the print-screen the first 'string' found is highlighted.

 

If a next instance was earlier discovered by another sub-routine, my 'read-menu' shows the 'N=Next' at the fully left, I associated this (visual) position to 'Enter' too (for convenience and speed of operation). Everything with 'set /p', works good as such. :)

 

Below you see the sub-routine of my 'read-menu'

:readline
if %linenum%==%lastline% && call :footer ! echo
set read=zyx
if exist numnext && set /p /u "read=N=Next D=Down U=Up O=One B=Back H=Home L=Last G=Goto F=Find E=Edit M=Menu> " && echo
if not %linenum%==%lastline% && if not exist numnext && set /p /u "read=D=Down U=Up O=One B=Back H=Home L=Last G=Goto F=Find E=Edit W=Write M=Menu> " && echo
if %linenum%==%lastline% && if not exist numnext && set /p /u "read=M=Menu D=Down U=Up O=One B=Back H=Home L=Last G=Goto F=Find E=Edit W=Write> " && echo
set gotoline= && set gotonext= && set readmenu=
if %read%==zyx && echo
if %read%==zyx && if exist numnext && set read=N
if %read%==zyx && if not %linenum%==%lastline% && if not exist numnext && set read=D
if %read%==zyx && if %linenum%==%lastline% && if not exist numnext && set read=M
set read=%read:~0,1%
if %read%==D && if not %linenum%==%lastline% && goto :eof
if %read%==U && set /a gotoline=%showline% && set /a showline=%showline%-%show% &; if %gotoline%<=%show% && set /a gotoline=%show%
if %read%==U && set gotonext=L && goto :eof
if %read%==O && set /a gotoline=%linenum%+1 > nul && set gotonext=L && goto :eof
if %read%==B && set /a gotoline=%linenum%-1 > nul && set gotonext=L && goto :eof
if %read%==H && set /a gotoline=1 > nul && set gotonext=L && goto :eof
if %read%==L && set /a gotoline=%lastline% > nul && set gotonext=L && goto :eof
if %read%==G && call :gotomenu &; set gotonext=L && goto :eof
if %read%==F && call :find &; if exist numline && set /a gotoline=%numline% > nul
if %read%==F && if not exist numline && set /a gotoline=%linenum% > nul
if %read%==F && set gotonext=L && set numline= && goto :eof
if %read%==N && if exist numnext && call :find &; if exist numline && set /a gotoline=%numline% > nul
if %read%==N && if not exist numline && set /a gotoline=%linenum% > nul
if %read%==N && set gotonext=L && set numline= && goto :eof
if %read%==W && goto :eof
if %read%==E && set /a gotoline=%linenum% > nul && set gotonext=G && goto :eof
if %read%==M && set /a gotoline=%linenum% > nul && set gotonext=L && goto :eof
if not %read%==D && if not %read%==U && if not %read%==L && if not %read%==F && if not %read%==N && if not %read%==W && if not %read%==E && if not %read%==M && goto :readline
goto :eof

Next line is searched if 'N' is given, or if 'Enter' is pressed too in case 'numnext exists' (fourth line in the code=box).
 



#13 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 26 March 2021 - 10:11 AM

Yep, but if you have a bottom line menu, not entirely unlike the "MORE" command in DOS/CMD prompt,  you can use the pause command just fine instead of the set /p.

 

The difference is that the set /p is essentially a "getstring" function, while the pause is essentially a "getkey" function.

 

something loosely *like*:

pause --wait=20 N=Next D=Down U=Up O=One B=Back H=Home L=Last G=Goto F=Find E=Edit M=Menu

set getkey=%@retval%

 

#this is timeout

if 1=%getkey%

#this is [ENTER]

if 13==%getkey% ...

#this is N

if 78==%getkey% ...

#this is n

if 110==%getkey% ...

 

Please note how you can have this way some "filtering" possibilities, i.e. A-Z are 65-90, a-z are 97-122, etc.

 

:duff:

Wonko


  • deomsh likes this

#14 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 26 March 2021 - 11:33 PM

This is really good, I wasn't aware of this possibility of the 'pause'-command.

 

'set /p' has some limitations in case of menu's I don't like: if the message is too long, the cursor goes back to the beginning of the command-line. Further 'set /p' always want a new line, can't be combined with 'echo -n' (further I am very happy with this command).

 

First I was a bit disappointed I found there was 'only' a return-value in case of 'normal' keys (but including Enter and Backspace!). But with 'pause --wait=20 --test-key' I got 16 bits-codes for ALL keys on my keyboard. So I had a party today!

 

I did a first test with following 'translation'-routine, implemented instead of my earlier lines (some are only in use for debugging).

 

And it's working!!! :heh:

#
setlocal
set nextcol=%greycol% && if exist numnext && set nextcol=%textcol%
echo D=Down U=Up O=One B=Back H=Home L=Last G=Goto F=Find (Ctrl+F) %nextcol%N=Next (F3) %textcol%E=Edit M=Menu && pause --wait=20 --test-key &; set /A keycode=%@retval% > nul
pause keycode=%keycode%
if %keycode%==0x1 && set read=M
if %keycode%==0x1C0D && set read=zyx
if %keycode%==0x2044 && set read=D
if %keycode%==0x1655 && set read=U
if %keycode%==0x184F && set read=O
if %keycode%==0x3042 && set read=B
if %keycode%==0x2348 && set read=H
if %keycode%==0x264C && set read=L
if %keycode%==0x2247 && set read=G
if %keycode%==0x2146 && set read=F
if %keycode%==0x2106 && set read=F
if %keycode%==0x314E && set read=N
if %keycode%==0x3D00 && set read=N
if %keycode%==0x1245 && set read=E
if %keycode%==0x324D && set read=M
endlocal && set read=%read%
pause read=%read%
#

I added a few pictures showing this menu in 'action'.

 

1. Directly after key-combination 'CTRL+F': https://postimg.cc/Z9RNzRWr

 

2. After hitting (many times) 'F3': https://postimg.cc/jnSqL87m (still more instances detected)

 

3. After last key 'F3' and ready for next search: https://postimg.cc/zyyf5PCc (this time with 'F')

 

I think, this opens many new possibilities....

 

I am very greatfull for your help. :thumbup:
 


Edited by deomsh, 26 March 2021 - 11:35 PM.


#15 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 27 March 2021 - 04:42 PM

It looks fine :thumbup: , you are welcome of course. :)

 

:duff:

Wonko



#16 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 30 March 2021 - 08:01 PM

I did some more testing of the Keyboard Buffer regarding maximum length of writing variables, and 'calling' them back to the command-line.

 

With a changed version of KEYBUFF.G4B (see code at the end of this post) I managed to make a single entry in the Keyboard Buffer of about 8KB. Above 255 chars the second of the leading bytes is in use (little endian, lowest byte first).

But although big entries are call'able to the command-line with the Up-Arrow, they are not editable, so useless in my case.

 

After many trials I found following (experimental) result: maximum 'editable' entry-length in the Keyboard Buffer is 1600 chars (0x640 in hex, including the two leading bytes 0x642, or as showed inside the Keyboard Buffer '42 06'.

 

BTW: 'Editable' means: 'editable' once 'called' back to the command-line.

 

The maximum length of a 'full' command on the command-line is a bit lower: 1536 chars (0x600 in hex, or exactly three 512-byte sectors). Be aware: experimental findings, no claims of 'absolute truth' (or even accuracy....). :ph34r:

 

I made three print-screens, again on an external location. Why I'm not allowed to upload anything to reboot.pro? :unsure:

 

1) Including the commands the maximum length writing to memory with 'write' was 1536 chars (if I counted right): https://postimg.cc/QFmNhHDp

 

2) Redirecting to memory with 'echo': 1535 chars all inclusive: https://postimg.cc/zLMyYVwx

 

2) Redirecting to memory with 'pause': same as 'echo': https://postimg.cc/VJqg6PZ9

 

I found no 'clue' regarding the difference of one char.... :bye:

 

A print-screen of new version KEYBUFF.G4B 'in action', menu-item 'Clean & write': https://postimg.cc/XBkR5NWw

--------------------------------------------------------------------
KEYBUFF.G4B
--------------------------------------------------------------------
!BAT
debug 0
clear
echo KEYBUFF.G4B by deomsh (descriptions 'cooler' thanks to Wonko the Sane)
echo Goal is testing if a variable writing to the Keyboard Buffer can be 'called' afterwards on the command-line with the 'arrow-up'-key
echo Keyboard Buffer starts at 0x3EA4C0 and ends at 0x3EC4BF. Total length=0x2000 = 8192 bytes - just inside (md)0x0+0x1F63
echo Each entry in Keyboard Buffer starts with length of keys+3, in hex. Strings in C are 00 terminated
echo Each new entry starts at 0x3EA4C0 - a simple implementation of a LIFO (Last In First Out) stack
echo Maximum combined length = 0x600 = 1600 chars = maximum length of command-line (command max 1536 chars ?)
echo If termination is 'not good' (?) sometimes a space + rhombus-symbol is displayed if written entry is 'called' from the command-line
echo Seems safe to copy variables / other 'parts' of memory with length up to 1600 chars, second entry-byte is used too, for total length of one entry. Reversed bytes (little endian)
echo If Keyboard Buffer is full, there is no end-mark visible inside the buffer
echo After reboot to MS-DOS => back to Grub4Dos command-line, old Keyboard Buffer entries still visible, but always INACTIVE
echo So there is somewhere an "administration" of the 'active' Keyboard Buffer (?)
echo
echo Explore Keyboard buffer, have fun.....!
echo
:start
setlocal
pager off
set key=zyx && set keycode=
echo -n $[0x0F]V$[0x07]iew $[0x0F]C$[0x07]lean $[0x0F]I$[0x07]nsert $[0x0F]W$[0x07]rite $[0x0F]Q$[0x07]uit (Enter=View)$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==zyx && echo && set key=V
if %key%==V && call :view
if %key%==C && echo && call :cleanbuf
if %key%==I && echo && call :insert
if %key%==W && call :write
if %key%==Q && echo && endlocal && goto :eof
endlocal
goto :start

:cleanbuf
cat --hex --skip=0x3EA4C0 --length=0x30 (md)0x0+0x1F63 && echo 
call Fn.24 0x3EA4C0 0x00 0x2000
cat --hex --skip=0x3EA4C0 --length=0x30 (md)0x0+0x1F63 && echo 
goto :eof

:view
pager on
cat --hex --skip=0x3EA4C0 --length=0x2000 (md)0x0+0x1F63 && echo 
pager off
goto :eof

:insert
set key=zyx
echo Insert keys and view Keyboard Buffer or give $[0x0F]Enter$[0x07] to go back
set /p "key= > "
echo 
echo
if not "%key%"=="zyx" && goto :view
if "%key%"=="zyx" && echo && goto :eof

:write
setlocal
set "var254=Variable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla Variable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla Variable with spaces blabla blublu blablablabla. Gauw nog even weggaan!"
echo
set "var100=Dit is een klein verhaaltje van maar liefst honderd tekens, er is best een heleboel te zeggen hoor!"
set "var63=Dit is een klein verhaaltje van maar liefst drieenzestig tekens"
set key=zyx
set /p "key=Give name of variable > " && echo && echo
if %key%==zyx && echo && echo && set variable=var
if not %key%==zyx && set variable=%key%
echo Variable to write to keyboard buffer: %variable% && echo
call set "var=%%%variable%%%"
echo var=%var% && echo
if exist var && set "var=%var%" &; set /a varlena=%@retval% > nul
if exist var && set /a varlenp=%varlena%+1 > nul &; echo Length of variable=%varlena% chars && echo
if not exist var && echo No variable given && echo && endlocal && goto :eof
:numagain
set morevars= && set varslen=
set key=zyx && set keycode=
echo -n $[0x0F]N$[0x07]umber of variables to write to Keyboard Buffer ($[0x0F]Enter=1$[0x07]) $[0x0F]M$[0x07]enu$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==M && echo && endlocal && goto :eof
if %key%==zyx && set /a morevars=1 > nul
if not exist morevars && set /a key=
if not exist morevars && set /p "key= > " && echo
if not exist morevars && set /a morevars=%key% > nul &; if not %morevars%>=1 && endlocal && goto :eof
set /a "varslen=%morevars% * %varlena% + %morevars%" > nul
echo 
if %varslen%<=1600 && echo -n Number of variables to write=%morevars%, total number of chars=%varslen% && if %morevars%>=2 && echo , including ending spaces!
echo && echo 
if not %varslen%<=1600 && echo Keybuffer is limited to 1600 chars! && goto :numagain && echo
set key=zyx && set keycode=
echo -n $[0x0F]W$[0x07]rite variable $[0x0F]C$[0x07]lean & write $[0x0F]M$[0x07]enu (Enter=Write)$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==M && echo && endlocal && goto :eof
if %key%==C && call :cleanbuf
if not %key%==W && if not %key%==zyx && if not %key%==C && echo && endlocal && goto :eof
set /a varleno=0 > nul
echo -n > (md)0x3000+16
write --offset=%varleno% (md)0x3000+16 \x0A\x0A > nul
:morevars
pause --wait=0 %var% >> (md)0x3000+16
set /a morevars=%morevars%-1 > nul
if %morevars%>=1 && goto :morevars
cat --locate=\x0A (md)0x3000+16 > nul &; set /a varlenw=%?% > nul
cat --skip=%varlenw% --locate=\x0A --replace=\x00 --number=1 (md)0x3000+16 > nul
cat --locate=\x0A --replace=\x20 (md)0x3000+16 > nul
call :bufentry
write --offset=%varleno% (md)0x3000+16 %bufentry% > nul
set /A bufflen=0x2000-%varlenw% > nul
if %bufflen%>=1 && dd if=(md)0x0+0x1F63 of=(md)0x3000+16 bs=1 count=%bufflen% skip=0x3EA4C0 seek=%varlenw% > nul
if %key%==C && echo
if not %key%==C && echo && cat --hex --skip=0x3EA4C0 --length=0x10 (md)0x0+0x1F63 && echo ---------
dd if=(md)0x3000+16 of=(md)0x0+0x1F63 bs=1 count=0x2000 skip=0 seek=0x3EA4C0 > nul
cat --hex --skip=0x3EA4C0 --length=0x20 (md)0x0+0x1F63 && echo +++++++++
set /A varskip=0x3EA4C0+%varlenw%-0x10 > nul
if %varlenw%>=0x11 && cat --hex --skip=%varskip% --length=0x20 (md)0x0+0x1F63 && echo
endlocal
goto :eof

:bufentry
set /A varlenw=%varlenw%+1 > nul
if %varlenw%>=0x643 && set bufentry=\x42\x06
if %varlenw%<=0x642 && set bufentry=\x%varlenw:~3,2%\x0%varlenw:~2,1%
if %varlenw%<=0xFF && set bufentry=\x%varlenw:~2%\x00
if %varlenw%<=0xF && set bufentry=\x0%varlenw:~2,1%\x00
goto :eof

:keycodes
setlocal
set *
set keycode=%~1
set key=%~2
if not exist keycode && endlocal && goto :eof
## Order: uppercase (shift+), lowercase, other key.
if %keycode%==0x1 && set key=M
if %keycode%==0x11B && set key=M
if %keycode%==0x1C0D && set key=zyx
if not %keycode%==0x1E41 if not %keycode%==0x1E61 || set key=A
if not %keycode%==0x3042 if not %keycode%==0x3062 || set key=B
if not %keycode%==0x2E43 if not %keycode%==0x2E63 || set key=C
if not %keycode%==0x2044 if not %keycode%==0x2064 || set key=D
if not %keycode%==0x1245 if not %keycode%==0x1265 || set key=E
if not %keycode%==0x2146 if not %keycode%==0x2166 || set key=F
if not %keycode%==0x2247 if not %keycode%==0x2267 || set key=G
if not %keycode%==0x2348 if not %keycode%==0x2368 || set key=H
if not %keycode%==0x1749 if not %keycode%==0x1769 || set key=I
if not %keycode%==0x264C if not %keycode%==0x266C || set key=L
if not %keycode%==0x324D if not %keycode%==0x326D || set key=M
if not %keycode%==0x314E if not %keycode%==0x316E || set key=N
if not %keycode%==0x184F if not %keycode%==0x186F || set key=O
if not %keycode%==0x1950 if not %keycode%==0x1970 || set key=P
if not %keycode%==0x1051 if not %keycode%==0x1071 || set key=Q
if not %keycode%==0x1352 if not %keycode%==0x1372 || set key=R
if not %keycode%==0x1F53 if not %keycode%==0x1F73 || set key=S
if not %keycode%==0x1655 if not %keycode%==0x1675 || set key=U
if not %keycode%==0x2F56 if not %keycode%==0x2F76 || set key=V
if not %keycode%==0x1157 if not %keycode%==0x1177 || set key=W
if not %keycode%==0x2D58 if not %keycode%==0x2D78 || set key=X
if not %keycode%==0x1559 if not %keycode%==0x1579 || set key=
#if not %keycode%==0x2E03 && set key=CtrlC
#if not %keycode%==0x2106 && set key=CtrlF
#if not %keycode%==0x1910 && set key=CtrlP
#if not %keycode%==0x4900 && set key=CtrlS
#if not %keycode%==0x2F16 && set key=CtrlX
#if %keycode%==0x3C00 && set key=F2
#if %keycode%==0x3D00 && set key=F3
#if %keycode%==0x3920 && set key=SPACE
#if %keycode%==0x1C0D && set key=ENTER
#if %keycode%==0x11B && set key=ESCAPE
#if %keycode%==0xE08 && set key=BACKSPACE
#if %keycode%==0x4700 && set key=HOME
#if %keycode%==0x4F00 && set key=END
#if %keycode%==0x4900 && set key=PAGEUP
#if %keycode%==0x5100 && set key=PAGEDOWN
endlocal && set key=%key%
goto :eof

:eof

--------------------------------------------------------------------

Edited by deomsh, 30 March 2021 - 08:15 PM.


#17 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 31 March 2021 - 11:52 AM

EDIT: (post not editable any longer after 15 hours??)

"After many trials I found following (experimental) result: maximum 'editable' entry-length in the Keyboard Buffer is 1600 chars (0x640 in hex, including the two leading bytes 0x642, or as showed inside the Keyboard Buffer '42 06'."

Not 1600, but 1599, the last '0A' is changed to '00'. So the terminating '00' seems to be counted too! If I changed last '00' to a space ('20'), 'called' line gives some error sign. Can be deleted, but last space can't be added!

I edited my script accordingly, including some (minor) changes:

-------------------------------------------------------------------------------
KEYBUFF.G4B
-------------------------------------------------------------------------------
!BAT
debug 0
clear
echo KEYBUFF.G4B by deomsh (descriptions 'cooler' thanks to Wonko the Sane)
echo Goal is testing if a variable writing to the Keyboard Buffer can be 'called' afterwards on the command-line with the 'Arrow-up'-key
echo Keyboard Buffer starts at 0x3EA4C0 and ends at 0x3EC4BF. Total length=0x2000 = 8192 bytes - just inside (md)0x0+0x1F63
echo Each entry in Keyboard Buffer starts with length of keys+3, in hex. Strings in C are 00 terminated
echo Each new entry starts at 0x3EA4C0 - a simple implementation of a LIFO (Last In First Out) stack
echo Maximum length = 0x5FF = 1599 chars = maximum length of command-line (command max 1536 chars ?)
echo If termination is 'not good' (?) sometimes a space + rhombus-symbol is displayed if written entry is 'called' from the command-line
echo Seems safe to copy variables / other 'parts' of memory with length up to 1600 chars, second entry-byte is used too, for total length of one entry. Reversed bytes (little endian)
echo If Keyboard Buffer is full, there is no end-mark visible inside the buffer
echo After reboot to MS-DOS => back to Grub4Dos command-line, old Keyboard Buffer entries still visible, but always INACTIVE
echo So there is somewhere an "administration" of the 'active' Keyboard Buffer (?)
echo
echo Explore Keyboard buffer, have fun.....!
echo
:start
setlocal
pager off
set key=zyx && set keycode=
echo -n $[0x0F]V$[0x07]iew $[0x0F]C$[0x07]lean $[0x0F]I$[0x07]nsert $[0x0F]W$[0x07]rite $[0x0F]Q$[0x07]uit (Enter=View)$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==zyx && echo && set key=V
if %key%==V && call :view
if %key%==C && echo && call :cleanbuf
if %key%==I && echo && call :insert
if %key%==W && call :write
if %key%==Q && echo && endlocal && goto :eof
endlocal
goto :start

:cleanbuf
cat --hex --skip=0x3EA4C0 --length=0x30 (md)0x0+0x1F63
echo ------------------------------------------------------------------------------
call Fn.24 0x3EA4C0 0x00 0x2000
cat --hex --skip=0x3EA4C0 --length=0x30 (md)0x0+0x1F63 && echo 
goto :eof

:view
pager on
cat --hex --skip=0x3EA4C0 --length=0x2000 (md)0x0+0x1F63 && echo 
pager off
goto :eof

:insert
set key=zyx
echo Insert keys and view Keyboard Buffer or give $[0x0F]Enter$[0x07] to go back
set /p "key= > "
echo 
echo
if not "%key%"=="zyx" && goto :view
if "%key%"=="zyx" && echo && goto :eof

:write
setlocal
set "var255=Variable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla Variable with spaces blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla Variable with spaces blabla blublu blablablabla. Gauw nog even weggaan..!"
echo
set "var99=Dit is een klein verhaaltje van maar liefst honderd tekens, er is best een heleboel te zeggen hoor!"
set "var63=Dit is een klein verhaaltje van maar liefst drieenzestig tekens"
set key=zyx
set /p "key=Give name of variable > " && echo && echo
if %key%==zyx && echo && echo && set variable=var
if not %key%==zyx && set variable=%key%
echo Variable to write to keyboard buffer: %variable% && echo
call set "var=%%%variable%%%"
echo var=%var% && echo
if exist var && set "var=%var%" &; set /a varlena=%@retval% > nul
if exist var && set /a varlenp=%varlena%+1 > nul &; echo Length of variable=%varlena% chars && echo
if not exist var && echo No variable given && echo && endlocal && goto :eof
:numagain
set morevars= && set varslen=
set key=zyx && set keycode=
echo -n $[0x0F]Enter=1$[0x07] $[0x0F]N$[0x07]umber of variables to write to Keyboard Buffer $[0x0F]M$[0x07]enu$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==M && echo && endlocal && goto :eof
if %key%==zyx && set /a morevars=1 > nul
if not exist morevars && set /a key=
if not exist morevars && set /p "key= > " && echo
if not exist morevars && set /a morevars=%key% > nul &; if not %morevars%>=1 && endlocal && goto :eof
set /a "varslen=%morevars% * %varlena% + %morevars% - 1" > nul
echo 
if %varslen%<=1599 && echo -n Number of variables to write=%morevars%, total number of chars=%varslen% && if %morevars%>=2 && echo , including ending spaces in between!
echo && echo 
if not %varslen%<=1599 && echo Keyboard buffer is limited to 1599 chars! && goto :numagain && echo
set key=zyx && set keycode=
echo -n $[0x0F]W$[0x07]rite variable $[0x0F]C$[0x07]lean & write $[0x0F]M$[0x07]enu (Enter=Write)$[0x07] && pause --wait=180 --test-key &; set /A keycode=%@retval% > nul
echo
call :keycodes "%keycode%" "key"
if %key%==M && echo && endlocal && goto :eof
if %key%==C && echo && call :cleanbuf
if not %key%==W && if not %key%==zyx && if not %key%==C && echo && endlocal && goto :eof
set /a varleno=0 > nul
echo -n > (md)0x3000+16
write --offset=%varleno% (md)0x3000+16 \x0A\x0A > nul
:morevars
pause --wait=0 %var% >> (md)0x3000+16
set /a morevars=%morevars%-1 > nul
if %morevars%>=1 && goto :morevars
cat --locate=\x0A (md)0x3000+16 > nul &; set /a varlenw=%?% > nul
cat --skip=%varlenw% --locate=\x0A --replace=\x00 --number=1 (md)0x3000+16 > nul
cat --locate=\x0A --replace=\x20 (md)0x3000+16 > nul
set /A varlenw=%varlenw%+1 > nul
call :bufentry
write --offset=%varleno% (md)0x3000+16 %bufentry% > nul
set /A bufflen=0x2000-%varlenw% > nul
if %bufflen%>=1 && dd if=(md)0x0+0x1F63 of=(md)0x3000+16 bs=1 count=%bufflen% skip=0x3EA4C0 seek=%varlenw% > nul
if %key%==C && echo
if not %key%==C && echo && cat --hex --skip=0x3EA4C0 --length=0x10 (md)0x0+0x1F63 && echo -------------------------------------------------------------------------------
dd if=(md)0x3000+16 of=(md)0x0+0x1F63 bs=1 count=0x2000 skip=0 seek=0x3EA4C0 > nul
cat --hex --skip=0x3EA4C0 --length=0x20 (md)0x0+0x1F63 && echo ||||||||
set /A varskip=0x3EA4C0+%varlenw%-0x10-0x2 > nul
if %varlenw%>=0x11 && cat --hex --skip=%varskip% --length=0x20 (md)0x0+0x1F63 && echo
endlocal
goto :eof

:bufentry
if %varlenw%>=0x643 && set bufentry=\x42\x06 && set /A varlenw=0x642 > nul
if %varlenw%<=0x642 && set bufentry=\x%varlenw:~3,2%\x0%varlenw:~2,1%
if %varlenw%<=0xFF && set bufentry=\x%varlenw:~2%\x00
if %varlenw%<=0xF && set bufentry=\x0%varlenw:~2,1%\x00
goto :eof

:keycodes
setlocal
set *
set keycode=%~1
set key=%~2
if not exist keycode && endlocal && goto :eof
## Order: uppercase (shift+), lowercase, other key.
if %keycode%==0x1 && set key=M
if %keycode%==0x11B && set key=M
if %keycode%==0x1C0D && set key=zyx
if not %keycode%==0x1E41 if not %keycode%==0x1E61 || set key=A
if not %keycode%==0x3042 if not %keycode%==0x3062 || set key=B
if not %keycode%==0x2E43 if not %keycode%==0x2E63 || set key=C
if not %keycode%==0x2044 if not %keycode%==0x2064 || set key=D
if not %keycode%==0x1245 if not %keycode%==0x1265 || set key=E
if not %keycode%==0x2146 if not %keycode%==0x2166 || set key=F
if not %keycode%==0x2247 if not %keycode%==0x2267 || set key=G
if not %keycode%==0x2348 if not %keycode%==0x2368 || set key=H
if not %keycode%==0x1749 if not %keycode%==0x1769 || set key=I
if not %keycode%==0x264C if not %keycode%==0x266C || set key=L
if not %keycode%==0x324D if not %keycode%==0x326D || set key=M
if not %keycode%==0x314E if not %keycode%==0x316E || set key=N
if not %keycode%==0x184F if not %keycode%==0x186F || set key=O
if not %keycode%==0x1950 if not %keycode%==0x1970 || set key=P
if not %keycode%==0x1051 if not %keycode%==0x1071 || set key=Q
if not %keycode%==0x1352 if not %keycode%==0x1372 || set key=R
if not %keycode%==0x1F53 if not %keycode%==0x1F73 || set key=S
if not %keycode%==0x1655 if not %keycode%==0x1675 || set key=U
if not %keycode%==0x2F56 if not %keycode%==0x2F76 || set key=V
if not %keycode%==0x1157 if not %keycode%==0x1177 || set key=W
if not %keycode%==0x2D58 if not %keycode%==0x2D78 || set key=X
if not %keycode%==0x1559 if not %keycode%==0x1579 || set key=Y
#if not %keycode%==0x2E03 && set key=CtrlC
#if not %keycode%==0x2106 && set key=CtrlF
#if not %keycode%==0x1910 && set key=CtrlP
#if not %keycode%==0x4900 && set key=CtrlS
#if not %keycode%==0x2F16 && set key=CtrlX
#if %keycode%==0x3C00 && set key=F2
#if %keycode%==0x3D00 && set key=F3
#if %keycode%==0x3920 && set key=SPACE
#if %keycode%==0x1C0D && set key=ENTER
#if %keycode%==0x11B && set key=ESCAPE
#if %keycode%==0xE08 && set key=BACKSPACE
#if %keycode%==0x4700 && set key=HOME
#if %keycode%==0x4F00 && set key=END
#if %keycode%==0x4900 && set key=PAGEUP
#if %keycode%==0x5100 && set key=PAGEDOWN
endlocal && set key=%key%
goto :eof

:eof

-------------------------------------------------------------------------------

Action picture (fourth in previous post) of max length is more understandable now too (last part minus two bytes): https://postimg.cc/8Fb3Npb6

 


Edited by deomsh, 31 March 2021 - 12:25 PM.


#18 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 01 April 2021 - 01:43 PM

Why I'm not allowed to upload anything to reboot.pro? :unsure:

Because we (reboot.pro) don't trust you :w00t: :ph34r:
 
Seriously, there is a setting somewhere on the board (that may BTW also have been changed in the recent board update) that prevents users with less than 30 or 50 posts (IF I recall correctly AND IF the setting has not been changed/reset in the upgrade) from:
1) editing own posts after a given time has passed
2) attaching anything to posts

 

You should PM erwan.l, he may be able to allow you to edit posts/attach things, when he has time to mingle with the board. 

 

 

 

Not 1600, but 1599, the last '0A' is changed to '00'. So the terminating '00' seems to be counted too! If I changed last '00' to a space ('20'), 'called' line gives some error sign. Can be deleted, but last space can't be added!

 ... strings in C are 00 terminated ...   :whistling: ;)

 

Wonko



#19 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 03 April 2021 - 03:07 PM

Thanks for the info :rolleyes:

About: "... strings in C are 00 terminated ... :whistling: ":

of cause they were there. I didn't mention, because I did 'Clean & write', so buffer consists of zero's (can be seen in the -external- action-picture). Only the 'size' (in my script 'varlenw') should be set one higher, 8K '00's are waiting to be the terminating 'one'. But now everything functions as desired, a space at the end is no longer a solution.

I am also comfortable with the '0A' termination of the 'pause'-command. If only one variable is redirected to memory, replacing '0A' with '00' is very easy. I found redirecting a variable to memory with 'pause' somewhere in Steve6375's book 'Getting started with Grub4dos_v0.95' (it's worth every penny!).

Below is how 'Write variable' looks, existing history is shifted down (this time not an print-screen, but using GRAB.G4B):BTW: next version of KEYBUFF.G4B already, but new functions ('Import', 'Export' and 'Fifo') are unfinished yet.
 

Length of variable=63 chars                                                     
                                                                                
Enter=1 Number of variables to write to Keyboard Buffer Menu.                   
 > 25                                                                           
                                                                                
Number of variables to write=25, total number of chars=1599, including ending sp
aces in between!                                                                
                                                                                
                                                                                
Write variable Clean & write Menu (Enter=Write).                                
                                                                                
003EA4C0: 05 00 32 35  00 08 00 76  61 72 36 33  00 0A 00 6B ; ..25...var63...k 
------------------------------------------------------------------------------- 
003EA4C0: 42 06 44 69  74 20 69 73  20 65 65 6E  20 6B 6C 65 ; B.Dit is een kle 
003EA4D0: 69 6E 20 76  65 72 68 61  61 6C 74 6A  65 20 76 61 ; in verhaaltje va 
003EA4E0: 6E 20 6D 61  61 72 20 6C  69 65 66 73  74 20 64 72 ; n maar liefst dr 
||||||||                                                                        
003EAAF0: 69 65 65 6E  7A 65 73 74  69 67 20 74  65 6B 65 6E ; ieenzestig teken 
003EAB00: 73 00 05 00  32 35 00 08  00 76 61 72  36 33 00 0A ; s...25...var63.. 
003EAB10: 00 6B 65 79  62 75 66 66  00 09 00 2F  2F 2F 2F 2F ; .keybuff...///// 
                                                                                
View Clean Test Import Export Fifo Write Quit (Enter=View).                     
                                                                                
grub> grab                                                                      
                                                                                         

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

I did some reading in the source-code of Grub4Dos, and I found something mentioned about the maximum length of the command-line in 'char_io.c':

/* Don't use this with a MAXLEN greater than 1600 or so!  The problem
   is that GET_CMDLINE depends on the everything fitting on the screen
   at once.  So, the whole screen is about 2000 characters, minus the
   PROMPT, and space for error and status lines, etc.  MAXLEN must be
   at least 1, and PROMPT and CMDLINE must be valid strings (not NULL
   or zero-length).

Seems this matches my earlier experimental results (??).

Also the maximum length of a command seems to be somewhere in 'cmdline.c' (if I am interpreting the code in the right way) :unsure:

cmd_buffer += (expand_var(heap,cmdline_buf,0x600)+0x10)&-0x10;

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

In practice I want to write strings in memory to the 'Keyboard Buffer'; to 'call' them as input for a 'set /p' statement (I saw in the source-code the official name is 'history buffer').

I found the maximum length of a string MUST be cut-off at 510 or 511 chars. My experiments showed me that typing in a 'set /p'-command-line is limited to 511 chars (so according the specs of a variable). If I 'call' a 511 char history-line, this length can be entered. But after editing that line first, length is limited to 510 chars.

If a line from history is 'called' with key 'Arrow-Up', a longer line can be 'called'. But after 'Enter' my two test systems crashed both. In VBOX 6 (64-bit) everything freezes, so I had to reboot; in Limbo-x86 (Android), the whole App crashed. Sadly Limbo-x86 is not fully compatible with Grub4Dos, and the development of the App is discontinued. :hmm:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

For now I have one problem left.

The number of instances in the active 'history buffer' is limited to the the actual commands given, which makes sense (I guess). Strings written to the 'set /p'-command-line are counted too (and written to the 'history buffer' - see first 'grabbed print-screen' above). Keystrokes given to 'pause --test-key' are NOT written to history. If I clean the 'history buffer', this number of 'the actual commands given' seems to be unchanged.

I tried exporting / importing the whole 'history buffer' to/from a file, but after reboot to MS-DOS and restarting Grub4Dos, the number of 'history-entries' is limited to the number of actual commands given in the 'new' session -  before importing a 'history buffer' from file.

 

The only way to get more history-entries is to give first the same number of commands as 'history-entries' desired!
Every 'real' char like 'Q' is 'good' (Grub4Dos will say 'Error: No such command:' - but that doesn't matter here), but a key like 'Enter' doesn't count in this case (which make sens too, I'm afraid).

I tried to found some memory-address where the number of actual 'commands' is counted, but I failed. The source-code mentions a 'static int' in this case:
 

/* The number of the history entries.  */
static int num_history = 0;

/* Get the NOth history. If NO is less than zero or greater than or
   equal to NUM_HISTORY, return NULL. Otherwise return a valid string.  */
static char *
get_history (int no)
{
  int j;
  char *p = (char *) HISTORY_BUF;
  if (no < 0 || no >= num_history)
	return 0;
  /* get history NO */
  for (j = 0; j < no; j++)
  {
	p += *(unsigned short *)p;
	if (p > (char *) HISTORY_BUF + MAX_CMDLINE * HISTORY_SIZE)
	{
		num_history = j;
		return 0;
	}
  }

  return p + 2;
} 

What I have been reading about such a variable on 'stackoverflow', there is no hope left for me.

Or am I wrong, and is it possible to locate this variable somewhere in memory?

Any ideas would be greatly appreciated! :bye:


Edited by deomsh, 03 April 2021 - 03:36 PM.


#20 AndrewBeen

AndrewBeen
  • Members
  • 1 posts
  •  
    United States

Posted 05 April 2021 - 01:58 PM

Yes it is possible and this process is described in the Grub4dos manual!


Edited by AndrewBeen, 05 April 2021 - 01:58 PM.


#21 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 08 April 2021 - 10:02 PM

Thanks AndrewBeen!

 

So: 'If 'ol else fails, read the manual'....? Didn't find anything special, but I realized I could try to compare Grub4Dos whole use of 32MB memory after a new command. earlier I compared only 0x2000 sectors (of 512 byte each). Was'nt needed in retrospective, but was 'helpful' *somehow*.

 

This time I was able to identify 'num_history'. Complicating is that almost each version of Grub4Dos I tested has it's own special memory address. Maybe better to say each 'build' (the compiler seems to 'rule' in case of a variable like 'static int' ). Luckily I found a sort of unique string to identify a small region.

 

With following script I was able to auto-detect 'num_history' for all TEN Grub4Dos versions I have tested (including last version of 0.45c). In the neighborhood I found the length of last command too, also shown if running the script.

--------------------------------------------------------------------------
NUMHIST.G4B
--------------------------------------------------------------------------
!BAT
echo
cat --skip=0x340000 --locate=\x00\x00\x00\x00\x00\x92\x3E\x00 (md)0x0+0x1D00 > nul &; set /A ZHistory=%?% > nul
set /A SHistory=%ZHistory%+0x8 > nul
read %SHistory% > nul &; set /A read=%@retval% > nul
if not %read%==0x6 && set /A SHistory=%SHistory%+0x4 > nul &; read %SHistory% > nul &; set /A read=%@retval% > nul
if %read%==0x6 && set /A NHistory=%SHistory%+0x10 > nul ! set NHistory=
if not exist NHistory && echo num_history not found! && goto :eof
set /A offset=%NHistory%-%ZHistory% > nul
if %offset%==0x18 && set /A lenbyte=%ZHistory%+0xC > nul
if %offset%==0x1C && set /A lenbyte=%ZHistory%+0x8 > nul
echo Shows num_history, starting at %NHistory% and cmd-length at %lenbyte% && echo
:nextcat
read %NHistory% > nul &; set /a numhist=%@retval% > nul
read %lenbyte% > nul &; set /a cmdlen=%@retval% > nul
cat --hex --skip=%NHistory% --length=0x4 (md)0x0+0x1D00 && cat --hex --skip=%lenbyte% --length=0x2 (md)0x0+0x1D00
echo num_history is %numhist% entries and length of command-line is %cmdlen% chars && echo
:next
set next=zyx
set /p "next= Insert chars or Q=Quit > " && echo && echo
if "%next%"=="zyx" && goto :next
if not "%next%"=="Q" && goto :nextcat

:eof

--------------------------------------------------------------------------

Also a link to an action-picture: https://postimg.cc/9zmpt8GX (just before last changes to NUMHIST.G4B)



#22 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16066 posts
  • Location:The Outside of the Asylum (gate is closed)
  •  
    Italy

Posted 09 April 2021 - 10:17 AM

Very good. :)

 

:cheerleader: Go, Deomsh, go! :cheerleader:

 

:duff:

Wonko 



#23 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 09 April 2021 - 09:05 PM

Thanks Wonko :)

 

I forgot to mention I tested Grub4Dos 0.45b, 0.45a and 0.45 too, first didn't found 'num_history'.

 

After a closer look in 0.45b memory 'num_history' can be found with '00 92 3E 00' + extra zero's (needed!) too (appears to be the address in little endian of the so called 'CMDLINE_BUF': contains last keyboard command). But in version 2012-01-16 'num_history' lies BELOW '00 92 3E 00': https://postimg.cc/WDzwMKSH My script can only run partly on 0.45b after deleting/changing not supported commands/operators: https://postimg.cc/gnKV1dT7 Still a nice playground.

 

But 0.45a 2010-04-20 uses another address, '60 82 3E 00' in the neighborhood of 'num_history' (have no source code, but I presume it's the 'CMDLINE_BUF' too). And 'num_history' also earlier. Version 2010-04-20 starts on 0x0033FD84: https://postimg.cc/bZ71tJDs (script cannot run on this version!). Build is from http://grub4dos.chen...2010-04-20.zip/

 

Version 0.45 2009-12-23: almost the same as 0.45a, but 'num_history' starts on 0x33D878: https://postimg.cc/620ZgfHv

 

BTW skip search before 0x340000 is not needed, only useful on Limbo X86 because it's very slow (imagine the poor ARM-processor simulating everything as an X86). :magic: Version 0.45 starts earlier too!


Edited by deomsh, 09 April 2021 - 09:14 PM.


#24 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 03 May 2021 - 03:37 PM

Lately I tried to use NUMHIST.G4B in KEYBUFF.G4B (see above for the scripts).

 

This time the ':numhist' sub-routine worked only the first time, the second time the searched '06'-value has been  changed to '1A', and num_history wasn't found anymore, although it's still there. See first (external) action print-screen: https://postimg.cc/McyLGSwz The '06'-value is in the print-screen on address 0x35763C (variable 'SHistory' in my script).

 

This problem drew my attention to the value on address 0x357648. It appears this value is always the sum of value starting at address 0x35763C and the length of command-line (starting at address 0x357640).

It took me a while to realize that in fact the length of command-line is the result of a substraction: highest value (starting at address 0x357648) minus the constant 'SHistory'-value (starting at address 0x35763C - and set to '06' in my script).

 

After some counting I found the 'new' constant '1A'-value is exactly the number of the chars in the message of 'set /p' I used in my script! On the first print-screen seen on line 13.

If I changed this message to 6 chars: 'Test> ' , the sub-routine found 'num_history' as expected. Be aware one space is included in these six chars! See second (external) action print-screen: https://postimg.cc/LYVQS3pD

 

Without message in 'set /p' the constant became zero and the value (starting) at address 0x357640) is the same as the length of the command-line, and my script couldn't find 'num_history' anymore. See third (external) action print-screen: https://postimg.cc/kB5Jkjmj

 

After each new start of the script from the Grub4Dos command-line, the '06'-value has always been present. So this suggests this 'constant' is just the (further unused) message-part of the Grub4Dos command-line, the familiar 'grub> ' :afro:

 

BTW now it also make 'more sense' why 'set /p' always starts at the beginning of a command-line...

 

 



#25 deomsh

deomsh

    Frequent Member

  • Advanced user
  • 196 posts
  •  
    Netherlands

Posted 17 May 2021 - 09:52 PM

I wrote some sub-routines for updating num_history.

 

First one, ':NHistory' is a smaller version of ':num_hist', used in earlier scripts above. Only the variable 'NHistory' must be stay for further use.

## Call before any 'set /p' statements are used (unless their message-part is exactly six chars long!)

:NHistory
setlocal && set *
cat --skip=0x340000 --locate=\x00\x00\x00\x00\x00\x92\x3E\x00 (md)0x0+0x1D00 > nul &; set /A ZHistory=%?% > nul
set /A SHistory=%ZHistory%+0x8 > nul
read %SHistory% > nul &; set /A read=%@retval% > nul
if not %read%==0x6 && set /A SHistory=%SHistory%+0x4 > nul &; read %SHistory% > nul &; set /A read=%@retval% > nul
if %read%==0x6 && set /A NHistory=%SHistory%+0x10 > nul
if not %read%==0x6 && set NHistory=
if not exist NHistory && echo num_history not found && pause --wait=7
endlocal && set NHistory=%NHistory% && goto :eof

I use following sub-routines to increase num_history. If ':add_history' is called, num_history will be set 'one' higher.

## NHistory must be set before!

:add_hist
setlocal && set * && set NHistory=%NHistory%
if not exist NHistory && endlocal && echo Abort: NHistory not found && pause --wait=7 && goto :eof
read %NHistory% > nul &; set /A numhist=%@retval% > nul &; echo num_history found: %numhist%
set /A numhist=%numhist%+0x1 > nul &; echo num_history to write %numhist%
call :cnvBE2LE "%numhist%"
if not exist valueLE && endlocal && echo Abort: can not write num_history to NHistory && pause --wait=7 && goto :eof
write --offset=%NHistory% --bytes=4 (md)0x0+0x1D00 %valueLE% > nul
read %NHistory% > nul &; set /A numhist=%@retval% > nul &; echo num_history written: %numhist%
cat --hex --skip=%NHistory% --length=0x4 (md)0x0+0x1D00
endlocal && set valueLE= && goto :eof

:cnvBE2LE
setlocal && set * && set value=%~1 &; set value=%value:~2% &; set /a valuelen=8-%@retval% > nul &; if not %valuelen%>=0 && echo Abort: 0x%value% is not a valid 32-bits hexadecimal value && endlocal && set valueLE= && goto :eof
:loopLE
if %valuelen%>=1 && set value=0%value% && set /a valuelen=%valuelen%-1 > nul && goto :loopLE
set valueLE=\x%value:~6,2%\x%value:~4,2%\x%value:~2,2%\x%value:~0,2%
endlocal && set valueLE=%valueLE% && goto :eof

The last sub-routine ':cnvBE2LE' is a new attempt to write a universal sub-routine to convert a max. 32-bit (Big Endian) hex value to Little Endian, ready for use with 'write'. Only six lines! I am not aware of a 'direct' method to write a 32-bit hex-value in Little Endian format with help of Grub4Dos. :unsure:

 

B.T.W. All echo and pause statements can be left out, the cat --hex statement too.

 







Also tagged with one or more of these keywords: grub4dos

4 user(s) are reading this topic

0 members, 4 guests, 0 anonymous users