none
Run Console In Background

    Question

  • I have a simple console app that writes the x/y location of the cursor and the color of the pixel it's on. It works great so long as it's in the foreground. How can I have it run when I toggle other programs to the front?

    Thanks in advance!

    using System;
    using System.IO;
    using System.Drawing;
    using System.Windows.Forms;
    
    
    namespace PixelColor
    {    
        class Program
        {
           
            static void Main(string[] args)
            {
                
                while (true)
                {
                    if(Console.ReadKey().Key == ConsoleKey.Home)
                    {                    
                        Console.WriteLine("X:" + Cursor.Position.X.ToString() + " Y:" + Cursor.Position.Y.ToString() + " : " + GetPixel(Cursor.Position));
                        SaveColorAndLocation("X:" + Cursor.Position.X.ToString() + " Y:" + Cursor.Position.Y.ToString() + " : " + GetPixel(Cursor.Position));
                    }
                }
    
    
            }//end Main
    
            static void SaveColorAndLocation(string text)
            {
                using (StreamWriter writer = new StreamWriter("colorandlocation.txt",true))
                {
                    writer.WriteLine(text);               
                }
            }
    
            static Color GetPixel(Point position)
            {
                using (var bitmap = new Bitmap(1, 1))
                {
                    using (var graphics = Graphics.FromImage(bitmap))
                    {
                        graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
                    }
                    return bitmap.GetPixel(0, 0);
                }
            }
        }
    }
    


    • Edited by Jmair Tuesday, April 18, 2017 1:53 PM Added Code
    Monday, April 17, 2017 10:29 PM

Answers

  • The keys can be intercepted using “hooks”: https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/.

    Here is a sample console application:

    class Program
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int PM_REMOVE = 1;
    
        private delegate IntPtr LowLevelKeyboardProc( int nCode, IntPtr wParam, IntPtr lParam );
        private static LowLevelKeyboardProc handler = HookCallback;
        private static IntPtr previousHook;
        private static bool endPressed = false;
    
        [DllImport( "user32", CharSet = CharSet.Auto, SetLastError = true )]
        private static extern IntPtr SetWindowsHookEx( int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId );
    
        [DllImport( "user32", CharSet = CharSet.Auto, SetLastError = true )]
        private static extern IntPtr CallNextHookEx( IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam );
    
    
        [StructLayout( LayoutKind.Sequential )]
        public struct NativeMessage
        {
            public IntPtr handle;
            public uint msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }
    
    
        [DllImport( "user32" )]
        static extern bool PeekMessage( out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg );
    
    
        private static IntPtr HookCallback( int nCode, IntPtr wParam, IntPtr lParam )
        {
            if( nCode >= 0 && wParam.ToInt32() == WM_KEYDOWN )
            {
                var key = unchecked((Keys)Marshal.ReadInt32( lParam ));
    
                switch( key )
                {
                case Keys.Home:
                    {
                        Console.Beep();
                        Console.WriteLine( "<HOME> detected" );
                        // . . .
                    }
                    break;
                case Keys.End:
                    {
                        Console.Beep();
                        Console.WriteLine( "<END> detected" );
                        endPressed = true;
                    }
                    break;
                }
            }
    
            return CallNextHookEx( previousHook, nCode, wParam, lParam );
        }
    
    
        static void Main( string[] args )
        {
            previousHook = SetWindowsHookEx( WH_KEYBOARD_LL, handler, IntPtr.Zero, 0 );
    
            Console.WriteLine( "Hook installed..." );
    
            while( !endPressed )
            {
                NativeMessage m;
                PeekMessage( out m, IntPtr.Zero, 0, 0, PM_REMOVE );
            }
        }
    }
    

    It detects the <HOME> key. In case of <END>, it exists.

    • Marked as answer by Jmair Tuesday, April 18, 2017 5:21 PM
    Tuesday, April 18, 2017 3:14 PM

All replies

  • Hello,

     All depends on your project code. If you would show us what you have then

    we may better understand your project.  We all have our methods and styles.

     

     However, you can give Window Form access to Console window, by change

    the Project Output Type from Windows App to Console App in the Project

    Application settings.  You will now have a both at the same time. 

     

    Inside the Form make these changes;

     1. Set Form property WindowState to Minimize

     2. Set Form property StartPosition to WindowsDefaultBounds or assign manually

     3. Add a Timer Object to the Form, set Interval 50

     4. Add Form and Timer Events and the below code

     Form.cs

    private void Form1_Load( object sender, EventArgs e )
    {
    	timer1.Enabled = true;
    	timer1.Start();
    }
    
    private void timer1_Tick( object sender, EventArgs e )
    {
    	Console.WriteLine( MousePosition.ToString() );
    }
    
    private void Form1_FormClosing( object sender, FormClosingEventArgs e )
    {
    	timer1.Stop();
    }

     Final results may vary :)

     Also remember, that you can change the Console properties just like

    any other Console Window and should retain them next execute.

     

     Hope this helps  :)


    • Edited by User3DX Tuesday, April 18, 2017 12:40 AM Updated
    Monday, April 17, 2017 10:42 PM
  • Hi Jmair,

    Thank you for posting here.

    For console application, the easy way is to set the Output Type as "Windows application".

    Right click your project> Properties> Application> Output Type> Windows Application

    It is the way for thread, you could set the Background thread via thread pool.

    The threads in the managed thread pool are background threads. That is, their IsBackgounnd properties are true.

    Please download the source file from Background Thread? Let me count the ways.... in code project for reference.

    I hope this would be helpful.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, April 18, 2017 6:16 AM
    Moderator
  • The next simple console program seems to work even if it is not the active and top window:

    static void Main( string[] args )
    {
    	Point previous_position = new Point( -1, -1 );
    	Color previous_colour = Color.Transparent;
    
    	Bitmap bmp = new Bitmap( 1, 1 );
    	for( ; ; Thread.Sleep( 333 ) )
    	{
    		var position = Cursor.Position;
    		Color colour;
    
    		using( var g = Graphics.FromImage( bmp ) )
    		{
    			g.CopyFromScreen( position, new Point( 0, 0 ), new Size( 1, 1 ) );
    			colour = bmp.GetPixel( 0, 0 );
    		}
    
    		if( previous_position != position || previous_colour != colour )
    		{
    			previous_position = position;
    			previous_colour = colour;
    
    			Console.WriteLine( "{0}: {1}", position, colour );
    		}
    	}
    }
    

    Perhaps your way is different, therefore show details to reproduce the problem.


    • Edited by Viorel_MVP Tuesday, April 18, 2017 6:36 AM
    Tuesday, April 18, 2017 6:23 AM
  • Wendy,

     Sorry to say but your suggestion is incorrect. If the Project template is

    Console and changed to Windows then OP must Add References. Where as

    I had suggested, Windows Form Project template includes these References.

    My suggestion saves time and needless References additions.  I don't know

    the knowledge of the OP and suggested what would be easy to accomplish.

     Thanks :)

    Tuesday, April 18, 2017 6:32 AM
  • Viorel_,

     I tried your code but we don't know the OP knowledge and even if

    our suggestion worked.  I re-evaluated your use of Bitmap and its

    good for the task. But didn't see the use Thread.Sleep.  Goes to show,

    everyone has a style or technique, we can always learn new tricks.

     I want to mention, no fault, to Wendy suggestion. I thought about it

    and its also usable to the OP.  Lets see what OP does...

     

     Just my opinion. :)


    • Edited by User3DX Tuesday, April 18, 2017 8:22 AM Correction
    Tuesday, April 18, 2017 6:50 AM
  • I think I found the issue. I'm trying to get a specific color so my code had a "press Home key" and it will store the color and location. Once I removed the ReadKey and had it ongoing, it worked fine. How can I have the ReadKey work when it's in the background though? 

    Tuesday, April 18, 2017 2:05 PM
  • Hello,

     Good that you have a solution. Try the below code;

    while (true)
    {
        if ( Console.KeyAvailable() )
        {
            if ( Console.ReadKey().Key == ConsoleKey.Home )
            {                    
                Console.WriteLine("X:" + Cursor.Position.X.ToString() + " Y:" + Cursor.Position.Y.ToString() + " : " + GetPixel(Cursor.Position));
                SaveColorAndLocation("X:" + Cursor.Position.X.ToString() + " Y:" + Cursor.Position.Y.ToString() + " : " + GetPixel(Cursor.Position));
            }
        }
    }

     The method Console.KeyAvailable() result is True/False. so your

    loop should continue.

     Please remember, mark replies appropriately and vote on them. Also

    for new question, start a new Post in the Forum.

     Thanks :)

    Tuesday, April 18, 2017 2:21 PM
  • The keys can be intercepted using “hooks”: https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/.

    Here is a sample console application:

    class Program
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int PM_REMOVE = 1;
    
        private delegate IntPtr LowLevelKeyboardProc( int nCode, IntPtr wParam, IntPtr lParam );
        private static LowLevelKeyboardProc handler = HookCallback;
        private static IntPtr previousHook;
        private static bool endPressed = false;
    
        [DllImport( "user32", CharSet = CharSet.Auto, SetLastError = true )]
        private static extern IntPtr SetWindowsHookEx( int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId );
    
        [DllImport( "user32", CharSet = CharSet.Auto, SetLastError = true )]
        private static extern IntPtr CallNextHookEx( IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam );
    
    
        [StructLayout( LayoutKind.Sequential )]
        public struct NativeMessage
        {
            public IntPtr handle;
            public uint msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }
    
    
        [DllImport( "user32" )]
        static extern bool PeekMessage( out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg );
    
    
        private static IntPtr HookCallback( int nCode, IntPtr wParam, IntPtr lParam )
        {
            if( nCode >= 0 && wParam.ToInt32() == WM_KEYDOWN )
            {
                var key = unchecked((Keys)Marshal.ReadInt32( lParam ));
    
                switch( key )
                {
                case Keys.Home:
                    {
                        Console.Beep();
                        Console.WriteLine( "<HOME> detected" );
                        // . . .
                    }
                    break;
                case Keys.End:
                    {
                        Console.Beep();
                        Console.WriteLine( "<END> detected" );
                        endPressed = true;
                    }
                    break;
                }
            }
    
            return CallNextHookEx( previousHook, nCode, wParam, lParam );
        }
    
    
        static void Main( string[] args )
        {
            previousHook = SetWindowsHookEx( WH_KEYBOARD_LL, handler, IntPtr.Zero, 0 );
    
            Console.WriteLine( "Hook installed..." );
    
            while( !endPressed )
            {
                NativeMessage m;
                PeekMessage( out m, IntPtr.Zero, 0, 0, PM_REMOVE );
            }
        }
    }
    

    It detects the <HOME> key. In case of <END>, it exists.

    • Marked as answer by Jmair Tuesday, April 18, 2017 5:21 PM
    Tuesday, April 18, 2017 3:14 PM
  • Thank you all for the suggestions. 
    Tuesday, April 18, 2017 5:22 PM