Wow, you sure are going to a lot of trouble to make this work.
I'd propose instead that you consider opening up a discussion about how to handle outputs from MAME in a more generic fashion. I've been thinking about how to support outputs both in the artwork (for visual ones) and for external support. The idea is to enhance what is already present in the rendering system and use names for outputs, and have values that they can be set to. For on/off type things, it would be set to 1 or 0. For items with variable values (like lamps that can have different brightness values), it would be some number from 0..65535 or something.
For external support, it would be OSD dependent obviously. On Windows, I would probably do the simplest thing and register for a new event and then just broadcast that event each time the output changes (perhaps throttled to same maximum rate). An external program could just listen for that event and do what it needs to do in response.
The goal would be to remove the keyboard LED ---meadow muffin--- from MAME proper and just post outputs this way. Someone else could write a standalone program that replicated the keyboard LED behavior (would be simple to do) if that's what was desired, or those LEDs could be routed to proper LEDs. There would be generic names for these ("led1", "led2", etc.) so they are easily tracked.
For Q*Bert, you'd just need to pick some name (like "knocker") and listen for the event that sets the "knocker" value to 1, and trigger your external item there.
Does this seem reasonable? It would also help MAME better document outputs in general. Right now, it doesn't do a good job because there is no common routines to call within MAME to signal the value of an output, so most of the outputs are just left dangling.
Well I didn't know you were willing to add it. I can throw around ideas for you guys, but I'm not good enough with the mame source to actually make a universal function. Of course I've noticed that with the recent changes the source is almost read-able.

I have a few thoughts:
There's the "do it right" method and the "do it now" method from where I'm thinking.
The "do it now" is fairly easy. All ports of mame have a caption right? Well just tack the light status onto the caption of the window and let the people writing output interfaces deal with the rest.
So MAME: Gorf[gorf] would become
MAME: Gorf[gorf] outp:0,0,0,0,0,0
or possibly
MAME: Gorf[gorf] outp:0 with the values 1-6 representing the six lights and 0 being off.
"Dangerous" outputs, like knockers could even be given a different heading like MAME: Q*Bert[qbert] sol:0
Getting a caption from mame is really easy because it has the window class of "MAME" so just have an app read the caption periodically and you are done. This might have benefits over an event message in that you could use the same code regardless of the os port. Of course it'll probably be slower.
It would be easier to code on the mame end because it wouldn't matter what type of output it is or even what format it's in. For that matter, set_led_status could simply be replaced/rerouted to set_caption_status.
If course this isn't the most documentation friendly solution I'm sure but if the hassle is in the coding, it's an option.
Another way to do it would just be to do the ctrlr files in reverse and have them bind to output ports (which from my understanding would just be memory addresses just like input ports defined in a driver, just read instead of write) the same way. Then you could use the event handling method, exactly as you described. The key would be to modify listxml (yet again) to output all possible output names so external programs aren't in the dark on what they are supposed to be looking for.
I think we can all agree that aside from maybe controlling the keyboard leds directly the actual app/dll/ect to control the device needs to be externalized. There are just too many options on how to output data from a computer and to say "this device and this method is supported, but this one isn't" would merely limit outputs again. People wanting to do something insaine like mame a galaxy force cab, wouldn't be able to unless there was a method presented that would allow them to do whatever they want with the data, not just fire it through the parallel port or turn on some ledwiz outputs.
Constants shouldn't be hard if that's the route you wish to go:
Start1-Start6 for games like digdug that blink the volcano buttons.
Coin1-Coin6 for games that flash the coin door lights.
Rank1-10 for games with rank lights.
Light1-60 (purposefully really huge amount) for misc lights
Solenoid1-10 for knockers, blowers, ect... anything that could be damaged (or annoying) if it were left on for more than a second.
Analog1-60 for anything like linear actuators, hydraulics, ect.
Digital1-60
And possibly a constant for stuff that is known to do something, but nobody knows how it does it.
like
Raw1-60
Raw could be used initially and as more about the data is learned, it can be split out into individual outputs.
You might want to get a little fancy too. You've got games like turbo that have digit displays. You could make a output for each individual line segment, or even each individual digit but it might make more sense to have text constants, where the event just sends the score.
Of course you have the mahjong pron games with the lcd screens. You could probably do something with that too, I just don't know why you would want to

The only issue I see with this is if you are going for accuracy, the only constant you really need is raw in most cases. Gorf for example is just an 8bit array, not different addresses for each light. On the machine I guess there's a chip that slipts out all this data into the 8 output signals (yes I said 8, have no clue what the other two do but there are even pins and relays on the light board for it). A function would have to be made for every single game with outputs that splits the data into chunks the output function can use (similar to how it's done in the artwork code now). We'e got a lot of games like afterburner, where we sorta know where the data is but don't have a clue what it does or how it does it.
Just random thoughts.
Level42, sorry for hijacking here. I'm still more than willing to make you a little app just for qbert. The thing is my proggie was going to be a universal solution and you brought up qbert so I mentioned it.
Budda.. can you send me specs on your parallel interface (forgot to ask, sorry)? I'm trying to get j5 to support frikkin everything and I'd like to add code for it.