Main Restorations Software Audio/Jukebox/MP3 Everything Else Buy/Sell/Trade
Project Announcements Monitor/Video GroovyMAME Merit/JVL Touchscreen Meet Up Retail Vendors
Driving & Racing Woodworking Software Support Forums Consoles Project Arcade Reviews
Automated Projects Artwork Frontend Support Forums Pinball Forum Discussion Old Boards
Raspberry Pi & Dev Board controls.dat Linux Miscellaneous Arcade Wiki Discussion Old Archives
Lightguns Arcade1Up Try the site in https mode Site News

Unread posts | New Replies | Recent posts | Rules | Chatroom | Wiki | File Repository | RSS | Submit news

  

Author Topic: Communicating with MAME  (Read 6738 times)

0 Members and 1 Guest are viewing this topic.

headkaze

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 2943
  • Last login:August 14, 2023, 02:00:48 am
  • 0x2b|~0x2b?
Communicating with MAME
« on: June 27, 2011, 11:09:25 pm »
This post is to document ways of communicating with MAME. Since MAME has a built in method for sending data to external applications this article will concentrate on ways of sending data to MAME. For info on receiving data from MAME check out my MAMEInterop SDK 1.1 and it's page on BYOAC here. It includes a Mame.dll that simplifies communication and includes sample code in C#, VB.NET, C++, Delphi and VB6.

The first method to send data to MAME is to use MAME's own output system's window to receive data. This seems like the most obvious choice since MAME already communicates to external apps this way albeit one-way.

The files of interest are src/osd/windows/output.c and src/osd/windows/output.h. The following example will modify MAME to receive a custom message for pausing and unpausing. You can view the full diff @ bezel_0129u2.zip although it is for a relatively old version of MAME.

First of all let's check out output.h. You will notice MAME has some output messages defined.

Code: [Select]
#define OM_MAME_START TEXT("MAMEOutputStart")
#define OM_MAME_STOP TEXT("MAMEOutputStop")
#define OM_MAME_UPDATE_STATE TEXT("MAMEOutputUpdateState")
#define OM_MAME_REGISTER_CLIENT TEXT("MAMEOutputRegister")
#define OM_MAME_UNREGISTER_CLIENT TEXT("MAMEOutputUnregister")
#define OM_MAME_GET_ID_STRING TEXT("MAMEOutputGetIDString")

These are all the custom messages that can be sent to other applications. These messages are registered using the Win32 API call RegisterWindowMessage(). Both the sending and receiving applications need to register these in order to communicate. So let's add our own custom message.

Code: [Select]
// IM_MAME_PAUSE: when received will pause mame.
//      LPARAM = State, 1=Pause, 0=UnPause
#define IM_MAME_PAUSE TEXT("MAMEInputPause")

Here is our custom IM_MAME_PAUSE message and we will use lParam to tell it to pause or unpause.

Now let's take a look at output.c where we will need to add code to register our message.

First of all we need a variable to storing the message id

Code: [Select]
static UINT im_mame_pause;
Then we need to register our message just as the input messages are registered

Code: [Select]
// HK: Add our pause input message
im_mame_pause = RegisterWindowMessage(IM_MAME_PAUSE);
assert(im_mame_pause != 0);

To send this custom message we need to register the same message and then we use PostMessage() to MAME's output window. It will look like this

Code: [Select]
PostMessage(hWnd, im_mame_pause, null, pauseState);
Now we need to add some more code to output.c to receive and process the message.

output_window_proc is MAME's Output Window's WndProc function. Here we will add code to process the pause message

Code: [Select]
// HK: Pause message received
if (message == im_mame_pause)
mame_pause(machine, lparam);

Remember we use the lParam parameter to tell MAME to pause or unpause. lParam is the last parameter of the PostMessage() Win32 API call.

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

NOTE: This is by no means the easiest way to pause MAME from an external application. I've found a much easier way by sending a built in message to MAME's main window instead of it's output window. Using this method requires no modification to MAME's source code.

Code: [Select]
PostMessage(hWnd, WM_USER_UI_TEMP_PAUSE, 1, null); // Pause MAME
PostMessage(hWnd, WM_USER_UI_TEMP_PAUSE, 0, null); // UnPause MAME

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

Which brings me to one more method for sending messages to MAME and that is it's main game window. You can use the Win32 API FindWindow() with the class name of "MAME" to find it. MAME can have multiple windows so I actually recommend using EnumWindows() and do a match for the window name starting with "MAME:" and the class name "MAME". Note that MAME's window title will have "MAME: [ROM_NAME]" so you cannot do an exact match of the window's title using FindWindow() only it's class "MAME". Using EnumWindows() you can do a partial match of "MAME:" and then you can even grab the ROM name from it.

Let's look at MAME's main WndProc function located in src\osd\windows\window.c

The function is called winwindow_video_window_proc. As with our previous method instead of sending messages to MAME's output window we send them directly to MAME using PostMessage() and process them in it's WinProc. We can simply use WM_USER + a custom offset. This is commonly used for custom messages.

Eg.
Code: [Select]
#define WM_USER_MY_CUSTOM_MESSAGE (WM_USER + 8)
Since MAME already uses custom messages we should make sure ours doesn't interfere with MAME's. MAME has the following custom messages defined.

Code: [Select]
#define WM_USER_FINISH_CREATE_WINDOW (WM_USER + 0)
#define WM_USER_SELF_TERMINATE (WM_USER + 1)
#define WM_USER_REDRAW (WM_USER + 2)
#define WM_USER_SET_FULLSCREEN (WM_USER + 3)
#define WM_USER_SET_MAXSIZE (WM_USER + 4)
#define WM_USER_SET_MINSIZE (WM_USER + 5)
#define WM_USER_UI_TEMP_PAUSE (WM_USER + 6)
#define WM_USER_EXEC_FUNC (WM_USER + 7)

So we can simply start our custom messages at (WM_USER + 8 ). Then all we do is add our code to process the message in winwindow_video_window_proc.

Code: [Select]
case WM_USER_MY_CUSTOM_MESSAGE:
{
// Process wParam and/or lParam
break;
}

Now you can just use PostMessage() to send MAME the message and use the wParam and/or lParam as custom parameters.

Code: [Select]
PostMessage(hWnd, WM_USER_MY_CUSTOM_MESSAGE, wParam, lParam);
« Last Edit: June 27, 2011, 11:12:10 pm by headkaze »

drventure

  • Trade Count: (+2)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 4152
  • Last login:April 23, 2024, 06:53:06 pm
  • Laser Death Ray Bargain Bin! Make me an offer!
Re: Communicating with MAME
« Reply #1 on: June 27, 2011, 11:43:12 pm »
Nice post and interesting stuff, but when would you typically send inputs into mame?

I can see the pause scenario, and maybe coin drop... but what else? Inputs from some esoteric types of controls maybe?

headkaze

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 2943
  • Last login:August 14, 2023, 02:00:48 am
  • 0x2b|~0x2b?
Re: Communicating with MAME
« Reply #2 on: June 27, 2011, 11:59:48 pm »
Nice post and interesting stuff, but when would you typically send inputs into mame?

I can see the pause scenario, and maybe coin drop... but what else? Inputs from some esoteric types of controls maybe?

Howard wanted to know methods of sending data to MAME for a force feedback project he's working on so I thought rather than PM him i'd post it here for everyone.

There are probably not alot of reasons to need to do it otherwise!

drventure

  • Trade Count: (+2)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 4152
  • Last login:April 23, 2024, 06:53:06 pm
  • Laser Death Ray Bargain Bin! Make me an offer!
Re: Communicating with MAME
« Reply #3 on: June 28, 2011, 12:08:26 am »
Ah. Cool. I was scratching my head as to other possibilities there.

Howard_Casto

  • Idiot Police
  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 19427
  • Last login:Yesterday at 04:15:56 pm
  • Your Post's Soul is MINE!!! .......Again??
    • The Dragon King
Re: Communicating with MAME
« Reply #4 on: June 28, 2011, 12:22:38 am »
Thanks, this should help.  The problem I'm seeing though is it's doubtful that the mame devs will allow me to insert a custom message specifically for inserting keystrokes.  I'll have to see what is already in there. 

Howard_Casto

  • Idiot Police
  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 19427
  • Last login:Yesterday at 04:15:56 pm
  • Your Post's Soul is MINE!!! .......Again??
    • The Dragon King
Re: Communicating with MAME
« Reply #5 on: June 28, 2011, 12:37:01 am »
Ah. Cool. I was scratching my head as to other possibilities there.

Just for clarification, many "force feedback" games in mame, especially sega games have regular microswitch limit switches to determine wheel/motor position.  This is all well and good but modern pc force feedback hardware lacks such limit switches and relies on the wheels/joysticks analog value to determine position.  Since the mame dev's would'nt appreciate me doing a colossal hack job I have hooked up the limit switches in mame as regular digital inputs (as they should be) but mamehooker will then have to translate the read position of the wheel/joystick into on/off values for the various limit switches.  

This is less for gameplay (most games will continue to feed force feedback data even if the startup test fails) and more for completeness.  Booting up outrun, having it do it's startup procedure once and then booting the game is much better than having it try and fail the startup 4 times, taking several seconds to boot.  Thus the need to send some data to mame.  

I'm just going over my options atm and trying to get all the fiddly ducks in a row before I make the submission.  This will be the first "true" force feedback output implementation in a mame driver, so I need to get it just right as it will be the prototype.
« Last Edit: June 28, 2011, 12:39:29 am by Howard_Casto »

headkaze

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 2943
  • Last login:August 14, 2023, 02:00:48 am
  • 0x2b|~0x2b?
Re: Communicating with MAME
« Reply #6 on: June 28, 2011, 12:50:03 am »
There are 3 ways to inject input into MAME

Method 1: You can compile it to use the DirectInput API by modifying src\osd\windows\input.c:

Code: [Select]
// For testing purposes: force DirectInput
#define FORCE_DIRECTINPUT       1

And then use the standard SendInput() API function.

Method 2: You can use my InputHook32.dll / InputHook64.dll's to attach the MAME process and hijack it's calls to the raw input API functions and inject keys into them directly by sending a fake WM_INPUT message. This would be considered "hacky" and may be problematic on Windows 7 machines although I haven't tried it yet. Also you need to use the 32 or 64 bit dll depending on the bitness of the MAME executable you're attaching to, not to mention you need to know the name of MAME executable. In my example app I use .NET which can compile JIT in both 32 and 64 bit and then use the relevant native dll. You would have problems doing this from a VB6 application which is 32-bit only, so it wouldn't work for a 64-bit compiled MAME.

Method 3: Use my VJoy Virtual Joystick Drivers although the freeware version only allows you to convert keyboard input to joystick input. With the commercial SDK you can convert any type of data into joystick input. You can only send input to two virtual joysticks using the slider, X axis, Y axis, Z axis, Z rotation, pov and 16 buttons.

I'm not exactly sure what data you need to send to MAME though?

Howard_Casto

  • Idiot Police
  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 19427
  • Last login:Yesterday at 04:15:56 pm
  • Your Post's Soul is MINE!!! .......Again??
    • The Dragon King
Re: Communicating with MAME
« Reply #7 on: June 28, 2011, 02:32:24 am »
Well #1 and #2 are out.  I'm pretty firm on the point that anything mamehooker does, will work on any flavor of mame, no dlls, source changes or what have you.  If I hadn't then I would have added overlay support to mamehooker ages ago... fairly easy to do with a wrapper for the dx dlls.  Mh is' hackish enough by communicating to mame via the output window... no need to complicate things earlier. 

#3 is a definate possibility.  The only issue is see with it is windoze and mame's akward joystick enumeration.  It would be difficult to make sure that the real joystick and the virtual one don't get swapped around. 

The proper way to do it would be to implement more feedback messages in the output code.  But then what do I do with the data?  In order to trip those new inputs in the game a generic "message to keystroke/whatever" function is going to have to be implemented.  I don't think that is going to be allowed.  I think I need to get in contact with some of the main mame devs and start a discussion. 

Lots of things to worry about with some of the new things I'll be adding. 

While I'm on the racing game kick I might as well try to implement a better mame shifter as well.  720 was allowed and it actually has three input configurations now (selected via "driver configuration").  I don't see why, in addition to the current "toggle" shifter, games couldn't include a "hardware" version (if the button is held the shifter is in "hi" and "lo" when released, just like a pole-position shifter) and maybe a dedicated button version ("hi" and "lo" each get their own outputs).  The code to implement such options would be trivial. 

Howard_Casto

  • Idiot Police
  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 19427
  • Last login:Yesterday at 04:15:56 pm
  • Your Post's Soul is MINE!!! .......Again??
    • The Dragon King
Re: Communicating with MAME
« Reply #8 on: June 28, 2011, 02:34:22 am »
p.s.  How long has it been since you've tried the "pause" message?  It won't work for me and I'm following along with the source file to make sure I'm sending the right data.  All the other custom messages in mame work just fine, but pause doesn't.

headkaze

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 2943
  • Last login:August 14, 2023, 02:00:48 am
  • 0x2b|~0x2b?
Re: Communicating with MAME
« Reply #9 on: June 28, 2011, 05:33:35 am »
p.s.  How long has it been since you've tried the "pause" message?  It won't work for me and I'm following along with the source file to make sure I'm sending the right data.  All the other custom messages in mame work just fine, but pause doesn't.

Are you pressing the pause key defined in MAME when sending the message? That can cause problems.

Also note that MAME has multiple windows. There is the console window and the rendering window(s). Which one are you sending the message to?

If you still can't get it to work try sending WM_ENTERMENULOOP to pause and WM_EXITMENULOOP to unpause.

BadMouth

  • Trade Count: (+6)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 9270
  • Last login:Yesterday at 11:32:53 pm
  • ...
Re: Communicating with MAME
« Reply #10 on: June 28, 2011, 12:32:06 pm »
While I'm on the racing game kick I might as well try to implement a better mame shifter as well.  720 was allowed and it actually has three input configurations now (selected via "driver configuration").  I don't see why, in addition to the current "toggle" shifter, games couldn't include a "hardware" version (if the button is held the shifter is in "hi" and "lo" when released, just like a pole-position shifter) and maybe a dedicated button version ("hi" and "lo" each get their own outputs).  The code to implement such options would be trivial.  

I started a universal shifter discussion a while back hoping to attract someone with enough ability and interest to implement it.
It never really went anywhere and not everyone understood what I was going for, but you might find something useful in it.....
http://forum.arcadecontrols.com/index.php?topic=108566.0

If the shifter toggle hacks were accepted for the sake of useability, I don't see why fudging limit switches wouldn't.

Howard_Casto

  • Idiot Police
  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 19427
  • Last login:Yesterday at 04:15:56 pm
  • Your Post's Soul is MINE!!! .......Again??
    • The Dragon King
Re: Communicating with MAME
« Reply #11 on: June 28, 2011, 03:27:02 pm »
While I'm on the racing game kick I might as well try to implement a better mame shifter as well.  720 was allowed and it actually has three input configurations now (selected via "driver configuration").  I don't see why, in addition to the current "toggle" shifter, games couldn't include a "hardware" version (if the button is held the shifter is in "hi" and "lo" when released, just like a pole-position shifter) and maybe a dedicated button version ("hi" and "lo" each get their own outputs).  The code to implement such options would be trivial.  

I started a universal shifter discussion a while back hoping to attract someone with enough ability and interest to implement it.
It never really went anywhere and not everyone understood what I was going for, but you might find something useful in it.....
http://forum.arcadecontrols.com/index.php?topic=108566.0

If the shifter toggle hacks were accepted for the sake of useability, I don't see why fudging limit switches wouldn't.

I saw that discussion but I didn't want to get involved.... I won't name names, but two or three people in the discussion actually knew what they were talking about and the rest didn't.  "The rest" got in the way of the discussion. 

I think shifters would have to be handled on a case by case basis, just like they are now, BUT just like they are now, they could all be standardized, and standardized to offer more input options.  I think it's more a case of laziness than anything.  I can do a few just to show people how to do it and if accepted hopefully some others can pick up the slack and implement it on the hi/lo shifters at least.


As for the limit switches I definately don't want to fudge them any worse then they already are.  What I can do though is keep the original "fudge" as an option via driver configuration.  As I said, the limit switches thus far don't really effect gameplay or force feedback anyway, they just screw up the startup test.  I definately want the option to expose them though.  If a person has an outrun deluxe cab, the pcb dies and they want to hook it up to mame they should be able to!

Also something of note....
I was playing around with the logitech profiler software and it can send keystrokes to mame!  Mind you it's completely worthless for the problem at hand (it allows an axis to send analog data OR keystrokes, not both.) but that means that somehow mame can still get simulated keystroke data.  It might be that they've made a virtual keyboard or something, but it's worth looking into.  I think the profiler software is actually open-source.  I'll take a look. 

HK:

I checked the class as "MAME" and then checked the window title, so as far as I can tell it's the render window.  I actually used to use postmessage for mame on a lot of my more ancient apps... before they switched away from directinput.  ;)  I'll try the enter and exit loop commands though.  It doesn't matter, I was just playing around with it.  At this rate I'll never get to rebuild J5.  :(