|
Joined: Feb 2004
Posts: 2,608 Likes: 315
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,608 Likes: 315 |
This function actually first "presses" all of the fields for a given keycode, then it releases them one by one each time it gets called after that. It seems really counter-intuitive. One of the things that really threw me for a loop is that it does things "reversed" like field->set_value(!m_status_keydown). m_status_keydown comes in as false, it sets all the fields, then it flips the m_status_keydown. You've missed some of the subtlety - it presses the keys one-at-a-time with a delay between each to ensure there's time for matrix scanning to detect the modifiers before the character key is pressed. Without this, uppercase letters, shifted numbers etc. don't work on Amiga, Sun, RM Nimbus, and a host of other systems (I implemented this myself after over a year of complaints about it not working but none of the natural keyboard advocates addressing it). However it releases all the emulated keys at the same time - it doesn't wait for the timer to fire between releasing keys. Yes, it's "dumb" in cases where a sequence of shifted keys are typed in a row - it presses and releases shift for each one - but making it "smarter" about this would complicated the code quite a bit. The trouble with adding a delay on CR is it's going to be a real pain for actually typing into a text editor, and even at a command prompt, different commands all take different amounts of time.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Hi Vas,
Yes I think I've missed a lot of the subtlety of how it works and how it needs to work across a spectrum of different machines.
Perhaps some of the problem is trying to get the natural keyboard to do a paste function with the same routine that handles normal user input.
A paste doesn't have to be fast, it could be on its own timer (and buffer) and just feed its keystrokes into the natural keyboard's posting systems on its own timetable. Then you could do it as slowly as you wish and not affect the normal typing.
|
|
|
|
Joined: Dec 1999
Posts: 1,180 Likes: 2
Very Senior Member
|
Very Senior Member
Joined: Dec 1999
Posts: 1,180 Likes: 2 |
I could have sworn this was all working in the (distant) past with natural keyboard mappings for apple2 (which I set up iirc) and a coded delay after carriage returns when pasting, I guess various refactorings over the years KO'd it.
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
It can't work with a fixed delay, because Applesoft takes more or less an unbounded amount of time to process a line. (Up to the limits of what you can fit on one line, of course). You'd probably want to use something like CiderPress which can convert tokenized .BAS files to and from .TXT listing files.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I thought I'd see if I could do something with lua and coroutines to feed keystrokes with delays. So I create a lua coroutine to pump keystrokes from a buffer. It's called every frame and calls coroutine.yield() when it's done. After a normal keystroke, it delays 3 frames. After a cr, it will delay 5*60 frames. What's kind of cool about lua coroutines is that you can call them with parameters if you like. So to add text I call the coroutine with a parameter. Just an experiment...
-- you must initialize these globals or the routine won't work, any error in the coroutine kills it so coroutine.status is dead
keyfeed_buffer = ""
keydelay = -1
keyfeed_buffer_pos = 1
normalkeydelay = 3
crkeydelay = 5 * 60
function keyboard_feeder()
while 1 do
--print("going to yield")
newparam = coroutine.yield()
--print ("keyboard_feeder_coroutine")
if newparam == nil then
--print("keydelay" .. keydelay)
if keydelay < 0 then -- get the next character
nextkeytofeed = string.sub(keyfeed_buffer,keyfeed_buffer_pos,keyfeed_buffer_pos)
keyfeed_buffer_pos = keyfeed_buffer_pos+1
emu.keypost(nextkeytofeed)
if nextkeytofeed == "" then keydelay = -1; keyfeed_buffer = ""; keyfeed_buffer_pos = 1
elseif nextkeytofeed == "\n" then keydelay = crkeydelay
else keydelay = normalkeydelay
end
else
keydelay = keydelay -1
end
else
-- print("adding " .. newparam .. " to buffer");
keyfeed_buffer=keyfeed_buffer .. newparam;
-- print(keyfeed_buffer);
end -- if
end -- while
end -- function
function call_keyboard_feeder()
--print ("call keyboard feeder")
coroutine.resume(keyboard_feeder_coroutine)
--print ("done call keyboard feeder")
end
function add_text(newtext)
coroutine.resume(keyboard_feeder_coroutine,newtext)
end
function register_keyboard_feeder()
keyboard_feeder_coroutine=coroutine.create(keyboard_feeder)
table.insert(dispatch_list,call_keyboard_feeder)
end
dispatch_list = { }
function frame_dispatcher()
for index,my_func in pairs(dispatch_list) do my_func() end
end
if already_registered_frame_dispatcher == nil then
emu.register_frame(frame_dispatcher);
already_registered_frame_dispatcher = 1
end
function cld()
dispatch_list = {}
end
print("type cld(); to stop a runaway dispatch");
cld()
register_keyboard_feeder()
add_text("this is a test of the emergency broadcast system.\n")
add_text("this is only a test.\n")
add_text("FEEDING 255 CHARACTERS.\n")
for i=1,255 do add_text(string.char(string.byte("0")+i%10)) end
add_text("\n")
add_text("That's 255 characters\n")
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
If you're feeding from Lua, you should be able to check the Apple II zero page variables to determine when Applesoft is ready to accept input.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Perhaps I could watch the PC of the apple and see when it hits the loop to accept user input. I don't know where it actually stores the buffer position in the zero page. I was thinking that it just kept it in the X register as far as I could tell.
I could register a function that would watch the PC.
for key,value in pairs(manager:machine().devices[":maincpu"].state) do print(key,value) end PC sol.device_state_entry*: 0x55a370aea448 CURFLAGS sol.device_state_entry*: 0x55a370aea598 IR sol.device_state_entry*: 0x55a370ae9848 CURSP sol.device_state_entry*: 0x55a370aea848 P sol.device_state_entry*: 0x55a370ae9c48 SP sol.device_state_entry*: 0x55a370ae9998 CURPC sol.device_state_entry*: 0x55a370aeac48 A sol.device_state_entry*: 0x55a370aea198 GENPC sol.device_state_entry*: 0x55a370aead98 Y sol.device_state_entry*: 0x55a370ae9d98 X sol.device_state_entry*: 0x55a370aea048
print(manager:machine().devices[":maincpu"].state["PC"].value) 64903
Maybe I could even stuff the keys into the $200-2FF input buffer rather than going through posting keystrokes.
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
That's an idea as well - put a whole line into the buffer, adjust the buffer position accordingly, and send an Enter keypress.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
It's an Applesoft TAS!
Last edited by crazyc; 10/12/17 11:02 PM.
|
|
|
0 members (),
58
guests, and
5
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,331
Posts122,197
Members5,077
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|