Tôi có ứng dụng máy chủ bàn điều khiển Qt. Tôi muốn khi ai đó nhấn Ctrl + C để thoát khỏi máy chủ của tôi một cách chính xác (gọi destructors, vv). Tôi đã đọc this, tuy nhiên tôi muốn điều này hoạt động trên cả Linux và Windows. Làm thế nào để làm nó?Cách nắm bắt Ctrl + C trên Windows và Linux với Qt
Trả lời
Tôi sử dụng lớp này để bắt tín hiệu trong các ứng dụng giao diện điều khiển C++. Nó không phải là cụ thể để Qt, tuy nhiên. Nó sử dụng SetConsoleCtrlHandler() trên nền tảng Windows và các chức năng được cung cấp bởi <signal.h> trên các nền tảng khác. Bit khó hiểu là "tín hiệu" không phải là một thuật ngữ nền tảng chéo - Windows và POSIX có các định nghĩa khác nhau cho chúng. Dù sao lớp này cố gắng để ánh xạ chúng vào một từ vựng chung. Ctrl^C là bản đồ tốt trên cả hai nền tảng.
Tôi hy vọng điều này có thể được điều chỉnh theo tình huống cụ thể của bạn. Hãy nhớ rằng kiểm tra lỗi là tối thiểu và có lẽ nên được cải thiện.
sử dụng (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
Đó công việc mã trên Windows và tôi nghĩ anh ấy có thể làm việc trên Linux .
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. Tôi có thể nắm bắt tín hiệu bàn phím nào ngoài Ctrl-C?
- 2. Tương đương với tín hiệu "SIGINT" (posix) để bắt "CTRL + C" trong Windows/MinGW
- 3. Cách nắm bắt IndentationError
- 4. C# Nắm bắt ngoại lệ xảy ra trên ThreadPool
- 5. Làm thế nào để nắm bắt đầu vào HID thô trên Linux?
- 6. Bắt Ctrl + C trong Java
- 7. Gửi CTRL + C tới cây con xử lý trên Windows
- 8. Biên dịch chéo trên Windows và Linux
- 9. Xử lý sự kiện CTRL + C trong Node.js trên Windows
- 10. Bắt Nan và Inf trong Windows C++
- 11. biên dịch trên windows và linux
- 12. (C/C++) Cách tạo tệp thi hành có thể chạy trên cả Windows và Linux?
- 13. Tạo tệp thực thi cho Windows bằng cách sử dụng Qt trên Linux
- 14. Làm thế nào để nắm bắt tín hiệu Control + D?
- 15. Làm cách nào để dừng lệnh R đang chạy trong linux khác với ctrl + c?
- 16. thay thế malloc_size trên Linux và Windows
- 17. Cách nắm bắt "Lỗi OpenCV" trong Python
- 18. C#: gửi ctrl + c đến bàn điều khiển chương trình bắt đầu với Process.Start()?
- 19. Biên dịch C# + WPF trên Linux để chạy trên Windows
- 20. Cách nắm bắt các phím mũi tên trong node.js
- 21. Bắt đầu với OpenCL trên Windows 7
- 22. QtCreator trên Windows để Cross Compile cho Linux ARM với CodeSourcery Toolchain
- 23. C++ Cross Platform Dynamic Libraries; Linux và Windows
- 24. Ctrl + C ngắt sự kiện xử lý trong Linux
- 25. Tôi có thể gửi ctrl-C (SIGINT) đến một ứng dụng trên Windows không?
- 26. Bắt Hệ thống Thời gian rảnh với Qt
- 27. Tôi có thể nắm bắt các gói mạng trên mỗi PID bằng cách nào?
- 28. chức năng cú pháp cố gắng nắm bắt và chính
- 29. CLI PHP trong Windows: Xử lý các lệnh Ctrl-C?
- 30. Cách ánh xạ Ctrl + A và Ctrl + Shift + A khác?
Cảm ơn bạn đã đăng câu trả lời cho câu hỏi này! Các câu trả lời chỉ mã không được khuyến khích trên Stack Overflow, vì một đoạn mã không có ngữ cảnh không giải thích cách thức hoặc lý do giải pháp sẽ hoạt động, gây khó khăn cho poster gốc (hoặc bất kỳ người đọc nào trong tương lai) hiểu logic đằng sau nó. Vui lòng chỉnh sửa câu hỏi của bạn và đưa ra giải thích về mã của bạn để người khác có thể hưởng lợi từ câu trả lời của bạn. Cảm ơn! –
Câu trả lời này dành cho các ứng dụng GUI Qt, trong khi OP yêu cầu một ứng dụng giao diện điều khiển Qt rõ ràng. OP muốn nắm bắt tín hiệu chấm dứt và xử lý nó, không thiết lập trình xử lý phím tắt cho ứng dụng GUI. Xem [Unix signal] (https://en.wikipedia.org/wiki/Unix_signal) để biết cách nó hoạt động trên Linux. –