2011-09-28 11 views
9

के साथ विंडोज और लिनक्स पर Ctrl + C को कैसे पकड़ें मेरे पास क्यूटी कंसोल सर्वर एप्लिकेशन है। मेरी इच्छा है कि जब कोई मेरे सर्वर को सही तरीके से छोड़ने के लिए Ctrl + C दबाता है (विनाशकों को बुलाता है, आदि)। मैंने this पढ़ा है, हालांकि मैं इसे लिनक्स और विंडोज दोनों पर काम करना चाहता हूं। यह कैसे करना है?क्यूटी

उत्तर

19

मैं इस कक्षा का उपयोग C++ कंसोल अनुप्रयोगों में संकेतों को पकड़ने के लिए करता हूं। यह क्यूटी के लिए विशिष्ट नहीं है, हालांकि। यह विंडोज प्लेटफार्मों पर SetConsoleCtrlHandler() का उपयोग करता है, और अन्य प्लेटफ़ॉर्म पर < सिग्नल.h > द्वारा प्रदान किए गए फ़ंक्शंस। मुश्किल बात यह है कि "सिग्नल" एक क्रॉस प्लेटफॉर्म शब्द नहीं है - विंडोज और पॉज़िक्स के लिए अलग-अलग परिभाषाएं हैं। वैसे भी यह वर्ग उन्हें एक सामान्य शब्दावली में मैप करने का प्रयास करता है। Ctrl^सी वह है जो दोनों प्लेटफ़ॉर्म पर अच्छी तरह से मानचित्र करता है।

मुझे आशा है कि इसे आपकी विशिष्ट स्थिति में अनुकूलित किया जा सके। कृपया ध्यान दें कि त्रुटि जांच न्यूनतम है और शायद इसमें सुधार किया जाना चाहिए।

उपयोग (main.cpp)

#include "SignalHandler.h" 

class Application : public SignalHandler 
{ 
public: 
    Application() : SignalHandler(SignalHandler::SIG_INT), myThread(NULL) {} 

    int Application::main(int argc, char *argv[]) 
    { 
     // Main program instructions here (e.g. start a thread) 
     myThread = new Thread(...); 
     myThread->start(); 
     myThread->join(); 
     delete myThread; 
     return 0; 
    } 

    bool handleSignal(int signal) 
    { 
     std::cout << "Handling signal " << signal << std::endl; 
     if (_myThread && _myThread->isRunning()) 
     { 
      _myThread->stop(); 
      // The thread is going to stop soon, so don't propagate this signal further 
      return true; 
     } 
     // Let the signal propagate as though we had not been there 
     return false; 
    } 
private: 
    Thread* myThread; 
}; 

int main(int argc, char* argv[]) 
{ 
    Application app; 
    return app.main(argc, argv); 
} 

SignalHandler.h

class SignalHandler 
{ 
public: 
    SignalHandler(int mask = DEFAULT_SIGNALS); 
    virtual ~SignalHandler(); 

    enum SIGNALS 
    { 
     SIG_UNHANDLED = 0, // Physical signal not supported by this class 
     SIG_NOOP  = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway) 
     SIG_INT   = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit) 
     SIG_TERM  = 4, // Control+Break (should terminate now without regarding the consquences) 
     SIG_CLOSE  = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM] 
     SIG_RELOAD  = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP] 
     DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE, 
    }; 
    static const int numSignals = 6; 

    virtual bool handleSignal(int signal) = 0; 

private: 
    int _mask; 
}; 

SignalHandler.cpp

#include "SignalHandler.h" 
#include <assert.h> 

#ifndef _WIN32 

#include <signal.h> 

#else 

#include <windows.h> 

#endif //!_WIN32 

// There can be only ONE SignalHandler per process 
SignalHandler* g_handler(NULL); 

#ifdef _WIN32 

BOOL WINAPI WIN32_handleFunc(DWORD); 
int WIN32_physicalToLogical(DWORD); 
DWORD WIN32_logicalToPhysical(int); 
std::set<int> g_registry; 

#else //_WIN32 

void POSIX_handleFunc(int); 
int POSIX_physicalToLogical(int); 
int POSIX_logicalToPhysical(int); 

#endif //_WIN32 

SignalHandler::SignalHandler(int mask) : _mask(mask) 
{ 
    assert(g_handler == NULL); 
    g_handler = this; 

#ifdef _WIN32 
    SetConsoleCtrlHandler(WIN32_handleFunc, TRUE); 
#endif //_WIN32 

    for (int i=0;i<numSignals;i++) 
    { 
     int logical = 0x1 << i; 
     if (_mask & logical) 
     { 
#ifdef _WIN32 
      g_registry.insert(logical); 
#else 
      int sig = POSIX_logicalToPhysical(logical); 
      bool failed = signal(sig, POSIX_handleFunc) == SIG_ERR; 
      assert(!failed); 
      (void)failed; // Silence the warning in non _DEBUG; TODO: something better 

#endif //_WIN32 
     } 
    } 

} 

SignalHandler::~SignalHandler() 
{ 
#ifdef _WIN32 
    SetConsoleCtrlHandler(WIN32_handleFunc, FALSE); 
#else 
    for (int i=0;i<numSignals;i++) 
    { 
     int logical = 0x1 << i; 
     if (_mask & logical) 
     { 
      signal(POSIX_logicalToPhysical(logical), SIG_DFL); 
     } 
    } 
#endif //_WIN32 
} 


#ifdef _WIN32 
DWORD WIN32_logicalToPhysical(int signal) 
{ 
    switch (signal) 
    { 
    case SignalHandler::SIG_INT: return CTRL_C_EVENT; 
    case SignalHandler::SIG_TERM: return CTRL_BREAK_EVENT; 
    case SignalHandler::SIG_CLOSE: return CTRL_CLOSE_EVENT; 
    default: 
     return ~(unsigned int)0; // SIG_ERR = -1 
    } 
} 
#else 
int POSIX_logicalToPhysical(int signal) 
{ 
    switch (signal) 
    { 
    case SignalHandler::SIG_INT: return SIGINT; 
    case SignalHandler::SIG_TERM: return SIGTERM; 
    // In case the client asks for a SIG_CLOSE handler, accept and 
    // bind it to a SIGTERM. Anyway the signal will never be raised 
    case SignalHandler::SIG_CLOSE: return SIGTERM; 
    case SignalHandler::SIG_RELOAD: return SIGHUP; 
    default: 
     return -1; // SIG_ERR = -1 
    } 
} 
#endif //_WIN32 


#ifdef _WIN32 
int WIN32_physicalToLogical(DWORD signal) 
{ 
    switch (signal) 
    { 
    case CTRL_C_EVENT: return SignalHandler::SIG_INT; 
    case CTRL_BREAK_EVENT: return SignalHandler::SIG_TERM; 
    case CTRL_CLOSE_EVENT: return SignalHandler::SIG_CLOSE; 
    default: 
     return SignalHandler::SIG_UNHANDLED; 
    } 
} 
#else 
int POSIX_physicalToLogical(int signal) 
{ 
    switch (signal) 
    { 
    case SIGINT: return SignalHandler::SIG_INT; 
    case SIGTERM: return SignalHandler::SIG_TERM; 
    case SIGHUP: return SignalHandler::SIG_RELOAD; 
    default: 
     return SignalHandler::SIG_UNHANDLED; 
    } 
} 
#endif //_WIN32 



#ifdef _WIN32 
BOOL WINAPI WIN32_handleFunc(DWORD signal) 
{ 
    if (g_handler) 
    { 
     int signo = WIN32_physicalToLogical(signal); 
     // The std::set is thread-safe in const reading access and we never 
     // write to it after the program has started so we don't need to 
     // protect this search by a mutex 
     std::set<int>::const_iterator found = g_registry.find(signo); 
     if (signo != -1 && found != g_registry.end()) 
     { 
      return g_handler->handleSignal(signo) ? TRUE : FALSE; 
     } 
     else 
     { 
      return FALSE; 
     } 
    } 
    else 
    { 
     return FALSE; 
    } 
} 
#else 
void POSIX_handleFunc(int signal) 
{ 
    if (g_handler) 
    { 
     int signo = POSIX_physicalToLogical(signal); 
     g_handler->handleSignal(signo); 
    } 
} 
#endif //_WIN32 
-2

विंडोज पर यह कोड काम करते हैं और मुझे लगता है कि वह लिनक्स पर काम कर सकते हैं ।

ui->setupUi(this); 
QAction *ctrlp =new QAction("plus",this), *ctrlm = new QAction("minus",this); 
ctrlp->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus)); 
ctrlm->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus)); 
connect(ctrlp, SIGNAL(triggered()), this, SLOT(on_pushButton_4_clicked())); 
connect(ctrlm, SIGNAL(triggered()), this, SLOT(on_pushButton_5_clicked())); 

connect(ui->pushButton_2,SIGNAL(clicked()),SLOT(close())); 
ui->textEdit->addAction(ctrlp); 
ui->textEdit->addAction(ctrlm); 
+1

इस प्रश्न का उत्तर पोस्ट करने के लिए धन्यवाद! कोड-केवल उत्तर स्टैक ओवरफ़्लो पर निराश होते हैं, क्योंकि किसी संदर्भ के साथ कोड डंप यह नहीं बताता कि समाधान कैसे काम करेगा या क्यों, मूल पोस्टर (या भविष्य के पाठकों) के लिए तर्क को समझना मुश्किल हो जाता है। कृपया, अपना प्रश्न संपादित करें और अपने कोड का स्पष्टीकरण शामिल करें ताकि अन्य आपके उत्तर से लाभ उठा सकें। धन्यवाद! –

+0

यह उत्तर क्यूटी जीयूआई अनुप्रयोगों के लिए है, जबकि ओपी स्पष्ट रूप से क्यूटी कंसोल एप्लिकेशन के लिए पूछता है। ओपी टर्मिनेट सिग्नल को पकड़ना और इसे संभालना चाहता है, जीयूआई एप्लीकेशन के लिए शॉर्टकट हैंडलर सेट नहीं करना चाहता। लिनक्स पर यह कैसे काम करता है इसके लिए [यूनिक्स सिग्नल] (https://en.wikipedia.org/wiki/Unix_signal) देखें। –