#include "SDLWindow.h" #include #include // include console I/O methods (conio.h for windows, our wrapper in linux) #if defined(WIN32) #include #else #include "../common/conio.h" #endif #include "serial/serial.h" constexpr char kWindowClassName[] = "Playsound"; constexpr char kWindowName[] = "Playsound"; SDLWindow::SDLWindow() { // 创建窗口 WNDCLASS wc = { 0 }; wc.lpfnWndProc = StaticWindowProcedure; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = kWindowClassName; RegisterClass(&wc); hWnd = CreateWindow(wc.lpszClassName, kWindowName, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, (LPVOID)this); } SDLWindow::~SDLWindow() { // 移除托盘图标 Shell_NotifyIcon(NIM_DELETE, &trayIconData); } int32_t SDLWindow::Run() { // 创建托盘图标 CreateTrayIcon(); // 初始化SDL音频设备 if (SDL_Init(SDL_INIT_AUDIO) < 0) { std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl; return -1; } SDL_AtomicSet(&Quit, 0); SDL_zero(audioSpec); audioSpec.freq = 44100; audioSpec.format = AUDIO_S16SYS; audioSpec.channels = 2; audioSpec.samples = 4096; audioSpec.callback = AudioCallback; audioDeviceID = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); if (audioDeviceID == 0) { std::cerr << "Failed to open audio device: " << SDL_GetError() << std::endl; return -1; } // 创建串口监听线程 HANDLE hSerialListenerThread = CreateThread(NULL, 0, SerialListenerThread, this, 0, NULL); // 主消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 等待串口监听线程结束 WaitForSingleObject(hSerialListenerThread, INFINITE); CloseHandle(hSerialListenerThread); // 停止音频设备 SDL_PauseAudioDevice(audioDeviceID, 1); SDL_CloseAudioDevice(audioDeviceID); SDL_Quit(); return 0; } void SDLWindow::CreateTrayIcon() { ZeroMemory(&trayIconData, sizeof(NOTIFYICONDATA)); trayIconData.cbSize = sizeof(NOTIFYICONDATA); trayIconData.hWnd = hWnd; trayIconData.uID = TRAY_ICON_ID; trayIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; trayIconData.uCallbackMessage = WM_TRAYICON; trayIconData.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_APPLICATION)); strcpy_s(trayIconData.szTip, sizeof(trayIconData.szTip), kWindowName); Shell_NotifyIcon(NIM_ADD, &trayIconData); } void SDLWindow::QuitApplication() { // 在这里添加退出逻辑 SDL_AtomicSet(&Quit, 1); // 终止应用程序消息循环 PostQuitMessage(0); } LRESULT SDLWindow::WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_TRAYICON && wParam == TRAY_ICON_ID) { if (lParam == WM_RBUTTONDOWN) { // 创建右键退出菜单 HMENU hMenu = CreatePopupMenu(); AppendMenu(hMenu, MF_STRING, 1, "Exit"); // 获取鼠标位置 POINT pt; GetCursorPos(&pt); // 显示右键退出菜单 SetForegroundWindow(hWnd); TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL); // 销毁菜单 DestroyMenu(hMenu); } } else if (uMsg == WM_COMMAND && LOWORD(wParam) == 1) { // 退出菜单被点击 QuitApplication(); } return DefWindowProc(hWnd, uMsg, wParam, lParam); } LRESULT CALLBACK SDLWindow::StaticWindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { SDLWindow* pWindow = nullptr; if (uMsg == WM_NCCREATE) { CREATESTRUCT* pCreateStruct = (CREATESTRUCT*)lParam; pWindow = (SDLWindow*)pCreateStruct->lpCreateParams; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWindow); } else { pWindow = (SDLWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA); } if (pWindow) { return pWindow->WindowProcedure(hWnd, uMsg, wParam, lParam); } return DefWindowProc(hWnd, uMsg, wParam, lParam); } DWORD WINAPI SDLWindow::SerialListenerThread(LPVOID lpParam) { SDLWindow* pWindow = (SDLWindow*)lpParam; TCHAR path[MAX_PATH] = { 0 }; GetModuleFileName(NULL, path, sizeof(path)); std::string exeDir = path; std::size_t pos = exeDir.find_last_of("\\/"); if (pos != std::string::npos) { exeDir = exeDir.substr(0, pos); } const std::string configPath = exeDir + "\\playsound.ini"; const TCHAR* iniFile = configPath.c_str(); TCHAR section[] = TEXT("Settings"); TCHAR port[256]; DWORD code = GetPrivateProfileString(section, TEXT("port"), TEXT(""), port, sizeof(port), iniFile); DWORD errorCode = GetLastError(); int baudrate = GetPrivateProfileInt(section, TEXT("baudrate"), 9600, iniFile); uint32_t timeout = GetPrivateProfileInt(section, TEXT("timeout"), 1000, iniFile); irrklang::ISoundEngine* soundEngine = irrklang::createIrrKlangDevice(); if (nullptr == soundEngine) { return -1; } // 此处添加串口监听线程代码 serial::Serial serialPort(port, baudrate, serial::Timeout::simpleTimeout(timeout)); if (!serialPort.isOpen()) { return -1; } constexpr int32_t bufferSize = 1024; while (0 == SDL_AtomicGet(&pWindow->Quit)) { std::string result = serialPort.read(bufferSize); if (result.empty()) { continue; } // 此处添加串口数据处理代码 //soundEngine->play2D() const std::string mediaPath = exeDir + "\\media\\getout.ogg"; soundEngine->play2D(mediaPath.c_str()); } soundEngine->drop(); return 0; } void SDLWindow::AudioCallback(void* userdata, Uint8* stream, int len) { // 此处添加音频处理代码 }