.NET कंसोल ऐप में मुख्य प्रेस के लिए सुनो


224

कुंजी प्रेस (जैसे Escदबाया गया) होने तक मैं अपना कंसोल एप्लिकेशन कैसे चला सकता हूं ?

मैं थोड़ी देर लूप के चारों ओर लिपटे हुए मान रहा हूँ। मुझे पसंद नहीं है ReadKeyक्योंकि यह ऑपरेशन को ब्लॉक करता है और कुंजी जारी रखने के लिए कहता है, बजाय कुंजी को जारी रखने और सुनने के।

यह कैसे किया जा सकता है?

जवाबों:


343

उपयोग करें Console.KeyAvailableताकि आप केवल तभी कॉल करें ReadKeyजब आपको पता हो कि यह ब्लॉक नहीं होगा:

Console.WriteLine("Press ESC to stop");
do {
    while (! Console.KeyAvailable) {
        // Do something
   }       
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);

6
लेकिन अगर आप इसे रीडलाइन () के बजाय करते हैं, तो आप "अप" कुंजी दबाकर इतिहास को याद रखने की भयानक सुविधा खो देते हैं।
v.oddou

3
@ v.oddou अंतिम पंक्ति के बाद, बस अपना जोड़ें Console.ReadLine()और आप सेट हैं, नहीं?
गफी

1
क्या यह लूप CPU / RAM का बहुत अधिक उपभोग नहीं करेगा? यदि नहीं, तो कैसे?
सोफिया

78

आप अपने दृष्टिकोण को थोड़ा बदल सकते हैं - Console.ReadKey()अपने ऐप को रोकने के लिए उपयोग करें, लेकिन अपने काम को पृष्ठभूमि में करें:

static void Main(string[] args)
{
    var myWorker = new MyWorker();
    myWorker.DoStuff();
    Console.WriteLine("Press any key to stop...");
    Console.ReadKey();
}

में myWorker.DoStuff()समारोह आप तो एक पृष्ठभूमि धागे पर एक और समारोह आह्वान (का उपयोग करते हुए हैं Action<>()या Func<>()एक आसान तरीका यह करने के लिए है), तो तुरंत वापस जाएँ।


60

सबसे छोटा तरीका:

Console.WriteLine("Press ESC to stop");

while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape))
{
    // do something
}

Console.ReadKey()एक अवरुद्ध कार्य है, यह कार्यक्रम के निष्पादन को रोकता है और एक महत्वपूर्ण प्रेस की प्रतीक्षा करता है, लेकिन Console.KeyAvailableपहले जांचने के लिए धन्यवाद , whileलूप अवरुद्ध नहीं है, लेकिन Escदबाए जाने तक चल रहा है।


अब तक का सबसे आसान उदाहरण। धन्यवाद।
जोएलक

18

जेसप रॉबर्ट्स द्वारा http://www.pluralsight.com पर C # वीडियो शाप बिल्डिंग .NET कंसोल कंसोल से

हम कई चलने की प्रक्रिया का पालन कर सकते हैं

  static void Main(string[] args)
    {
        Console.CancelKeyPress += (sender, e) =>
        {

            Console.WriteLine("Exiting...");
            Environment.Exit(0);
        };

        Console.WriteLine("Press ESC to Exit");

        var taskKeys = new Task(ReadKeys);
        var taskProcessFiles = new Task(ProcessFiles);

        taskKeys.Start();
        taskProcessFiles.Start();

        var tasks = new[] { taskKeys };
        Task.WaitAll(tasks);
    }

    private static void ProcessFiles()
    {
        var files = Enumerable.Range(1, 100).Select(n => "File" + n + ".txt");

        var taskBusy = new Task(BusyIndicator);
        taskBusy.Start();

        foreach (var file in files)
        {
            Thread.Sleep(1000);
            Console.WriteLine("Procesing file {0}", file);
        }
    }

    private static void BusyIndicator()
    {
        var busy = new ConsoleBusyIndicator();
        busy.UpdateProgress();
    }

    private static void ReadKeys()
    {
        ConsoleKeyInfo key = new ConsoleKeyInfo();

        while (!Console.KeyAvailable && key.Key != ConsoleKey.Escape)
        {

            key = Console.ReadKey(true);

            switch (key.Key)
            {
                case ConsoleKey.UpArrow:
                    Console.WriteLine("UpArrow was pressed");
                    break;
                case ConsoleKey.DownArrow:
                    Console.WriteLine("DownArrow was pressed");
                    break;

                case ConsoleKey.RightArrow:
                    Console.WriteLine("RightArrow was pressed");
                    break;

                case ConsoleKey.LeftArrow:
                    Console.WriteLine("LeftArrow was pressed");
                    break;

                case ConsoleKey.Escape:
                    break;

                default:
                    if (Console.CapsLock && Console.NumberLock)
                    {
                        Console.WriteLine(key.KeyChar);
                    }
                    break;
            }
        }
    }
}

internal class ConsoleBusyIndicator
{
    int _currentBusySymbol;

    public char[] BusySymbols { get; set; }

    public ConsoleBusyIndicator()
    {
        BusySymbols = new[] { '|', '/', '-', '\\' };
    }
    public void UpdateProgress()
    {
        while (true)
        {
            Thread.Sleep(100);
            var originalX = Console.CursorLeft;
            var originalY = Console.CursorTop;

            Console.Write(BusySymbols[_currentBusySymbol]);

            _currentBusySymbol++;

            if (_currentBusySymbol == BusySymbols.Length)
            {
                _currentBusySymbol = 0;
            }

            Console.SetCursorPosition(originalX, originalY);
        }
    }

2
क्या आप उस दृष्टिकोण के बारे में थोड़ा समझा सकते हैं जो मैं अपने कंसोल एप्लिकेशन के साथ भी कर रहा हूं। कोड के लिए स्पष्टीकरण बहुत अच्छा होगा।
नायेफ हर्ब

@nayefharb कार्यों का एक समूह सेटअप करें, उन्हें प्रारंभ करें, और WaitAll तब तक प्रतीक्षा करेगा जब तक वे सभी वापस नहीं आ जाते। इसलिए व्यक्तिगत कार्य वापस नहीं आएंगे और यह तब तक हमेशा के लिए जारी रहेगा जब तक कि कैंसेप्ले ट्रिगर न हो जाए।
16

Console.CursorVisible = false;कर्सर ब्लिंक ग्लिच से बचने के लिए सबसे अच्छा होगा। इस लाइन को static void Main(string[] args)ब्लॉक में पहली लाइन के रूप में जोड़ें ।
हितेश

12

यहां आपके लिए एक अलग धागे पर कुछ करने के लिए एक दृष्टिकोण है और एक अलग धागे में दबाए गए कुंजी को सुनना शुरू करें। और जब आपकी वास्तविक प्रक्रिया समाप्त होती है या उपयोगकर्ता Escकुंजी दबाकर प्रक्रिया समाप्त कर देता है तो कंसोल इसकी प्रोसेसिंग को रोक देगा ।

class SplitAnalyser
{
    public static bool stopProcessor = false;
    public static bool Terminate = false;

    static void Main(string[] args)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine("Split Analyser starts");
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("Press Esc to quit.....");
        Thread MainThread = new Thread(new ThreadStart(startProcess));
        Thread ConsoleKeyListener = new Thread(new ThreadStart(ListerKeyBoardEvent));
        MainThread.Name = "Processor";
        ConsoleKeyListener.Name = "KeyListener";
        MainThread.Start();
        ConsoleKeyListener.Start();

        while (true) 
        {
            if (Terminate)
            {
                Console.WriteLine("Terminating Process...");
                MainThread.Abort();
                ConsoleKeyListener.Abort();
                Thread.Sleep(2000);
                Thread.CurrentThread.Abort();
                return;
            }

            if (stopProcessor)
            {
                Console.WriteLine("Ending Process...");
                MainThread.Abort();
                ConsoleKeyListener.Abort();
                Thread.Sleep(2000);
                Thread.CurrentThread.Abort();
                return;
            }
        } 
    }

    public static void ListerKeyBoardEvent()
    {
        do
        {
            if (Console.ReadKey(true).Key == ConsoleKey.Escape)
            {
                Terminate = true;
            }
        } while (true); 
    }

    public static void startProcess()
    {
        int i = 0;
        while (true)
        {
            if (!stopProcessor && !Terminate)
            {
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("Processing...." + i++);
                Thread.Sleep(3000);
            }
            if(i==10)
                stopProcessor = true;

        }
    }

}

5

यदि आप विजुअल स्टूडियो का उपयोग कर रहे हैं, तो आप डिबग मेनू में "स्टार्ट विदाउट डिबगिंग" का उपयोग कर सकते हैं।

यह स्वचालित रूप से लिखेगा "जारी रखने के लिए कोई भी कुंजी दबाएं।" आवेदन के पूरा होने पर आपके लिए कंसोल और यह कुंजी को दबाए जाने तक आपके लिए कंसोल को खुला छोड़ देगा।


3

ऐसे मामलों को संबोधित करना जो कुछ अन्य जवाबों को अच्छी तरह से संभाल नहीं पाते हैं:

  • उत्तरदायी : कीप हैंडलिंग कोड का प्रत्यक्ष निष्पादन; मतदान या अवरुद्ध देरी की योनि से बचा जाता है
  • वैकल्पिकता : वैश्विक कुंजीपट ऑप्ट-इन है ; अन्यथा एप्लिकेशन को सामान्य रूप से बाहर निकलना चाहिए
  • चिंताओं का पृथक्करण : कम आक्रामक सुनने का कोड; स्वतंत्र रूप से सामान्य कंसोल ऐप कोड का संचालन करता है।

इस पृष्ठ के कई समाधानों में मतदान Console.KeyAvailableया अवरुद्ध करना शामिल है Console.ReadKey। हालांकि यह सच है कि .NET Consoleयहां बहुत सहयोगी नहीं है, आप सुनने के Task.Runअधिक आधुनिक Asyncमोड की ओर बढ़ने के लिए उपयोग कर सकते हैं ।

मुख्य मुद्दा यह है कि डिफ़ॉल्ट रूप से, आपका कंसोल थ्रेड Asyncऑपरेशन के लिए सेट नहीं किया गया है - जिसका अर्थ है, जब आप अपने mainफ़ंक्शन के निचले भाग से बाहर आते हैं, तो Asyncपूर्णता की प्रतीक्षा करने के बजाय , आपका AppDoman और प्रक्रिया समाप्त हो जाएगी । इसे संबोधित करने का एक उचित तरीका यह होगा कि आप अपने सिंगल-थ्रेड कंसोल प्रोग्राम में पूर्ण समर्थन स्थापित करने के लिए स्टीफन क्लीरी के AsyncContext का उपयोग करें Async। लेकिन सरल मामलों के लिए, जैसे कि कीपर के लिए इंतजार करना, एक पूर्ण ट्रैम्पोलिन स्थापित करना ओवरकिल हो सकता है।

नीचे दिया गया उदाहरण किसी प्रकार के पुनरावृत्त बैच फ़ाइल में उपयोग किए जाने वाले कंसोल प्रोग्राम के लिए होगा। इस मामले में, जब कार्यक्रम अपने काम के साथ किया जाता है, तो आम तौर पर इसे एक कीपर की आवश्यकता के बिना बाहर निकल जाना चाहिए , और फिर हम ऐप को बाहर निकलने से रोकने के लिए एक वैकल्पिक कुंजी प्रेस की अनुमति देते हैं । हम चीजों की जांच करने के लिए चक्र को रोक सकते हैं, संभवतः फिर से शुरू कर सकते हैं, या एक ज्ञात 'नियंत्रण बिंदु' के रूप में विराम का उपयोग कर सकते हैं, जिस पर बैच फ़ाइल को साफ करने के लिए।

static void Main(String[] args)
{
    Console.WriteLine("Press any key to prevent exit...");
    var tHold = Task.Run(() => Console.ReadKey(true));

    // ... do your console app activity ...

    if (tHold.IsCompleted)
    {
#if false   // For the 'hold' state, you can simply halt forever...
        Console.WriteLine("Holding.");
        Thread.Sleep(Timeout.Infinite);
#else                            // ...or allow continuing to exit
        while (Console.KeyAvailable)
            Console.ReadKey(true);     // flush/consume any extras
        Console.WriteLine("Holding. Press 'Esc' to exit.");
        while (Console.ReadKey(true).Key != ConsoleKey.Escape)
            ;
#endif
    }
}

1

नीचे दिए गए कोड के साथ आप स्पेसबार को अपने कंसोल एक्जीक्यूशन के बीच में दबा सकते हैं और तब तक रोक सकते हैं जब तक कि दूसरी चाबी न दब जाए और मुख्य लूप को तोड़ने के लिए एस्केपके को भी सुन लें।

static ConsoleKeyInfo cki = new ConsoleKeyInfo();


while(true) {
      if (WaitOrBreak()) break;
      //your main code
}

 private static bool WaitOrBreak(){
        if (Console.KeyAvailable) cki = Console.ReadKey(true);
        if (cki.Key == ConsoleKey.Spacebar)
        {
            Console.Write("waiting..");
            while (Console.KeyAvailable == false)
            {
                Thread.Sleep(250);Console.Write(".");
            }
            Console.WriteLine();
            Console.ReadKey(true);
            cki = new ConsoleKeyInfo();
        }
        if (cki.Key == ConsoleKey.Escape) return true;
        return false;
    }

-1

मेरे अनुभव के अनुसार, कंसोल में ऐप्स को दबाए गए अंतिम कुंजी को पढ़ने का सबसे आसान तरीका निम्नानुसार है (उदाहरण तीर कुंजी के साथ):

ConsoleKey readKey = Console.ReadKey ().Key;
if (readKey == ConsoleKey.LeftArrow) {
    <Method1> ();  //Do something
} else if (readKey == ConsoleKey.RightArrow) {
    <Method2> ();  //Do something
}

मैं छोरों से बचने के लिए उपयोग करता हूं, इसके बजाय मैं एक विधि के भीतर कोड लिखता हूं, और मैं इसे "Method1" और "Method2" दोनों के अंत में कहता हूं, इसलिए, "Method1" या "Method2", Console.ReadKey () को निष्पादित करने के बाद .की फिर से चाबी पढ़ने के लिए तैयार है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.