Previous Thread
Next Thread
Print Thread
Page 1 of 3 1 2 3
Joined: May 2009
Posts: 2,208
Likes: 355
J
Very Senior Member
OP Offline
Very Senior Member
J
Joined: May 2009
Posts: 2,208
Likes: 355
This question is primarily directed at Golden Child, but I'm hoping Vas might be able to provide some insight as well. This is in regards to my thread here: https://old.reddit.com/r/MAME/comments/17i3er5/input_question_for_anyone_who_uses_the_nes_driver/

I know that there are video overlays that one can use with OBS to record the state of a controller at any given moment, what I want is to re-create such a thing within MAME itself in order to compare the two.

All I really want is for there to be well-positioned boxes for: D-pad L/R/U/D, and Buttons 1-4. If it's possible to make a Lua script to read the current inputs that MAME is registering, and either fill or not-fill a surrounding with a highlight whenever that button is considered to be pressed, that would be a huge help, because if it's overlaid on the window, then I'll capture it while recording a given session. I can then see where the disagreement originates: If MAME's idea of "which button is pressed" differs from the controller overlay, then that could point the finger one way. If not, then it makes it clearer that the MAME driver for the NES itself is flawed in how it handles inputs.

Joined: Feb 2004
Posts: 2,579
Likes: 287
Very Senior Member
Offline
Very Senior Member
Joined: Feb 2004
Posts: 2,579
Likes: 287
If you just want to display inputs as seen by the emulated system, you’re better off just making a layout file. Use the inputs to set the state of elements, and make them draw a different colour box depending on the state. You can do it with Lua script, but it’s a lot more work. If you ask over at the MAME Artwork forum, most of the more experienced guys there have mastered doing this for simple cases, so you could probably get more detailed examples from them. Also it’s kind of hap’s thing.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
Hi, JD,

sure I can whip something up, gimme an hour or two, gotta work out how to read an nes ioport in a lua script

print(manager.machine.ioport.ports[":ctrl1:joypad:JOYPAD"]:read())

I'll also try Vas's suggestion to make a simple layout.

(woo hoo crossed the 1000 post mark)

Last edited by Golden Child; 10/28/23 06:31 PM.
1 member likes this: robcfg
Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
Ok, here's a little script that will show the buttons for the left controller:

Code
function iifnot0(a,b,c) if a~=0 then return b else return c end end
function drawoverlay()
dpadx,dpady = 50, 170 padx,pady = 30, 30 cposx,cposy = 120, 170 rposx, rposy = 190,170
buttons = {up = 16, down = 32, left = 64, right = 128, a=1, b=2, select=4, start=8} 
buttonpos = {up = {dpadx, dpady-pady},  down = {dpadx,dpady + pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, select={cposx, cposy}, start={cposx+padx,cposy}, b={rposx,rposy},a={rposx+padx,rposy}}
for i,j in pairs(buttons) do 
 manager.machine.screens[":screen"]:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,
 0x88ffffff, iifnot0(manager.machine.ioport.ports[":ctrl1:joypad:JOYPAD"]:read() & buttons[i], 0x88ff0000, 0x88000000)) 
 manager.machine.screens[":screen"]:draw_text(buttonpos[i][1]+2,buttonpos[i][2]+4,i)
end
end
emu.register_frame_done(drawoverlay)


You can paste it in on the lua console or save it to a file and dofile("myfile.lua")

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
Here's a layout file for nes, put it in a file called artwork/nes1/nes1.lay and then use "-override_artwork nes1"


Code


<mamelayout version="2">
	<element name="button">
		<rect state="1"><color alpha="0.5" red="1.0" green="0" blue="0"/></rect>
		<rect state="0"><color alpha="0.5" red="0" green="0" blue="0"/></rect>
	</element>


	<view name="Controllers Overlay">
		<screen index="0">
			<bounds x="0" y="0" width="256" height="240" />
		</screen>

<!-- a -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x1">
		<bounds x="220" y="170" width="20" height="20"/>
		</element>
<!-- b -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x2">
		<bounds x="190" y="170" width="20" height="20"/>
		</element>


<!-- select -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x4">
		<bounds x="120" y="170" width="20" height="20"/>
		</element>

<!-- start -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x8">
		<bounds x="150" y="170" width="20" height="20"/>
		</element>

<!-- up -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x10">
		<bounds x="50" y="140" width="20" height="20"/>
		</element>
<!-- down -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x20">
		<bounds x="50" y="200" width="20" height="20"/>
		</element>

<!-- left -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x40">
		<bounds x="20" y="170" width="20" height="20"/>
		</element>

<!-- right -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x80">
		<bounds x="80" y="170" width="20" height="20"/>
		</element>

	</view>
</mamelayout>



3 members like this: ICEknight, robcfg, R. Belmont
Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
For fun, I thought I'd add the ability to move the overlay up and down with keypad 2 and 8, adjust the alpha with keypad 4 and 6, and turn the overlay off and on with [ and ]

Code
function iifnot0(a,b,c) if a~=0 then return b else return c end end

displayoverlay=true
originx,originy=50,170
alphavalue=0.5

function drawoverlay()
dpadx,dpady = 50,originy padx,pady = 30,30 cposx,cposy = 120,originy rposx, rposy = 190,originy
buttons = {up = 16, down = 32, left = 64, right = 128, a=1, b=2, select=4, start=8} 
buttonpos = {up = {dpadx, dpady-pady},  down = {dpadx,dpady + pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, select={cposx, cposy}, start={cposx+padx,cposy}, b={rposx,rposy},a={rposx+padx,rposy}}
if displayoverlay==true then
for i,j in pairs(buttons) do 
 manager.machine.screens[":screen"]:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,
   0x00ffffff | math.floor(alphavalue*255)<<24, 
   iifnot0(manager.machine.ioport.ports[":ctrl1:joypad:JOYPAD"]:read() & buttons[i], 
     0x00ff0000 | math.floor(alphavalue*255)<<24, 
     0x00000000 | math.floor(alphavalue*255)<<24))
 manager.machine.screens[":screen"]:draw_text(buttonpos[i][1]+2, buttonpos[i][2]+4, i,
     0xffffff | math.floor(alphavalue*255)<<24)
end
end
input=manager.machine.input
if input:code_pressed(input:code_from_token("KEYCODE_OPENBRACE")) then displayoverlay = false end
if input:code_pressed(input:code_from_token("KEYCODE_CLOSEBRACE")) then displayoverlay = true end
if input:code_pressed(input:code_from_token("KEYCODE_8PAD")) then originy = originy - 1 end
if input:code_pressed(input:code_from_token("KEYCODE_2PAD")) then originy = originy + 1 end
if input:code_pressed(input:code_from_token("KEYCODE_4PAD")) then alphavalue = alphavalue-0.01 if alphavalue<0 then alphavalue=0 end end
if input:code_pressed(input:code_from_token("KEYCODE_6PAD")) then alphavalue = alphavalue+0.01 if alphavalue>1.0 then alphavalue=1.0 end end
end

emu.register_frame_done(drawoverlay)



1 member likes this: RomKnight
Joined: May 2009
Posts: 2,208
Likes: 355
J
Very Senior Member
OP Offline
Very Senior Member
J
Joined: May 2009
Posts: 2,208
Likes: 355
By the way, I do apologize for not having had a chance to dig into this. My weekend was topsy-turvy schedule-wise, and this week I just don't have much spare time. I'll get onto this this coming weekend.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
If it helps, I added a framecounter display on the layout.

Interestingly, it seems to use up all the textures if you set the maxstate of the counter to something like 999999.
If I omit the maxstate, it will "wrap" the counter at 2048.

FRAME:2045
Searching font Liberation Sans in -. path/s
Matching font: 0x55578a018070
FRAME:2046
Searching font Liberation Sans in -. path/s
Matching font: 0x55578a957cf0
FRAME:2047
Searching font Liberation Sans in -. path/s
Matching font: 0x55578a983500
FRAME:2048
FRAME:2049
FRAME:2050

and if I set the maxstate to "99999" then it will count up to 4523 and fatal error
FRAME:4522
Searching font Liberation Sans in -. path/s
Matching font: 0x55c577436580
FRAME:4523
Searching font Liberation Sans in -. path/s
Matching font: 0x55c5774f96f0
Ignoring MAME exception: renderer_ogl::texture_create: texture hash exhausted ...
Fatal error: renderer_ogl::texture_create: texture hash exhausted ...
Average speed: 99.42% (74 seconds)


Code

<mamelayout version="2">
	<element name="button">
		<rect state="1"><color alpha="0.5" red="1.0" green="0.0" blue="0.0"/></rect>
		<rect state="0"><color alpha="0.5" red="0.0" green="0.0" blue="0.0"/></rect>
	</element>


<group name="controller">

<!-- a -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x1">
		<bounds x="220" y="170" width="20" height="20"/>
		</element>
<!-- b -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x2">
		<bounds x="190" y="170" width="20" height="20"/>
		</element>


<!-- select -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x4">
		<bounds x="120" y="170" width="20" height="20"/>
		</element>

<!-- start -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x8">
		<bounds x="150" y="170" width="20" height="20"/>
		</element>

<!-- up -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x10">
		<bounds x="50" y="140" width="20" height="20"/>
		</element>
<!-- down -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x20">
		<bounds x="50" y="200" width="20" height="20"/>
		</element>

<!-- left -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x40">
		<bounds x="20" y="170" width="20" height="20"/>
		</element>

<!-- right -->
		<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="0x80">
		<bounds x="80" y="170" width="20" height="20"/>
		</element>

</group>

	<element name="framecount"><simplecounter align="2" /></element>

	<view name="Controllers Overlay">
		<screen index="0">
			<bounds x="0" y="0" width="256" height="240" />
		</screen>
		<group ref="controller">
		</group>
		<element ref="framecount" id="framecount">
	  		<bounds x="0" y="0" width="50" height="10"/>
		</element>
	</view>
	
	
	
	
	
	
	
	
<script><![CDATA[

-- file is the layout file object

print("LAYOUT LOADED  file.device.name = "..file.device.name)
print("LAYOUT LOADED  file.device.shortname = "..file.device.shortname)
print("LAYOUT LOADED  file.device.tag = = "..file.device.tag)


file:set_resolve_tags_callback(
	function ()

file.views["Controllers Overlay"].items["framecount"]:set_element_state_callback(
		function () 
		--print("FRAME:"..machine.screens[":screen"]:frame_number())
		return machine.screens[":screen"]:frame_number()
		end)

end)

]]></script>
	
	

</mamelayout>

Last edited by Golden Child; 11/01/23 09:27 AM.
Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
And a framenumber on the lua script:

Code
function iifnot0(a,b,c) if a~=0 then return b else return c end end

displayoverlay=true
originx,originy=50,170
alphavalue=0.5

function drawoverlay()
dpadx,dpady = 50,originy padx,pady = 30,30 cposx,cposy = 120,originy rposx, rposy = 190,originy
buttons = {up = 16, down = 32, left = 64, right = 128, a=1, b=2, select=4, start=8} 
buttonpos = {up = {dpadx, dpady-pady},  down = {dpadx,dpady + pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, select={cposx, cposy}, start={cposx+padx,cposy}, b={rposx,rposy},a={rposx+padx,rposy}}
if displayoverlay==true then
for i,j in pairs(buttons) do 
 manager.machine.screens[":screen"]:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,
   0x00ffffff | math.floor(alphavalue*255)<<24, 
   iifnot0(manager.machine.ioport.ports[":ctrl1:joypad:JOYPAD"]:read() & buttons[i], 
     0x00ff0000 | math.floor(alphavalue*255)<<24, 
     0x00000000 | math.floor(alphavalue*255)<<24))
 manager.machine.screens[":screen"]:draw_text(buttonpos[i][1]+2, buttonpos[i][2]+4, i,
     0xffffff | math.floor(alphavalue*255)<<24)
end
framenum = manager.machine.screens[":screen"]:frame_number()
 manager.machine.screens[":screen"]:draw_text(5,5,"Frame Number: "..framenum,
     0xffffff | math.floor(alphavalue*255)<<24)
 manager.machine.screens[":screen"]:draw_text(5,5,"Frame Number: "..framenum.."   "..string.rep(" ",framenum % 10 * 2)..framenum % 10,
     0xffffff | math.floor(alphavalue*255)<<24)
end
input=manager.machine.input
if input:code_pressed(input:code_from_token("KEYCODE_OPENBRACE")) then displayoverlay = false end
if input:code_pressed(input:code_from_token("KEYCODE_CLOSEBRACE")) then displayoverlay = true end
if input:code_pressed(input:code_from_token("KEYCODE_8PAD")) then originy = originy - 1 end
if input:code_pressed(input:code_from_token("KEYCODE_2PAD")) then originy = originy + 1 end
if input:code_pressed(input:code_from_token("KEYCODE_4PAD")) then alphavalue = alphavalue-0.01 if alphavalue<0 then alphavalue=0 end end
if input:code_pressed(input:code_from_token("KEYCODE_6PAD")) then alphavalue = alphavalue+0.01 if alphavalue>1.0 then alphavalue=1.0 end end
end

emu.register_frame_done(drawoverlay)

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
[Linked Image from i.imgur.com]

layout version:

[Linked Image from i.imgur.com]

Last edited by Golden Child; 11/01/23 05:06 PM.
1 member likes this: ICEknight
Joined: Aug 2008
Posts: 24
R
Member
Offline
Member
R
Joined: Aug 2008
Posts: 24
I somehow integrate this to work with my 2 screen setup (1 is for the marquees).

I have to ask though, could there be a way to make this work with other systems? Gameboy, game gear, master system, megadrive, ...?

I'm sure there's no one size fits all but I'd like to see this as a feature, if at all possible, at some point because it's really cool.

Anyway, thanks and thanks to the whole team as well.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
It should be possible to do this for any system because the input system works in the same way.

so for instance, looking at genesis, to get the list of ports:

function printt(t) for i,j in pairs(t) do print (i,j) end end
printt(manager.machine.ioport.ports)

:RESET sol.ioport_port*: 0x564f7ec6e7d8
:ctrl1:mdpad:PAD sol.ioport_port*: 0x564f7ec202c8
:ctrl2:mdpad:PAD sol.ioport_port*: 0x564f7ecfc988

then get the fields:

printt(manager.machine.ioport.ports[":ctrl1:mdpad:PAD"].fields)
P1 B sol.ioport_field*: 0x564f7ec3fff8
%p B sol.ioport_field*: 0x564f7ec46198
%p A sol.ioport_field*: 0x564f7ec56848
P1 Right sol.ioport_field*: 0x564f7ec2b2b8
P1 Up sol.ioport_field*: 0x564f7ecfc988
P1 A sol.ioport_field*: 0x564f7ec202c8
P1 Start sol.ioport_field*: 0x564f7ec41338
%p C sol.ioport_field*: 0x564f7ec567f8
P1 C sol.ioport_field*: 0x564f7ec5a1d8
P1 Down sol.ioport_field*: 0x564f7f703e88
P1 Left sol.ioport_field*: 0x564f7ec60e08


and then look at the mask:

for i,j in pairs(manager.machine.ioport.ports[":ctrl1:mdpad:PAD"].fields) do print(i, j.mask) end
P1 Down 2
P1 C 32
P1 Left 4
P1 Up 1
P1 B 16
%p A 64
%p C 32
%p B 16
P1 Start 128
P1 Right 8
P1 A 64

Last edited by Golden Child; 11/01/23 06:41 PM.
Joined: Aug 2008
Posts: 24
R
Member
Offline
Member
R
Joined: Aug 2008
Posts: 24
EDIT:
Corrected 1 problem, got another smile
Turns out it was a misplaced /n
No more errors but I can't see the text on the buttons, still.

/edit


I'm probably doing something stupid as it is my 1st time looking at LUA but I have trouble making this work for the genesis. I can see the layout but the boxes are not filled with the text. They change to red in the correct positions when I press the buttons too, so I'm assuming the pad is detected correctly.

The error is in line 13 on this .lua script

The error is: "attempt to index a nil value (field ':screen')" and line 13 would be "manager.machine.screens[":screen"]:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,"
For the sake of debug I removed the "manager.machine.screens[":screen"]" and then the error moves to draw_box

Quote
function iifnot0(a,b,c) if a~=0 then return b else return c end end

displayoverlay=true
originx,originy=50,170
alphavalue=0.5

function drawoverlay()
dpadx,dpady = 50,originy padx,pady = 30,30 cposx,cposy = 120,originy rposx,rposy = 190,originy
buttons = {up = 1, down = 2, left = 4, right = 8, b = 16, c = 32, a = 64, start = 128}
buttonpos = {up = {dpadx, dpady-pady}, down = {dpadx,dpady+pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, c={cposx, cposy}, start={cposx+padx, cposy}, b={rposx,rposy}, a={rposx+padx, rposy}}
if displayoverlay==true then
for i,j in pairs(buttons) do
manager.machine.screens[":screen"]:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,
0x00ffffff | math.floor(alphavalue*255)<<24,
iifnot0(manager.machine.ioport.ports[":ctrl1:mdpad:PAD"]:read() & buttons[i],
0x00ff0000 | math.floor(alphavalue*255)<<24,
0x00000000 | math.floor(alphavalue*255)<<24))
manager.machine.screens[":screen"]:draw_text(buttonpos[i][1]+2, buttonpos[i][2]+4, i,
0xffffff | math.floor(alphavalue*255)<<24)
end
end
input=manager.machine.input
if input:code_pressed(input:code_from_token("KEYCODE_OPENBRACE")) then displayoverlay = false end
if input:code_pressed(input:code_from_token("KEYCODE_CLOSEBRACE")) then displayoverlay = true end
if input:code_pressed(input:code_from_token("KEYCODE_8PAD")) then originy = originy - 1 end
if input:code_pressed(input:code_from_token("KEYCODE_2PAD")) then originy = originy + 1 end
if input:code_pressed(input:code_from_token("KEYCODE_4PAD")) then alphavalue = alphavalue-0.01 if alphavalue<0 then alphavalue=0 end end
if input:code_pressed(input:code_from_token("KEYCODE_6PAD")) then alphavalue = alphavalue+0.01 if alphavalue>1.0 then alphavalue=1.0 end end
end

emu.register_frame_done(drawoverlay)

So, if this is something quick and you have a spare 5m I'll like your help on this.
Thanks in advance.

Last edited by RomKnight; 11/02/23 01:35 PM.
Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
Each driver is free to name its screens differently, so in this case the screen is named ":megadriv"

Run a search and replace from ":screen" to ":megadriv" and it should work

function printt(t) for i,j in pairs(t) do print (i,j) end end printt(manager.machine.screens)
:megadriv sol.screen_device*: 0x557f97832d78


Code
function iifnot0(a,b,c) if a~=0 then return b else return c end end

displayoverlay=true
originx,originy=50,170
alphavalue=0.5

function calcalpha() return math.floor(alphavalue*255)<<24 end
function pressed(token) input=manager.machine.input return input:code_pressed(input:code_from_token(token)) end

function drawoverlay()
dpadx,dpady = 50,originy padx,pady = 30,30 cposx,cposy = 120,originy rposx,rposy = 190,originy
buttons = {up = 1, down = 2, left = 4, right = 8, b = 16, c = 32, a = 64, start = 128}
buttonpos = {up = {dpadx, dpady-pady}, down = {dpadx,dpady+pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, c={cposx, cposy}, start={cposx+padx, cposy}, b={rposx,rposy}, a={rposx+padx, rposy}}
if displayoverlay==true then
screenname = ":screen"
screenname = ":megadriv"
screen = manager.machine.screens[screenname]
for i,j in pairs(buttons) do
screen:draw_box(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20,
0x00ffffff | calcalpha(),
iifnot0(manager.machine.ioport.ports[":ctrl1:mdpad:PAD"]:read() & buttons[i],
0x00ff0000 | calcalpha(),
0x00000000 | calcalpha()))
screen:draw_text(buttonpos[i][1]+2, buttonpos[i][2]+4, i, 0xffffff | calcalpha())
end
end
if pressed("KEYCODE_OPENBRACE") then displayoverlay = false end
if pressed("KEYCODE_CLOSEBRACE") then displayoverlay = true end
if pressed("KEYCODE_8PAD") then originy = originy - 1 end
if pressed("KEYCODE_2PAD") then originy = originy + 1 end
if pressed("KEYCODE_4PAD") then alphavalue = alphavalue-0.01 if alphavalue<0 then alphavalue=0 end end
if pressed("KEYCODE_6PAD") then alphavalue = alphavalue+0.01 if alphavalue>1.0 then alphavalue=1.0 end end
end

emu.register_frame_done(drawoverlay)

Last edited by Golden Child; 11/02/23 04:02 PM.
Joined: Aug 2008
Posts: 24
R
Member
Offline
Member
R
Joined: Aug 2008
Posts: 24
Perfect.
Thanks for the time explaining it.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
For fun, I wanted to see if I could get lua to generate some xml. So this makes a list of elements from drawing boxes and text, then prints some xml.

Code
elementlist = {} 
 
function iifnot0(a,b,c) if a~=0 then return b else return c end end

function mydrawbox(x,y,x1,y1,portname,mask,bordercolor,inside1,inside0)
 manager.machine.screens[":screen"]:draw_box(x,y,x1,y1,bordercolor, iifnot0(manager.machine.ioport.ports[portname]:read() & mask, inside1, inside0))
table.insert(elementlist, {type="box",x=x,y=y,x1=x1,y1=y1,portname=portname,mask=mask,bordercolor=bordercolor,inside1=inside1,inside0=inside0})
 end
 
 
function mydrawtext(x,y,text,col)
manager.machine.screens[":screen"]:draw_text(x,y,text,col) 
table.insert(elementlist, {type="text",x=x,y=y,text=text,col=col})
end

function otag(t,attrs,inside) attrs=attrs or "" return "<"..t.." "..attrs..">\n" end -- open tag
function ctag(t) return "</"..t..">\n" end -- close tag
function tag(t,attrs,inside) attrs=attrs or "" inside = inside or "" return "<"..t.." "..attrs..">\n"..inside.."</"..t..">\n" end -- complete tag
function stag(t,attrs) attrs=attrs or "" return "<"..t.." "..attrs.."/>\n"end -- singleton tag
function attr(a,v) return a.."=\""..v.."\"".." " end  -- attribute


function makelayout()
print(otag("mamelayout",attr("version",2)))
print(tag("element",attr("name","button"),
tag("rect","",stag("color",attr("red",1.0)..attr("green",1.0)..attr("blue",1.0)))..
tag("rect",attr("state",1),stag("color",attr("red",1.0)..attr("green",0.0)..attr("blue",0.0))..
stag("bounds",attr("x",0.05)..attr("y",0.05)..attr("width",0.90)..attr("height",0.90)))..
tag("rect",attr("state",0),stag("color",attr("red",0.0)..attr("green",0.0)..attr("blue",0.0))..
stag("bounds",attr("x",0.05)..attr("y",0.05)..attr("width",0.90)..attr("height",0.90))) ))
for i,j in pairs(elementlist) do
if j.type=="text" then print(tag("element",attr("name","text"..j.text),stag("text",attr("string",j.text)))) end
end
print(otag("view",attr("name","Overlay")))
print([[<screen index="0">
<bounds x="0" y="0" width="256" height="240" />
</screen>]])
for i,j in pairs(elementlist) do
if j.type=="text" then print(tag("element",attr("ref","text"..j.text),stag("bounds",attr("top",j.y)..attr("left",j.x)..attr("bottom",j.y+10)..attr("right",j.x+4*j.text:len())))) end
if j.type=="box" then print(tag("element",attr("ref","button")..attr("inputtag",j.portname)..attr("inputmask",j.mask),stag("bounds",attr("top",j.y)..attr("left",j.x)..attr("bottom",j.y1)..attr("right",j.x1)))) end
end
print(ctag("view"))
print(ctag("mamelayout"))
end


function drawoverlay()
elementlist = {} 
dpadx,dpady = 50, 170 padx,pady = 30, 30 cposx,cposy = 120, 170 rposx, rposy = 190,170
buttons = {up = 16, down = 32, left = 64, right = 128, a=1, b=2, select=4, start=8} 
buttonpos = {up = {dpadx, dpady-pady},  down = {dpadx,dpady + pady}, right = {dpadx+padx, dpady}, left={dpadx-padx, dpady}, select={cposx, cposy}, start={cposx+padx,cposy}, b={rposx,rposy},a={rposx+padx,rposy}}
for i,j in pairs(buttons) do 
 mydrawbox(buttonpos[i][1],buttonpos[i][2],buttonpos[i][1]+20,buttonpos[i][2]+20, 
 ":ctrl1:joypad:JOYPAD",buttons[i], 0x88ffffff, 0x88ff0000, 0x88000000) 
mydrawtext(buttonpos[i][1]+2,buttonpos[i][2]+4,i,0x88ffffff)
end
end

emu.register_frame_done(drawoverlay)

makelayout()


and the xml it generates:

Code
<mamelayout version="2" >

<element name="button" >
<rect >
<color red="1.0" green="1.0" blue="1.0" />
</rect>
<rect state="1" >
<color red="1.0" green="0.0" blue="0.0" />
<bounds x="0.05" y="0.05" width="0.9" height="0.9" />
</rect>
<rect state="0" >
<color red="0.0" green="0.0" blue="0.0" />
<bounds x="0.05" y="0.05" width="0.9" height="0.9" />
</rect>
</element>

<element name="textright" >
<text string="right" />
</element>

<element name="textup" >
<text string="up" />
</element>

<element name="texta" >
<text string="a" />
</element>

<element name="textdown" >
<text string="down" />
</element>

<element name="textleft" >
<text string="left" />
</element>

<element name="textb" >
<text string="b" />
</element>

<element name="textstart" >
<text string="start" />
</element>

<element name="textselect" >
<text string="select" />
</element>

<view name="Overlay" >

<screen index="0">
<bounds x="0" y="0" width="256" height="240" />
</screen>
<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="128" >
<bounds top="170" left="80" bottom="190" right="100" />
</element>

<element ref="textright" >
<bounds top="174" left="82" bottom="184" right="102" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="16" >
<bounds top="140" left="50" bottom="160" right="70" />
</element>

<element ref="textup" >
<bounds top="144" left="52" bottom="154" right="60" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="1" >
<bounds top="170" left="220" bottom="190" right="240" />
</element>

<element ref="texta" >
<bounds top="174" left="222" bottom="184" right="226" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="32" >
<bounds top="200" left="50" bottom="220" right="70" />
</element>

<element ref="textdown" >
<bounds top="204" left="52" bottom="214" right="68" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="64" >
<bounds top="170" left="20" bottom="190" right="40" />
</element>

<element ref="textleft" >
<bounds top="174" left="22" bottom="184" right="38" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="2" >
<bounds top="170" left="190" bottom="190" right="210" />
</element>

<element ref="textb" >
<bounds top="174" left="192" bottom="184" right="196" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="8" >
<bounds top="170" left="150" bottom="190" right="170" />
</element>

<element ref="textstart" >
<bounds top="174" left="152" bottom="184" right="172" />
</element>

<element ref="button" inputtag=":ctrl1:joypad:JOYPAD" inputmask="4" >
<bounds top="170" left="120" bottom="190" right="140" />
</element>

<element ref="textselect" >
<bounds top="174" left="122" bottom="184" right="146" />
</element>

</view>

</mamelayout>



[Linked Image from i.imgur.com]

2 members like this: u-man, robcfg
Joined: Aug 2008
Posts: 24
R
Member
Offline
Member
R
Joined: Aug 2008
Posts: 24
This is cool and useful.
thanks.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
I had an idea of having a set of "macro buttons" that you could click on to help you control a system.

For example, on the apple II you could have a button that would do "CTRL+RESET" or would type a system command like "CATALOG" or "CALL -151".

This would be useful for helping navigate unfamiliar systems or to type unusual commands.

For proof of concept, I wanted to make clickable buttons on a layout, which means adding an input port.


So taking the apple2e driver, I added a dummy input port "keyb_dummy"


Code
static INPUT_PORTS_START( apple2e_common )

	PORT_START("keyb_dummy")
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY0")
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY1")
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY2")
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY3")
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY4")
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY5")
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY6")
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY7")
	PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY8")
	PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DUMMY9")


...
		m_kbspecial(*this, "keyb_special"),
		m_kbdummy(*this, "keyb_dummy"),
		m_sysconfig(*this, "a2_config"),
...
	required_ioport m_kbspecial;
	required_ioport m_kbdummy;
	optional_ioport m_sysconfig;

...


so now I've got some dummy buttons I can hook up to a layout.


So now I can make a layout file:

Taking my layout file from the nes and hacking up on it:


Code
<mamelayout version="2" >

<element name="button" >
<rect >
<color red="1.0" green="1.0" blue="1.0" />
</rect>
<rect state="1" >
<color red="1.0" green="0.0" blue="0.0" />
<bounds x="0.05" y="0.05" width="0.9" height="0.9" />
</rect>
<rect state="0" >
<color red="0.0" green="0.0" blue="0.0" />
<bounds x="0.05" y="0.05" width="0.9" height="0.9" />
</rect>
</element>

<element name="textreset" >
<text string="Reset" />
</element>

<element name="textctrl" >
<text string="Control" />
</element>

<element name="textctrlreset" >
<text string="Control-Reset" />
</element>

<element name="textctrlcenter" >
<text string="^C + CR" />
</element>

<element name="textcall151" >
<text string="CALL -151" />
</element>


<group name="buttons">
<element ref="button" inputtag=":keyb_special" inputmask="8" >
<bounds top="170" left="20" bottom="190" right="40" />
</element>

<element ref="textctrl" >
<bounds top="174" left="22" bottom="184" right="38" />
</element>

<element ref="button" inputtag=":keyb_dummy" inputmask="2" >
<bounds top="170" left="160" bottom="190" right="190" />
</element>

<element ref="textctrlcenter" >
<bounds top="174" left="162" bottom="184" right="182" />
</element>

<element ref="button" inputtag=":keyb_dummy" inputmask="4" >
<bounds top="170" left="120" bottom="190" right="150" />
</element>

<element ref="textctrlreset" >
<bounds top="174" left="122" bottom="184" right="146" />
</element>

<element ref="button" inputtag=":keyb_dummy" inputmask="8" >
<bounds top="170" left="210" bottom="190" right="240" />
</element>

<element ref="textcall151" >
<bounds top="174" left="212" bottom="184" right="236" />
</element>

<element ref="button" inputtag=":keyb_special" inputmask="128" >
<bounds top="170" left="80" bottom="190" right="100" />
</element>

<element ref="textreset" >
<bounds top="174" left="82" bottom="184" right="102" />
</element>


</group>
<view name="Helper" >
<screen index="0">
<bounds x="0" y="0" width="280" height="240" />
</screen>
<group ref="buttons">
<bounds left="-160" right="0" top="0" bottom="20"/>
</group>
</view>

</mamelayout>


and a lua script (executed with dofile) that simply watches the dummy port and executes a command based on the port being pressed.

Code
function press(port,field)
  manager.machine.ioport.ports[port].fields[field]:set_value(1)
end

function release(port,field)
  manager.machine.ioport.ports[port].fields[field]:clear_value()
end
  


function do_reset()
  press(":keyb_special","Control")
  press(":keyb_special","RESET")
  emu.wait(2/60)
  release(":keyb_special","RESET")
  release(":keyb_special","Control")
  emu.wait(1/60)
end


function do_ctrlc()
  press(":keyb_special","Control")
  press(":X3","C  c") -- was aborting because it was looking for "c"
  emu.wait(2/60)
  release(":X3","C  c")
  emu.wait(1/60)
  release(":keyb_special","Control")
  emu.wait(1/60)
  press(":X6","Return")  -- not in X5 it's in X6!!!
  emu.wait(1/60)
  release(":X6","Return")
   emu.wait(1/60)
end





function check_dummy()
  if lastdummyread == nil then lastdummyread=0 end
  dummyread = manager.machine.ioport.ports[":keyb_dummy"]:read()
  if dummyread ~= 0 and lastdummyread==0 then
    if dummyread & 4 ~= 0 then
       co1=coroutine.create(do_reset) coroutine.resume(co1)
    end
    if dummyread & 2 ~= 0 then
       co1=coroutine.create(do_ctrlc) coroutine.resume(co1)
    end
  end
  lastdummyread = dummyread
end


emu.register_frame_done(check_dummy)



It's kind of primitive, but it works.

[Linked Image from i.imgur.com]

Joined: May 1999
Posts: 615
Likes: 1
Senior Member
Offline
Senior Member
Joined: May 1999
Posts: 615
Likes: 1
Interesting, Golden Child, but for this to work I have to modify the source code, if I understand it correctly, right?

Joined: Mar 2001
Posts: 17,181
Likes: 211
R
Very Senior Member
Offline
Very Senior Member
R
Joined: Mar 2001
Posts: 17,181
Likes: 211
Right, that's a source mod. The Franklin clones have F1-F12 keys that are programmable macros but the emulation isn't 100% correct.

Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
Yes, the modifications are to have a "dummy" input port so that you can click on a layout button.

Theoretically, you could make as many dummy ports and fields as you would like.

The layout element is connected to the port with an inputtag and inputmask.

It's primitive, but there's all kinds of interesting things you could do like loading/switching floppies, etc.

Video of it in action (it's super exciting, I know)



The dummy ports aren't connected to the keyboard, but you can activate them with the keyboard using the inputmacro plugin:

[Linked Image from i.imgur.com]

Last edited by Golden Child; 11/11/23 04:16 PM.
Joined: Feb 2014
Posts: 1,080
Likes: 155
G
Very Senior Member
Offline
Very Senior Member
G
Joined: Feb 2014
Posts: 1,080
Likes: 155
I never knew about the function keys on the Franklin Ace 500/2x00. That's really cool. I wish that I'd had one of those back in the day just for that feature.

Perusing the code, I made a few modifications and the function keys seem to work, (at least on initial testing, not extensively tested though).

I think the problem is that it hits the strobe when you press the key AND when you release the key and there's no key down so it returns 0 and basically types the @ symbol.

Code
		// check Franklin F-keys
		if ((m_isace500) || (m_isace2200))
		{
			const u32 uFkeys = m_franklin_fkeys->read();

			if ((uFkeys ^ m_franklin_last_fkeys) && uFkeys)
			{
				m_transchar = count_leading_zeros_32(uFkeys) + 0x20;
				m_strobe = 0x80;
				m_franklin_strobe = 0;
			}
			m_franklin_last_fkeys = uFkeys;
		}
	}


So Franklin basic has a special command called FKEY
and you can redefine the function keys with FKEY [num],[string]

for example:

FKEY 1,"DUDE"
FKEY 2,"LIST"+CHR$(13)


Seems to work better on the Ace 2200 diagnostic disk keyboard test: (disk named Franklin Ace 2200 V1.0.dsk)

[Linked Image from i.imgur.com]

Last edited by Golden Child; 11/12/23 01:45 AM.
2 members like this: u-man, robcfg
Joined: Mar 2001
Posts: 17,181
Likes: 211
R
Very Senior Member
Offline
Very Senior Member
R
Joined: Mar 2001
Posts: 17,181
Likes: 211
Thanks, those two changes seem to make it work great!

Page 1 of 3 1 2 3

Link Copied to Clipboard
Who's Online Now
1 members (1 invisible), 43 guests, and 1 robot.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,310
Posts121,714
Members5,070
Most Online1,283
Dec 21st, 2022
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Forum hosted by www.retrogamesformac.com