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: Here I make a front end for windows 7 c#  (Read 4888 times)

0 Members and 1 Guest are viewing this topic.

whitebabylon

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 28
  • Last login:April 26, 2015, 12:10:26 am
  • I want to build my own arcade controls!
Here I make a front end for windows 7 c#
« on: October 10, 2014, 02:16:54 pm »
Greetings,
First time poster here. I thought I'd talk about my attempt to making my own front end.
I know there are lots of wonderful ones already, though I don't know how they work in terms of code, I am doing this for fun.
I am fairly new to the windows programming world, so if you see what I'm doing in this thread and realize it is just terrible, feel free to throw around some ideas.
After my front end, I really want to build an actual cabinet, though I have never touched a tool in my life - so I've been very back-and-forth about it.
Hopefully after the software is done I'll feel accomplished enough to learn some simple things about wood working.
Here you can see my 'cade setup. If you can call it a setup.  :laugh:

http://i16.photobucket.com/albums/b5/whitebabylon/cade_zpscd5c7f6b.jpg

Here's a 3 second very crappy video.

http://s16.photobucket.com/user/whitebabylon/media/20141010_1317401_zpsde346f7d.mp4.html


Video background. The top right video which is the same as the background video will be for system/game preview videos.

OK, code time.
For each game system we want to keep track of a few things. It's rom directory, it's rom file type, its exe directory, and the name of the exe.

Code: [Select]
        string dir_MAME = @"D:\arcade\mame\roms\";
        string type_MAME = "*.zip";
        string exeDir_MAME = @"D:\arcade\mame\";
        string exeName_MAME = @"mame.exe";


If you imagine a simple design like below. You click a button and depending on the button you get the roms from the proper directory. After that, on pressing a key, you want to open the emulator with that ROM.


When you click a button it fires up some code. For MAME I have this:

Code: [Select]
cmdString = "D:\\ & " + "cd " + exeDir_MAME + " & " + exeName_MAME + " \"" + listBox1.SelectedItem.ToString() + "\"";
                    WorkingDir = exeDir_MAME;
                    dir_CUR = dir_MAME;
                    type_CUR = type_MAME;
                    procName = "mame";
                    windowMsg = "Default IME";

You set up the directory of the EXE, rom and the type of file the rom is. You also want to keep track of the emulators process name, which can be seen under Processes tab of CTRL_ALT_DELETE menu in windows. Also, we want to know the 'window message' for when the emulator is open and ready to be manipulated. I don't know much about it, but I've found that every emulator thus far fires off a 'Default IME' when it's basically 'ready'.
The one variable I didn't mention yet is a command string. We basically are forming the windows command line command to properly execute the 'open file with these exe' command.
We call

Code: [Select]
ExecuteCommand(cmdString);
private void ExecuteCommand(string command)
        {
            ProcessStartInfo processInfo;
            Process process;
            processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
            processInfo.CreateNoWindow = true;
            processInfo.UseShellExecute = false;
 
            processInfo.WorkingDirectory = WorkingDir;

            process = Process.Start(processInfo);
            process.Close();

        }

My command strings are actually 3 commands chained together with &. First we change from C to D directory, where my arcade files are. Then we navigate to the EXE directory, then we directly call the EXE and the rom file command like:
"file.exe file.rom"

I've found I have to directly navigate to the exe folder first, before calling the exe and call it directly. I cannot explain why I can't just call 'D:\arcade\mame.exe', but it did not work.

With any luck that should fire up your emulator with the rom. This does not work with all emulators, and I've chosen emulators that allow me to do this. For example, Project 64 uses something else to open it's own files. One work around that I thought about was to send the CTRL+O keystrokes to the emulator which is the shortcut for file->open, and to send the keystrokes of the rom path\rom name to the 'Windows File Open Directory' box that pops up, to open it. You could do this behind the scenes and it would probably only take a second or two. I'll get more into input in a bit.

Basically so far all we've done is call the command line tool to open a file. After a file has been called to open a timer starts immediately. As we keep track of each emulators process name, we say for each process see if this one exists, if it does, grab the first one (if multiples are open, which they should not be). Then it grabs the systems message of the window and checks of its the correct message before we manipulate a few things.
Read the comments to understand a bit more.

Code: [Select]
private void programOpen_Tick(object sender, EventArgs e)
        {
//Create a windows handle
            IntPtr WindowHandle = IntPtr.Zero;
            try
            {
//grab the process, in our example 'mame'
                Process[] processes = Process.GetProcessesByName(procName);
//for each process that exists, grab our process
                foreach (var handle in EnumerateProcessWindowHandles(
                    Process.GetProcessesByName(procName).First().Id))
                {
//stringbuilder and sendmessage grab our MAME emulators message
                    StringBuilder message = new StringBuilder(1000);
                    SendMessage(handle, WM_GETTEXT, message.Capacity, message);
                    Console.WriteLine("NEW MSG + " + message);
// if our message is whatever we decided was 'file loaded' then do some stuff
                    if (message.ToString() == windowMsg)
                    {
//Here we use a lot of User32.dll calls to manipulate the window, first we grab the width/height of our computer screen
//then we get the window handle of our process, and set it's position to 0,0 and its height/width to the monitor. in my example I take into account the window border
//so that it hides the windows borders, which are 2 pixels thick by setting this to -2,-2 and added 4 to the width/height
//emulators have menus which look like [File, Open, Help] etc... so we call GetMenu and SetMenu and remove menu and drawmenu bar to erase this
//what we are doing here is 'full screen'ing the emulator. This works for all the ones I've tried. It's kind of dirty I think, but I love it.

                        System.Drawing.Rectangle resolution = Screen.PrimaryScreen.Bounds;
                        int screenWidth = resolution.Width;
                        int screenHeight = resolution.Height;
                        foreach (Process process in processes)
                        {
                            WindowHandle = process.MainWindowHandle;
                            SetWindowPos(WindowHandle, IntPtr.Zero, -2, -2, (screenWidth + 4), (screenHeight + 4), SWP_NOZORDER | SWP_SHOWWINDOW);
                            IntPtr hmenu = GetMenu(WindowHandle);
                            int counter = GetMenuItemCount(hmenu);
                            int i = 0;
                            uint MF_BYPOSITION = (0x400);
                            uint value_zero = 0;
                            int GWL_STYLE = -16;
                            int WS_VISIBLE = 0x10000000;
                            for (i = 0; i < (int)counter; i++)
                            {
                                RemoveMenu(hmenu, value_zero, (uint)MF_BYPOSITION);
                            }
                            DrawMenuBar(WindowHandle);
                            SetWindowLong(WindowHandle, GWL_STYLE, WS_VISIBLE);
                            InvalidateRect(WindowHandle, IntPtr.Zero, true);

                        }
                        programOpen.Stop();
                    }
                }
            }
            catch
            {

            }
        }

So user32 does some window manipulations. Setting positions, width/height, windows style, and menus of the applications we run to full screen things. We can also set a 'topmost' flag to make applications appear always on the top of our screen, this will be important to assure the user is seeing what we want. When the program starts up we will want it to be full screen and always on top, thus if anything ever happens on windows for whatever reason, it won't stop the users visual experience. When we launch an emulator we will trade which application is always-top.
Using this we can handle our windows and running applications. Next big thing is input. I use a global key hook to essentially create my own keyboard shortcut commands, and to allow me to remap keys.
Say if you press A, you can 'stop' the A value from being sent, and replace it with your own value.
Here's some dirty code:
Code: [Select]
       /***********************************************************
         *
         *                      Keyboard Input
         *
         *
         * *********************************************************/
        private enum INPUTTYPE : uint
        {
            Keyboard = 1
        }

        private enum KEYEVENTF : uint
        {
            KeyUp = 2,
            Scan = 8,
        }

        [DllImport("User32.dll", SetLastError = true)]
        private static extern uint SendInput(int nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] inputs, int cbSize);

        [StructLayout(LayoutKind.Sequential)]
        private struct INPUT
        {
            public INPUTTYPE type;
            public INPUT_U u;

            public static INPUT VirtualKeyDown(ushort keyP)
            {

                var input = new INPUT() { type = INPUTTYPE.Keyboard };


                input.u.ki = new KEYBDINPUT() { scanCode = (ushort)keyP, flags = (KEYEVENTF)0x0008 };

                return input;
            }

            public static INPUT VirtualKeyUp(ushort keyP)
            {
                var input = new INPUT() { type = INPUTTYPE.Keyboard };
                input.u.ki = new KEYBDINPUT() { scanCode = (ushort)keyP, flags = (KEYEVENTF)0x0008 | (KEYEVENTF)0x0002 };

                return input;
            }
        }

        [StructLayout(LayoutKind.Explicit)]
        private struct INPUT_U
        {
            [FieldOffset(0)]
            public KEYBDINPUT ki;

            [FieldOffset(0)]
            public MOUSEINPUT mi;

            [FieldOffset(0)]
            public HARDWAREINPUT hi;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct KEYBDINPUT
        {
            public ushort virtualKey;
            public ushort scanCode;
            public KEYEVENTF flags;
            public uint time;

            public IntPtr extraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr extraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct HARDWAREINPUT
        {
            public int uMsg;
            public IntPtr wParam;
            public IntPtr lParam;
        }


Once you have that stuff though its a bit easier to use it.
first you initiate
Code: [Select]
hookId = SetHook(hookProc2, moduleHandle);

private static IntPtr SetHook(LowLevelKeyboardProc hookProc, IntPtr moduleHandle)
        {

            return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
        }
 private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
Then you can use it in this function
Code: [Select]
private static IntPtr HookCallback2(int nCode, IntPtr wParam, IntPtr lParam)
        {
int vkCode = Marshal.ReadInt32(lParam);
//If key up of a button
 if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)
            {
//If keyboard input is "C" button, then
 if (((System.Windows.Forms.Keys)vkCode).ToString() == "C")
                {
//create an input array, we can have more than 1 input in this array, but this one just replaces "C" with the value 0x2c. I don't remember the value, but you can look up the vlaues here:
//http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
                    INPUT[] inputs = new INPUT[] {
INPUT.VirtualKeyUp((ushort)0x2c),
                };
//send this input
                    SendInput(inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
//I use a value here, and if it's 1, then we don't return the original value
                    returnMe = 1;
                }
            }
//if a keyDOWN event is called, then if it's Z then send a keydown of whatever key
 if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {

                returnMe = 1;

                if (((System.Windows.Forms.Keys)vkCode).ToString() == "Z")
                {
                    INPUT[] inputs = new INPUT[] {
INPUT.VirtualKeyDown((ushort)0x2e),
                    };
                    SendInput(inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
                }
//calling 'CallNextHookEx' sends the original key message, returning 1 instead lets you send your own message and ignore the original key press
if (returnMe == (int)1)
            {
                return (System.IntPtr)1;
            }
            else
            {
                return CallNextHookEx(hookId, nCode, wParam, lParam);
            }
        }
This has allowed me to send custom input to nestopia, MAME and all the other emulators that I've tried.
It also allows me to remap A -> B and B -> A. Which I originally thought wasn't allowed.
You can get a keys current state, like say CONTROL key, and if it's down, and your original key is A you could execute some code. Essentially making CTRL+A your very own hotkey. With our windows handling code we can create a menu that pops up on whatever hot key we want to allow the user to close current emulator, and to switch back to the arcade program.

You can look up user32.dll on p/invoke and learn about some of the functionality that I use
Code: [Select]
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName,
            string lpWindowName);

        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern short GetKeyState(int virtualKeyCode);

        // Activate an application window.
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        static extern IntPtr GetMessageExtraInfo();

        [DllImport("user32.dll")]
        static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);


        /* enumerate windows*/
        delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn,
            IntPtr lParam);

        static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processId)
        {
            var handles = new List<IntPtr>();

            foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
                EnumThreadWindows(thread.Id,
                    (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);

            return handles;
        }

        private const uint WM_GETTEXT = 0x000D;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam,
            StringBuilder lParam);

        /* */
        /* Erase menu fron a window*/
        [DllImport("user32.dll")]
        static extern IntPtr GetMenu(IntPtr hWnd);

        [DllImport("user32.dll")]
        static extern int GetMenuItemCount(IntPtr hMenu);

        [DllImport("user32.dll")]
        static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);

        [DllImport("user32.dll")]
        static extern bool DrawMenuBar(IntPtr hWnd);

        [DllImport("user32.dll")]
        static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
        /* */
        /* Set border style */
        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        /* */
        private const int WH_KEYBOARD_LL = 13;
        private const int WH_GETMESSAGE = 3;
       

        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;
        private static LowLevelKeyboardProc hookProc = HookCallback;
        private static LowLevelKeyboardProc hookProc2 = HookCallback2;
        private static IntPtr hookId = IntPtr.Zero;
        private string pressedBefore = "A";
        public IntPtr moduleHandle;

        const short SWP_NOSIZE = 1;
        const short SWP_NOZORDER = 0X4;
        const int SWP_SHOWWINDOW = 0x0040;


        const UInt32 SWP_NOSIZE2 = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 TOPMOST_FLAGS = (UInt32) (SWP_NOMOVE | SWP_NOSIZE2);
        static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);


Full code for the alpha program here:
http://pastebin.com/emCjcjk5


Now the current application from the image above is just a WPF front end. It uses a media element as the background, and Labels to display a menu. It uses brushes to paint the currently selected menu item.

It might not make much sense until I actually finish the code and post the fully functional fully commented end peice.
Game plan is to have 3 types of input, keyboard/xarcade (same as keyboard really)/ and xbox controller. Remapping the first two with SendInput function, and xbox controller with "Microsoft.Xna.Framework".


Jimbo

  • Trade Count: (+1)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1014
  • Last login:January 04, 2025, 12:18:10 pm
  • I have no idea what I'm doing.
    • Wood Finishes Direct
Re: Here I make a front end for windows 7 c#
« Reply #1 on: October 10, 2014, 02:28:20 pm »
Good luck, I remember when I wrote my first front-end and I got a lot of enjoyment out of it.  It's a great thing to write to learn how to code in my opinion!

whitebabylon

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 28
  • Last login:April 26, 2015, 12:10:26 am
  • I want to build my own arcade controls!
Re: Here I make a front end for windows 7 c#
« Reply #2 on: November 03, 2014, 02:24:05 pm »
Good luck, I remember when I wrote my first front-end and I got a lot of enjoyment out of it.  It's a great thing to write to learn how to code in my opinion!
Thanks, its been fun so far.

Video update here:
http://s16.photobucket.com/user/whitebabylon/media/20141031_143351_zpsrlgmcdu6.mp4.html

Wall of text here:
Just a small update, its been awhile. I've programmed some LEDs. It takes windows max volume output and uses it as the 'speed' it cycles through a base rotation of colors. Its kind of cool but I'd like something more elaborate in the end. I have a sound card hook that captures the data but it returns a value of like -99999999999 to 9999999999 so once I figure out how to deciepher that into actual notes or something (at least high medium and low pitch) I could translate a much cooler RGB effect.

The menu lets you scroll and select a system then presents you with a #,ALL,A-Z menu to select your games. I'm finding that this is still not enough to cycle through the games so I'm thinking about putting in an old cell phone style of input, where tapping a key once gives you either A,B or C. and use my 8 arcade buttons to allow you to type in keywords quickly.

As of right now, it launches the games you select and you can play, and then on a key combination press it will close your emulator and send you back to the arcade.
There's an application in the background that directs the flow of programs. The programs it controls is:
1.)Splash SCreen
2.) Arcade video background
3.) Arcade video foreground (the menu and the game play demonstration video in the top right)
4.) Emulator

Depending on whats open and what you press it knows how to handle opening/closing things. If neither an emulator or the arcade app are open, somethings wrong and it launches the arcade app.

-So I need to get all my videos in place (dear god).
-Allow for dynamic input profiles (mostly editing .xmls on a per emulator basis)
-Change my mame list from displaying rom names to actual game names
-allow search feature for faster navigations
-have another option of 'favorites' for each system so I can find my most played games faster

After that I'll feel pretty good. Could use tweaking between windows for a more flawless interaction.

empardopo

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 526
  • Last login:July 20, 2025, 05:12:51 am
    • My personal forum
Re: Here I make a front end for windows 7 c#
« Reply #3 on: January 28, 2015, 01:30:14 am »
How is It this project? Is It alive?

bulbousbeard

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 522
  • Last login:August 25, 2015, 11:58:25 pm
  • I want to build my own arcade controls!
Re: Here I make a front end for windows 7 c#
« Reply #4 on: January 28, 2015, 04:03:32 am »
I wrote Big Blue in WPF, too, and I have a working implementation of Raw Input for multiple keyboard and mouse inputs as well as an XInput implementation for 360 pads. If you want the source code, let me know. If you're in WPF, you should just be able to drop it in.

I also use similar methods for launching games, and I can launch binaries from any directory in one call. There's probably a lot of stuff from Big Blue that you could use.

https://sites.google.com/site/bigbluefrontend/
« Last Edit: January 28, 2015, 04:05:31 am by bulbousbeard »

empardopo

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 526
  • Last login:July 20, 2025, 05:12:51 am
    • My personal forum
Re: Here I make a front end for windows 7 c#
« Reply #5 on: January 28, 2015, 04:35:25 am »
I wrote Big Blue in WPF, too, and I have a working implementation of Raw Input for multiple keyboard and mouse inputs as well as an XInput implementation for 360 pads. If you want the source code, let me know. If you're in WPF, you should just be able to drop it in.

I also use similar methods for launching games, and I can launch binaries from any directory in one call. There's probably a lot of stuff from Big Blue that you could use.

https://sites.google.com/site/bigbluefrontend/

Interesting! I'll try to take a look! Could you to share the source code with me then?
Thanks!

whitebabylon

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 28
  • Last login:April 26, 2015, 12:10:26 am
  • I want to build my own arcade controls!
Re: Here I make a front end for windows 7 c#
« Reply #6 on: April 14, 2015, 01:34:01 pm »
I wrote Big Blue in WPF, too, and I have a working implementation of Raw Input for multiple keyboard and mouse inputs as well as an XInput implementation for 360 pads. If you want the source code, let me know. If you're in WPF, you should just be able to drop it in.

I also use similar methods for launching games, and I can launch binaries from any directory in one call. There's probably a lot of stuff from Big Blue that you could use.

https://sites.google.com/site/bigbluefrontend/
I haven't worked on my front end in a long time. never really finished it either. It launches games and I haven't touched it since haha.
I was debating starting from scratch with it. My interface plays a 1080p video background which flickers when the user scrolls trhough the menus really fast. I solved this problem by having multiple forms open. It seems very hacky. I'm wondering if using DirectX if I couldn't use the graphics card to power the user interface if that wouldn't solve my problem?
But I know nothing about doing that.